src/thread/linux/SDL_systhread.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. SDL_SYS_CreateThread
  2. SDL_SYS_SetupThread
  3. SDL_ThreadID
  4. SDL_SYS_WaitThread
  5. SDL_SYS_KillThread
  6. RunThread
  7. SDL_SYS_CreateThread
  8. SDL_SYS_SetupThread
  9. SDL_ThreadID
  10. SDL_SYS_WaitThread
  11. SDL_SYS_KillThread
  12. RunThread
  13. SDL_SYS_CreateThread
  14. SDL_SYS_SetupThread
  15. SDL_ThreadID
  16. SDL_SYS_WaitThread
  17. SDL_SYS_KillThread

   1 /*
   2     SDL - Simple DirectMedia Layer
   3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
   4 
   5     This library is free software; you can redistribute it and/or
   6     modify it under the terms of the GNU Library General Public
   7     License as published by the Free Software Foundation; either
   8     version 2 of the License, or (at your option) any later version.
   9 
  10     This library is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13     Library General Public License for more details.
  14 
  15     You should have received a copy of the GNU Library General Public
  16     License along with this library; if not, write to the Free
  17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 
  19     Sam Lantinga
  20     slouken@devolution.com
  21 */
  22 
  23 #ifdef SAVE_RCSID
  24 static char rcsid =
  25  "@(#) $Id: SDL_systhread.c,v 1.3.2.7 2001/02/10 07:20:04 hercules Exp $";
  26 #endif
  27 
  28 /* Linux thread management routines for SDL */
  29 
  30 #include "SDL_error.h"
  31 #include "SDL_thread.h"
  32 #include "SDL_systhread.h"
  33 
  34 #ifdef FORK_HACK
  35 
  36 #include <unistd.h>
  37 
  38 int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
     /* [<][>][^][v][top][bottom][index][help] */
  39 {
  40         SDL_SetError("Threads are not supported on this platform");
  41         return(-1);
  42 }
  43 void SDL_SYS_SetupThread(void)
     /* [<][>][^][v][top][bottom][index][help] */
  44 {
  45         return;
  46 }
  47 Uint32 SDL_ThreadID(void)
     /* [<][>][^][v][top][bottom][index][help] */
  48 {
  49         return((Uint32)getpid());
  50 }
  51 void SDL_SYS_WaitThread(SDL_Thread *thread)
     /* [<][>][^][v][top][bottom][index][help] */
  52 {
  53         return;
  54 }
  55 void SDL_SYS_KillThread(SDL_Thread *thread)
     /* [<][>][^][v][top][bottom][index][help] */
  56 {
  57         return;
  58 }
  59 
  60 #else
  61 
  62 #include <signal.h>
  63 
  64 #if !defined(MACOSX) /* pthread_sigmask seems to be missing on MacOS X? */
  65 /* List of signals to mask in the subthreads */
  66 static int sig_list[] = {
  67         SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,
  68         SIGVTALRM, SIGPROF, 0
  69 };
  70 #endif /* !MACOSX */
  71 
  72 #ifdef SDL_USE_PTHREADS
  73 
  74 #include <pthread.h>
  75 
  76 
  77 static void *RunThread(void *data)
     /* [<][>][^][v][top][bottom][index][help] */
  78 {
  79         SDL_RunThread(data);
  80         pthread_exit((void*)0);
  81         return((void *)0);              /* Prevent compiler warning */
  82 }
  83 
  84 int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
     /* [<][>][^][v][top][bottom][index][help] */
  85 {
  86         pthread_attr_t type;
  87 
  88         /* Set the thread attributes */
  89         if ( pthread_attr_init(&type) != 0 ) {
  90                 SDL_SetError("Couldn't initialize pthread attributes");
  91                 return(-1);
  92         }
  93         pthread_attr_setdetachstate(&type, PTHREAD_CREATE_JOINABLE);
  94 
  95         /* Create the thread and go! */
  96         if ( pthread_create(&thread->handle, &type, RunThread, args) != 0 ) {
  97                 SDL_SetError("Not enough resources to create thread");
  98                 return(-1);
  99         }
 100         return(0);
 101 }
 102 
 103 void SDL_SYS_SetupThread(void)
     /* [<][>][^][v][top][bottom][index][help] */
 104 {
 105 #if !defined(MACOSX) /* pthread_sigmask seems to be missing on MacOS X? */
 106         int i;
 107         sigset_t mask;
 108 
 109         /* Mask asynchronous signals for this thread */
 110         sigemptyset(&mask);
 111         for ( i=0; sig_list[i]; ++i ) {
 112                 sigaddset(&mask, sig_list[i]);
 113         }
 114         pthread_sigmask(SIG_BLOCK, &mask, 0);
 115 #endif /* !MACOSX */
 116 
 117 #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
 118         /* Allow ourselves to be asynchronously cancelled */
 119         { int oldstate;
 120                 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
 121         }
 122 #endif
 123 }
 124 
 125 /* WARNING:  This may not work for systems with 64-bit pid_t */
 126 Uint32 SDL_ThreadID(void)
     /* [<][>][^][v][top][bottom][index][help] */
 127 {
 128         return((Uint32)pthread_self());
 129 }
 130 
 131 void SDL_SYS_WaitThread(SDL_Thread *thread)
     /* [<][>][^][v][top][bottom][index][help] */
 132 {
 133         pthread_join(thread->handle, 0);
 134 }
 135 
 136 void SDL_SYS_KillThread(SDL_Thread *thread)
     /* [<][>][^][v][top][bottom][index][help] */
 137 {
 138 #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
 139         pthread_cancel(thread->handle);
 140 #else
 141 #ifdef __FreeBSD__
 142 #warning For some reason, this doesnt actually kill a thread - FreeBSD 3.2
 143 #endif
 144         pthread_kill(thread->handle, SIGKILL);
 145 #endif
 146 }
 147 
 148 #else /* Linux-specific clone() based implementation */
 149 
 150 #include <stdlib.h>
 151 #include <errno.h>
 152 #include <unistd.h>
 153 #include <sys/wait.h>
 154 
 155 
 156 /* Stack size for child thread */
 157 #define STACKSIZE 16384*4               /* 16384 is too small */
 158 
 159 #ifdef __GLIBC__
 160 #include <sched.h>
 161 #else
 162 /* From <linux/sched.h> */
 163 #define CLONE_VM      0x00000100   /* set if VM shared */
 164 #define CLONE_FS      0x00000200   /* set if fs info shared */
 165 #define CLONE_FILES   0x00000400   /* set if open files shared */
 166 #define CLONE_SIGHAND 0x00000800   /* set if signal handlers shared */
 167 #define CLONE_PID     0x00001000   /* set if pid shared */
 168 
 169 /* The infamous "start_thread" function, courtesy Linus Torvalds */
 170 extern int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg);
 171 #endif
 172 
 173 static int RunThread(void *data)
     /* [<][>][^][v][top][bottom][index][help] */
 174 {
 175         SDL_RunThread(data);
 176         return(0);
 177 }
 178 
 179 int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
     /* [<][>][^][v][top][bottom][index][help] */
 180 {
 181         void *stack;
 182 
 183         /* Allocate memory for thread stack */
 184         stack = malloc(STACKSIZE);
 185         if ( stack == (void *)0 ) {
 186                 SDL_OutOfMemory();
 187                 return(-1);
 188         }
 189         thread->data = stack;
 190 
 191         /* Adjust the stack since it actually grows down */
 192         stack = (void *) ((char *)stack + STACKSIZE);
 193 
 194         /* Create the thread and go! */
 195         thread->handle = clone(RunThread, stack,
 196                         (CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND), args);
 197         if ( thread->handle < 0 ) {
 198                 free(thread->data);
 199                 SDL_SetError("Not enough resources to create thread");
 200                 return(-1);
 201         }
 202         return(0);
 203 }
 204 
 205 void SDL_SYS_SetupThread(void)
     /* [<][>][^][v][top][bottom][index][help] */
 206 {
 207         int i;
 208         sigset_t mask;
 209 
 210         /* Mask asynchronous signals for this thread */
 211         sigemptyset(&mask);
 212         for ( i=0; sig_list[i]; ++i ) {
 213                 sigaddset(&mask, sig_list[i]);
 214         }
 215         sigprocmask(SIG_BLOCK, &mask, 0);
 216 }
 217 
 218 /* WARNING:  This may not work for systems with 64-bit pid_t */
 219 Uint32 SDL_ThreadID(void)
     /* [<][>][^][v][top][bottom][index][help] */
 220 {
 221         return((Uint32)getpid());
 222 }
 223 
 224 void SDL_SYS_WaitThread(SDL_Thread *thread)
     /* [<][>][^][v][top][bottom][index][help] */
 225 {
 226 #ifdef __WCLONE
 227         errno = 0;
 228         while ( errno != ECHILD ) {
 229                 waitpid(thread->handle, 0, __WCLONE);
 230         }
 231 #else
 232         /* Ack, ugly ugly hack --
 233            wait() doesn't work, waitpid() doesn't work, and ignoring SIG_CHLD
 234            doesn't work .. and the child thread is still a zombie, so kill()
 235            doesn't work.
 236         */
 237         char command[1024];
 238 
 239         sprintf(command,
 240                 "ps ax|fgrep -v fgrep|fgrep -v '<zombie>'|fgrep %d >/dev/null",
 241                                                                 thread->handle);
 242         while ( system(command) == 0 )
 243                 sleep(1);
 244 #endif
 245         free(thread->data);
 246 }
 247 
 248 void SDL_SYS_KillThread(SDL_Thread *thread)
     /* [<][>][^][v][top][bottom][index][help] */
 249 {
 250         kill(thread->handle, SIGKILL);
 251 }
 252 
 253 #endif /* SDL_USE_PTHREADS */
 254 
 255 #endif /* FORK_HACK */

/* [<][>][^][v][top][bottom][index][help] */