Created
May 5, 2010 07:42
-
-
Save ELLIOTTCABLE/390498 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
thread Thread__create(pool a_pool) { | |
thread this = malloc(sizeof(struct thread)); | |
this->pthread = malloc(sizeof(pthread_t)); | |
this->pool = a_pool; | |
pthread_create(&this->pthread, | |
NULL, (void *(*)(void *))register_a_thread, (void *)this); | |
return this; | |
} | |
void register_a_thread(void *argument) { | |
thread this = (thread)argument; | |
this->initialized = true; | |
Thread.work(this); | |
Thread.destroy(this); | |
//return; /* This can never return; `Thread.destroy()` calls `pthread_exit()`. */ | |
} | |
void thread__work(thread this) { | |
/* This is the primary work loop. As long as the thread is `initialized` | |
* (meaning it hasn’t been informed that it should terminate), it will | |
* wait for signals (via it’s pool’s condvar) that there is work available | |
* to be done, specifically, that there are routines in the queue to be | |
* interpreted. | |
* -- | |
* FIXME: Should we move the *loop* out of here, and just have the condition | |
* check? Perhaps move even that out, and only execute routines. */ | |
while (this->initialized) { | |
pthread_mutex_lock ( this->pool->mutex); | |
pthread_cond_wait (this->pool->condition, this->pool->mutex); | |
pthread_mutex_unlock( this->pool->mutex); | |
/* Once the thread is woken up by a condvar signal, we check that there’s | |
* actually routines to process (if not, it falls through to waiting | |
* again) */ | |
while (this->initialized && this->pool->size > 0) | |
Paws.Routine.execute( Pool.drip(this->pool) ); | |
} | |
/* Usually, this is called from `register_a_thread()`, so it’s quite likely | |
* that the thread will destroy itself after this returns. */ | |
return; | |
} | |
void thread__destroy(thread this) { | |
this->initialized = false; | |
/* If `this` is the current thread, we directly kill ourselves after having | |
* cleaned up. Else, we `join` against the passed `thread`, blocking until | |
* it finishes its work and terminates. */ | |
if (pthread_equal( pthread_self(), this->pthread )) { | |
/* FIXME: How do I deallocate the `pthread_t` structure? There’s no | |
* documented `pthread_destroy()` function. */ | |
/* FIXME: How do I ensure nobody else tries to access this after it is | |
* freed? Other people may still have references to it. */ | |
free(this); | |
pthread_exit(NULL); | |
} else { | |
/* TODO: Find a way to signal a specific thread to wake, instead of | |
* broadcasting a pointless wake to *all* threads in the pool. Seems | |
* wasteful, if not dangerous. */ | |
pthread_cond_broadcast(this->pool->condition); | |
/* TODO: Replace this with an ‘is active’ mutex; prevent any destructive | |
* modifications to the `thread` structure while it’s running. | |
* Locking against that mutex would be equivalent to `join`ing, | |
* because the thread would only release the mutex while it’s | |
* shutting down. */ | |
pthread_join(this->pthread, NULL); | |
free(this); | |
} | |
return; /* This will never return, if called from the thread itself */ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pool Pool__create(void) { | |
pool this = malloc(sizeof( struct pool )); | |
this->mutex = malloc(sizeof( pthread_mutex_t )); | |
this->condition = malloc(sizeof( pthread_cond_t )); | |
this->size = 0; | |
this->queue = NULL; | |
/* We initialize the mutex, and just to be safe, lock against it. */ | |
pthread_mutex_init (this->mutex, NULL); | |
pthread_mutex_lock (this->mutex); | |
pthread_cond_init (this->condition, NULL); | |
pthread_mutex_unlock(this->mutex); | |
return this; | |
} | |
void pool__enqueue(pool this, routine a_routine) { | |
routine *queue = malloc(sizeof(routine) * this->size + 1); | |
memcpy(queue, this->queue, sizeof(routine) * this->size); | |
queue[this->size] = a_routine; | |
this->queue = queue; | |
this->size++; | |
pthread_cond_signal (this->condition); | |
} | |
routine pool__drip(pool this) { | |
routine first = this->queue[0]; | |
routine *queue = malloc(sizeof(routine) * this->size - 1); | |
memcpy(queue, this->queue + 1, sizeof(routine) * this->size - 1); | |
this->queue = queue; | |
this->size--; | |
return first; | |
} | |
void pool__destroy(pool this) { | |
/* TODO: Clean up. */ | |
free(this); | |
return; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ees very pretty.