iothread.c

Go to the documentation of this file.
00001 
00025 #include <SDL.h>
00026 #include <SDL_thread.h>
00027 #include <assert.h>
00028 #include "iothread.h"
00029 #include "random.h"
00030 
00036 static SDL_cond *notify;
00037 
00043 static SDL_Thread *thread = NULL;
00044 
00050 struct Operation_t {
00054     ioOperation op;
00058     void *data;
00059 };
00060 
00066 static struct Operation_t queue[IO_QUEUE_SIZE];
00067 
00073 static int queueLen = 0;
00074 
00080 static int queueNext = 0;
00081 
00087 static SDL_mutex *queueMutex = NULL;
00088 
00096 static int opFlags = 0;
00097 
00104 #define FLAG_CANCEL  1
00105 
00112 #define FLAG_TERM    2
00113 
00120 static int ioThread(void *ignore) {
00121     SDL_mutex *waitMutex;
00122     struct Operation_t oper;
00123     int next = 1;
00124     int lastLen;
00125     // initalize the random number generator
00126     RandInit();
00127     // create new mutex semaphores
00128     if ((queueMutex = SDL_CreateMutex()) == NULL) {
00129         // create failed!
00130         return -1;
00131     }
00132     if ((waitMutex = SDL_CreateMutex()) == NULL) {
00133         // create failed!
00134         SDL_DestroyMutex(queueMutex);
00135         queueMutex = NULL;
00136         return -1;
00137     }
00138     // lock it
00139     if (SDL_mutexP(waitMutex) == -1) {
00140         // lock failed!
00141         ioThread_die:
00142         SDL_DestroyMutex(waitMutex);
00143         SDL_DestroyMutex(queueMutex);
00144         queueMutex = NULL;
00145         return -1;
00146     }
00147     // wait for stuff to do
00148     while (SDL_CondWait(notify, waitMutex) == 0) {
00149         ioThread_noWait:
00150         // lock the queue
00151         if (SDL_mutexP(queueMutex) == -1) {
00152             // failed to use a mutex, so this isn't going to work
00153             goto ioThread_die;
00154         }
00155         // check for nothing in the queue
00156         if (queueLen-- == 0) {
00157             // time to quit
00158             break;
00159         }
00160         // store the number of items queued for a later check
00161         lastLen = queueLen;
00162         // clear the cancel request flag
00163         opFlags = 0;
00164         // copy the queue entry
00165         oper = queue[next];
00166         // advance the next counter
00167         next = (next + 1) % IO_QUEUE_SIZE;
00168         // release the queue
00169         SDL_mutexV(queueMutex);
00170         // run the operation
00171         (*oper.op)(oper.data);
00172         // need to terminate?
00173         if (opFlags & FLAG_TERM) {
00174             // leave the loop to perform cleanup
00175             break;
00176         }
00177         // check for more stuff queued
00178         if (queueLen) {
00179             // do not wait on the condition; continue with the next operation
00180             // now
00181             goto ioThread_noWait;
00182         }
00183     }
00184     SDL_DestroyMutex(waitMutex);
00185     SDL_DestroyMutex(queueMutex);
00186     queueMutex = NULL;
00187     return 0;
00188 }
00189 
00190 void StartIOThread() {
00191     // create the condition gizmo used to signal the I/O thread
00192     notify = SDL_CreateCond();
00193     // start the I/O thread
00194     thread = SDL_CreateThread(ioThread, NULL);
00195     // avoid possible race conditions by allowing the thread some time to
00196     // initalize itself
00197     SDL_Delay(2);
00198 }
00199 
00200 void StopIOThread() {
00201     // see if the thread was started and a queue mutex exists
00202     if (thread && queueMutex) {
00203         // The thread was started and should be running. Try to lock the queue.
00204         if (SDL_mutexP(queueMutex) == -1) {
00205             // kill the thread forcefully.
00206             EndIOThread_kill:
00207             SDL_KillThread(thread);
00208             //printf("Forced end of IO thread\n");
00209         }
00210         else {
00211             // remove the last item from the queue
00212             queueLen = 0;
00213             // request than any operation in progess please quit
00214             opFlags = FLAG_CANCEL | FLAG_TERM;
00215             // release the queue lock
00216             SDL_mutexV(queueMutex);
00217             // signal the thread
00218             if (SDL_CondSignal(notify) == -1) {
00219                 // couldn't do it; assure a dead thread
00220                 goto EndIOThread_kill;
00221             }
00222             // wait for the thread to finish
00223             SDL_WaitThread(thread, NULL);
00224             //printf("Normal end of IO thread\n");
00225         }
00226         thread = NULL;
00227     }
00228     SDL_DestroyCond(notify);
00229 }
00230 
00231 int QueueOperation(ioOperation op, void *data) {
00232     int ret;
00233     // the queue should already exist
00234     assert(queueMutex != NULL);
00235     // check for full queue
00236     if (queueLen == IO_QUEUE_SIZE)
00237         return -1;
00238     // attempt to lock the queue
00239     if (SDL_mutexP(queueMutex) == -1) {
00240         // failed
00241         return -2;
00242     }
00243     // compute new length
00244     ret = ++queueLen;
00245     // compute the index of the new item
00246     queueNext = (queueNext + 1) % IO_QUEUE_SIZE;
00247     // add the item
00248     queue[queueNext].op = op;
00249     queue[queueNext].data = data;
00250     // signal the thread
00251     SDL_CondSignal(notify);
00252     // release the lock
00253     SDL_mutexV(queueMutex);
00254     // send back the remaining queue length
00255     return ret;
00256 }
00257 
00258 Bool IsCancelationRequested() {
00259     return opFlags & FLAG_CANCEL;
00260 }
00261 
00262 Bool CancelOperations() {
00263     // see if the thread was started and a queue mutex exists
00264     if (thread && queueMutex) {
00265         // The thread was started and should be running. Try to lock the queue.
00266         if (SDL_mutexP(queueMutex) != -1) {
00267             // remove the last item from the queue
00268             queueLen = 0;
00269             // request than any operation in progess please quit
00270             opFlags = FLAG_CANCEL;
00271             // release the queue lock
00272             SDL_mutexV(queueMutex);
00273             // sucess
00274             return TRUE;
00275         }
00276     }
00277     // failed
00278     return FALSE;
00279 }
00280 

Generated on Mon May 28 04:41:39 2007 for Retro Tank Super Attack by  doxygen 1.5.2