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