SDL_thread.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:7k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
  4.     This library is free software; you can redistribute it and/or
  5.     modify it under the terms of the GNU Library General Public
  6.     License as published by the Free Software Foundation; either
  7.     version 2 of the License, or (at your option) any later version.
  8.     This library is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.     Library General Public License for more details.
  12.     You should have received a copy of the GNU Library General Public
  13.     License along with this library; if not, write to the Free
  14.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  15.     Sam Lantinga
  16.     slouken@libsdl.org
  17. */
  18. #ifdef SAVE_RCSID
  19. static char rcsid =
  20.  "@(#) $Id: SDL_thread.c,v 1.4 2002/04/22 21:38:02 wmay Exp $";
  21. #endif
  22. /* System independent thread management routines for SDL */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include "SDL_error.h"
  27. #include "SDL_mutex.h"
  28. #include "SDL_thread.h"
  29. #include "SDL_thread_c.h"
  30. #include "SDL_systhread.h"
  31. #define ARRAY_CHUNKSIZE 32
  32. /* The array of threads currently active in the application
  33.    (except the main thread)
  34.    The manipulation of an array here is safer than using a linked list.
  35. */
  36. static int SDL_maxthreads = 0;
  37. static int SDL_numthreads = 0;
  38. static SDL_Thread **SDL_Threads = NULL;
  39. static SDL_mutex *thread_lock = NULL;
  40. int _creating_thread_lock = 0;
  41. int SDL_ThreadsInit(void)
  42. {
  43. int retval;
  44. #ifdef ENABLE_PTH
  45. if (!pth_init()) {
  46. return -1;
  47. }
  48. #endif
  49. retval = 0;
  50. /* Set the thread lock creation flag so that we can reuse an
  51.    existing lock on the system - since this mutex never gets
  52.    destroyed (see SDL_ThreadsQuit()), we want to reuse it.
  53. */
  54. _creating_thread_lock = 1;
  55. thread_lock = SDL_CreateMutex();
  56. _creating_thread_lock = 0;
  57. if ( thread_lock == NULL ) {
  58. retval = -1;
  59. }
  60. return(retval);
  61. }
  62. /* This should never be called...
  63.    If this is called by SDL_Quit(), we don't know whether or not we should
  64.    clean up threads here.  If any threads are still running after this call,
  65.    they will no longer have access to any per-thread data.
  66.  */
  67. void SDL_ThreadsQuit()
  68. {
  69. SDL_mutex *mutex;
  70. mutex = thread_lock;
  71. thread_lock = NULL;
  72. if ( mutex != NULL ) {
  73. SDL_DestroyMutex(mutex);
  74. }
  75. #ifdef ENABLE_PTH
  76. pth_kill();
  77. #endif
  78. }
  79. /* Routines for manipulating the thread list */
  80. static void SDL_AddThread(SDL_Thread *thread)
  81. {
  82. SDL_Thread **threads;
  83. /* WARNING:
  84.    If the very first threads are created simultaneously, then
  85.    there could be a race condition causing memory corruption.
  86.    In practice, this isn't a problem because by definition there
  87.    is only one thread running the first time this is called.
  88. */
  89. if ( thread_lock == NULL ) {
  90. if ( SDL_ThreadsInit() < 0 ) {
  91. return;
  92. }
  93. }
  94. SDL_mutexP(thread_lock);
  95. /* Expand the list of threads, if necessary */
  96. #ifdef DEBUG_THREADS
  97. printf("Adding thread (%d already - %d max)n",
  98. SDL_numthreads, SDL_maxthreads);
  99. #endif
  100. if ( SDL_numthreads == SDL_maxthreads ) {
  101. threads=(SDL_Thread **)malloc((SDL_maxthreads+ARRAY_CHUNKSIZE)*
  102.                               (sizeof *threads));
  103. if ( threads == NULL ) {
  104. SDL_OutOfMemory();
  105. goto done;
  106. }
  107. memcpy(threads, SDL_Threads, SDL_numthreads*(sizeof *threads));
  108. SDL_maxthreads += ARRAY_CHUNKSIZE;
  109. if ( SDL_Threads ) {
  110. free(SDL_Threads);
  111. }
  112. SDL_Threads = threads;
  113. }
  114. SDL_Threads[SDL_numthreads++] = thread;
  115. done:
  116. SDL_mutexV(thread_lock);
  117. }
  118. static void SDL_DelThread(SDL_Thread *thread)
  119. {
  120. int i;
  121. if ( thread_lock ) {
  122. SDL_mutexP(thread_lock);
  123. for ( i=0; i<SDL_numthreads; ++i ) {
  124. if ( thread == SDL_Threads[i] ) {
  125. break;
  126. }
  127. }
  128. if ( i < SDL_numthreads ) {
  129. if ( --SDL_numthreads > 0 ) {
  130. while ( i < SDL_numthreads ) {
  131. SDL_Threads[i] = SDL_Threads[i+1];
  132. ++i;
  133. }
  134. } else {
  135. SDL_maxthreads = 0;
  136. free(SDL_Threads);
  137. SDL_Threads = NULL;
  138. }
  139. #ifdef DEBUG_THREADS
  140. printf("Deleting thread (%d left - %d max)n",
  141. SDL_numthreads, SDL_maxthreads);
  142. #endif
  143. }
  144. SDL_mutexV(thread_lock);
  145. }
  146. }
  147. /* The default (non-thread-safe) global error variable */
  148. static SDL_error SDL_global_error;
  149. /* Routine to get the thread-specific error variable */
  150. SDL_error *SDL_GetErrBuf(void)
  151. {
  152. SDL_error *errbuf;
  153. errbuf = &SDL_global_error;
  154. if ( SDL_Threads ) {
  155. int i;
  156. Uint32 this_thread;
  157. this_thread = SDL_ThreadID();
  158. SDL_mutexP(thread_lock);
  159. for ( i=0; i<SDL_numthreads; ++i ) {
  160. if ( this_thread == SDL_Threads[i]->threadid ) {
  161. errbuf = &SDL_Threads[i]->errbuf;
  162. break;
  163. }
  164. }
  165. SDL_mutexV(thread_lock);
  166. }
  167. return(errbuf);
  168. }
  169. /* Arguments and callback to setup and run the user thread function */
  170. typedef struct {
  171. int (*func)(void *);
  172. void *data;
  173. SDL_Thread *info;
  174. SDL_sem *wait;
  175. } thread_args;
  176. void SDL_RunThread(void *data)
  177. {
  178. thread_args *args;
  179. int (*userfunc)(void *);
  180. void *userdata;
  181. int *statusloc;
  182. /* Perform any system-dependent setup
  183.    - this function cannot fail, and cannot use SDL_SetError()
  184.  */
  185. SDL_SYS_SetupThread();
  186. /* Get the thread id */
  187. args = (thread_args *)data;
  188. args->info->threadid = SDL_ThreadID();
  189. /* Figure out what function to run */
  190. userfunc = args->func;
  191. userdata = args->data;
  192. statusloc = &args->info->status;
  193. /* Wake up the parent thread */
  194. SDL_SemPost(args->wait);
  195. /* Run the function */
  196. *statusloc = userfunc(userdata);
  197. }
  198. SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data)
  199. {
  200. SDL_Thread *thread;
  201. thread_args *args;
  202. int ret;
  203. /* Allocate memory for the thread info structure */
  204. thread = (SDL_Thread *)malloc(sizeof(*thread));
  205. if ( thread == NULL ) {
  206. SDL_OutOfMemory();
  207. return(NULL);
  208. }
  209. memset(thread, 0, (sizeof *thread));
  210. thread->status = -1;
  211. /* Set up the arguments for the thread */
  212. args = (thread_args *)malloc(sizeof(*args));
  213. if ( args == NULL ) {
  214. SDL_OutOfMemory();
  215. free(thread);
  216. return(NULL);
  217. }
  218. args->func = fn;
  219. args->data = data;
  220. args->info = thread;
  221. args->wait = SDL_CreateSemaphore(0);
  222. if ( args->wait == NULL ) {
  223. free(thread);
  224. free(args);
  225. return(NULL);
  226. }
  227. /* Add the thread to the list of available threads */
  228. SDL_AddThread(thread);
  229. /* Create the thread and go! */
  230. ret = SDL_SYS_CreateThread(thread, args);
  231. if ( ret >= 0 ) {
  232. /* Wait for the thread function to use arguments */
  233. SDL_SemWait(args->wait);
  234. } else {
  235. /* Oops, failed.  Gotta free everything */
  236. SDL_DelThread(thread);
  237. free(thread);
  238. thread = NULL;
  239. }
  240. SDL_DestroySemaphore(args->wait);
  241. free(args);
  242. /* Everything is running now */
  243. return(thread);
  244. }
  245. void SDL_WaitThread(SDL_Thread *thread, int *status)
  246. {
  247. if ( thread ) {
  248. SDL_SYS_WaitThread(thread);
  249. if ( status ) {
  250. *status = thread->status;
  251. }
  252. SDL_DelThread(thread);
  253. free(thread);
  254. }
  255. }
  256. Uint32 SDL_GetThreadID(SDL_Thread *thread)
  257. {
  258. Uint32 id;
  259. if ( thread ) {
  260. id = thread->threadid;
  261. } else {
  262. id = SDL_ThreadID();
  263. }
  264. return(id);
  265. }
  266. void SDL_KillThread(SDL_Thread *thread)
  267. {
  268. if ( thread ) {
  269. SDL_SYS_KillThread(thread);
  270. SDL_WaitThread(thread, NULL);
  271. }
  272. }