#include "threads.h" #include #include #include struct Promise { int done; int refs; struct Environment* env; Object object; pthread_t thread; }; Object clonePromise(Object src) { src.promise->refs += 1; return src; } int isDone(struct Promise* promise) { return promise->done; } int isPromise(Object src) { return src.type == TYPE_PROMISE; } void cleanPromise(struct Promise* promise) { promise->refs -= 1; if (promise->refs == 0) { deleteEnv(promise->env); cleanObject(&promise->object); free(promise); } } Object await(Object* params, int length, struct Environment* env) { checkTypes(await); struct Promise* promise = params[0].promise; if (!promise->done) { // TODO: Does `done` need a mutex or other lock? pthread_join(promise->thread, NULL); } return cloneObject(promise->object); } void* doAsync(void* args) { struct Promise* promise = args; Object cloned = promise->object; Object first_eval = eval(&cloned, promise->env); Object e = funcyEval(&first_eval, NULL, 0, promise->env); promise->object = e; promise->done = 1; cleanObject(&cloned); cleanPromise(promise); deleteEnv(promise->env); return NULL; } Object async(Object* params, int length, struct Environment* env) { Object promise = newObject(TYPE_PROMISE); promise.promise = malloc(sizeof(struct Promise)); *promise.promise = (struct Promise) { .refs = 2, // Held by doAsync and the returned object .done = 0, .env = env, .object = cloneObject(params[0]), }; env->refs += 1; pthread_create(&promise.promise->thread, NULL, doAsync, promise.promise); return promise; }