Home | History | Annotate | Download | only in pthreads-win32
      1 /*
      2  * create.c
      3  *
      4  * Description:
      5  * This translation unit implements routines associated with spawning a new
      6  * thread.
      7  *
      8  * --------------------------------------------------------------------------
      9  *
     10  *      Pthreads-win32 - POSIX Threads Library for Win32
     11  *      Copyright(C) 1998 John E. Bossom
     12  *      Copyright(C) 1999,2005 Pthreads-win32 contributors
     13  *
     14  *      Contact Email: rpj (at) callisto.canberra.edu.au
     15  *
     16  *      The current list of contributors is contained
     17  *      in the file CONTRIBUTORS included with the source
     18  *      code distribution. The list can also be seen at the
     19  *      following World Wide Web location:
     20  *      http://sources.redhat.com/pthreads-win32/contributors.html
     21  *
     22  *      This library is free software; you can redistribute it and/or
     23  *      modify it under the terms of the GNU Lesser General Public
     24  *      License as published by the Free Software Foundation; either
     25  *      version 2 of the License, or (at your option) any later version.
     26  *
     27  *      This library is distributed in the hope that it will be useful,
     28  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
     29  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     30  *      Lesser General Public License for more details.
     31  *
     32  *      You should have received a copy of the GNU Lesser General Public
     33  *      License along with this library in the file COPYING.LIB;
     34  *      if not, write to the Free Software Foundation, Inc.,
     35  *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
     36  */
     37 
     38 #include "pthread.h"
     39 #include "implement.h"
     40 #if ! defined(_UWIN) && ! defined(WINCE)
     41 #include <process.h>
     42 #endif
     43 
     44 int
     45 pthread_create (pthread_t * tid,
     46 		const pthread_attr_t * attr,
     47 		void *(PTW32_CDECL *start) (void *), void *arg)
     48      /*
     49       * ------------------------------------------------------
     50       * DOCPUBLIC
     51       *      This function creates a thread running the start function,
     52       *      passing it the parameter value, 'arg'. The 'attr'
     53       *      argument specifies optional creation attributes.
     54       *      The identity of the new thread is returned
     55       *      via 'tid', which should not be NULL.
     56       *
     57       * PARAMETERS
     58       *      tid
     59       *              pointer to an instance of pthread_t
     60       *
     61       *      attr
     62       *              optional pointer to an instance of pthread_attr_t
     63       *
     64       *      start
     65       *              pointer to the starting routine for the new thread
     66       *
     67       *      arg
     68       *              optional parameter passed to 'start'
     69       *
     70       *
     71       * DESCRIPTION
     72       *      This function creates a thread running the start function,
     73       *      passing it the parameter value, 'arg'. The 'attr'
     74       *      argument specifies optional creation attributes.
     75       *      The identity of the new thread is returned
     76       *      via 'tid', which should not be the NULL pointer.
     77       *
     78       * RESULTS
     79       *              0               successfully created thread,
     80       *              EINVAL          attr invalid,
     81       *              EAGAIN          insufficient resources.
     82       *
     83       * ------------------------------------------------------
     84       */
     85 {
     86   pthread_t thread;
     87   ptw32_thread_t * tp;
     88   register pthread_attr_t a;
     89   HANDLE threadH = 0;
     90   int result = EAGAIN;
     91   int run = PTW32_TRUE;
     92   ThreadParms *parms = NULL;
     93   unsigned int stackSize;
     94   int priority;
     95   pthread_t self;
     96 
     97   /*
     98    * Before doing anything, check that tid can be stored through
     99    * without invoking a memory protection error (segfault).
    100    * Make sure that the assignment below can't be optimised out by the compiler.
    101    * This is assured by conditionally assigning *tid again at the end.
    102    */
    103   tid->x = 0;
    104 
    105   if (attr != NULL)
    106     {
    107       a = *attr;
    108     }
    109   else
    110     {
    111       a = NULL;
    112     }
    113 
    114   if ((thread = ptw32_new ()).p == NULL)
    115     {
    116       goto FAIL0;
    117     }
    118 
    119   tp = (ptw32_thread_t *) thread.p;
    120 
    121   priority = tp->sched_priority;
    122 
    123   if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL)
    124     {
    125       goto FAIL0;
    126     }
    127 
    128   parms->tid = thread;
    129   parms->start = start;
    130   parms->arg = arg;
    131 
    132 #if defined(HAVE_SIGSET_T)
    133 
    134   /*
    135    * Threads inherit their initial sigmask from their creator thread.
    136    */
    137   self = pthread_self();
    138   tp->sigmask = ((ptw32_thread_t *)self.p)->sigmask;
    139 
    140 #endif /* HAVE_SIGSET_T */
    141 
    142 
    143   if (a != NULL)
    144     {
    145       stackSize = (unsigned int)a->stacksize;
    146       tp->detachState = a->detachstate;
    147       priority = a->param.sched_priority;
    148 
    149 #if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL)
    150       /* WinCE */
    151 #else
    152       /* Everything else */
    153 
    154       /*
    155        * Thread priority must be set to a valid system level
    156        * without altering the value set by pthread_attr_setschedparam().
    157        */
    158 
    159       /*
    160        * PTHREAD_EXPLICIT_SCHED is the default because Win32 threads
    161        * don't inherit their creator's priority. They are started with
    162        * THREAD_PRIORITY_NORMAL (win32 value). The result of not supplying
    163        * an 'attr' arg to pthread_create() is equivalent to defaulting to
    164        * PTHREAD_EXPLICIT_SCHED and priority THREAD_PRIORITY_NORMAL.
    165        */
    166       if (PTHREAD_INHERIT_SCHED == a->inheritsched)
    167 	{
    168 	  /*
    169 	   * If the thread that called pthread_create() is a Win32 thread
    170 	   * then the inherited priority could be the result of a temporary
    171 	   * system adjustment. This is not the case for POSIX threads.
    172 	   */
    173 #if ! defined(HAVE_SIGSET_T)
    174 	  self = pthread_self ();
    175 #endif
    176 	  priority = ((ptw32_thread_t *) self.p)->sched_priority;
    177 	}
    178 
    179 #endif
    180 
    181     }
    182   else
    183     {
    184       /*
    185        * Default stackSize
    186        */
    187       stackSize = PTHREAD_STACK_MIN;
    188     }
    189 
    190   tp->state = run ? PThreadStateInitial : PThreadStateSuspended;
    191 
    192   tp->keys = NULL;
    193 
    194   /*
    195    * Threads must be started in suspended mode and resumed if necessary
    196    * after _beginthreadex returns us the handle. Otherwise we set up a
    197    * race condition between the creating and the created threads.
    198    * Note that we also retain a local copy of the handle for use
    199    * by us in case thread.p->threadH gets NULLed later but before we've
    200    * finished with it here.
    201    */
    202 
    203 #if ! (defined (__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__)
    204 
    205   tp->threadH =
    206     threadH =
    207     (HANDLE) _beginthreadex ((void *) NULL,	/* No security info             */
    208 			     stackSize,		/* default stack size   */
    209 			     ptw32_threadStart,
    210 			     parms,
    211 			     (unsigned)
    212 			     CREATE_SUSPENDED,
    213 			     (unsigned *) &(tp->thread));
    214 
    215   if (threadH != 0)
    216     {
    217       if (a != NULL)
    218 	{
    219 	  (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority);
    220 	}
    221 
    222       if (run)
    223 	{
    224 	  ResumeThread (threadH);
    225 	}
    226     }
    227 
    228 #else
    229 
    230   {
    231     ptw32_mcs_local_node_t stateLock;
    232 
    233     /*
    234      * This lock will force pthread_threadStart() to wait until we have
    235      * the thread handle and have set the priority.
    236      */
    237     ptw32_mcs_lock_acquire(&tp->stateLock, &stateLock);
    238 
    239     tp->threadH =
    240       threadH =
    241       (HANDLE) _beginthread (ptw32_threadStart, stackSize,	/* default stack size   */
    242 			     parms);
    243 
    244     /*
    245      * Make the return code match _beginthreadex's.
    246      */
    247     if (threadH == (HANDLE) - 1L)
    248       {
    249         tp->threadH = threadH = 0;
    250       }
    251     else
    252       {
    253         if (!run)
    254 	  {
    255 	    /*
    256 	     * beginthread does not allow for create flags, so we do it now.
    257 	     * Note that beginthread itself creates the thread in SUSPENDED
    258 	     * mode, and then calls ResumeThread to start it.
    259 	     */
    260 	    SuspendThread (threadH);
    261 	  }
    262 
    263         if (a != NULL)
    264 	  {
    265 	    (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority);
    266 	  }
    267       }
    268 
    269     ptw32_mcs_lock_release (&stateLock);
    270   }
    271 #endif
    272 
    273   result = (threadH != 0) ? 0 : EAGAIN;
    274 
    275   /*
    276    * Fall Through Intentionally
    277    */
    278 
    279   /*
    280    * ------------
    281    * Failure Code
    282    * ------------
    283    */
    284 
    285 FAIL0:
    286   if (result != 0)
    287     {
    288 
    289       ptw32_threadDestroy (thread);
    290       tp = NULL;
    291 
    292       if (parms != NULL)
    293 	{
    294 	  free (parms);
    295 	}
    296     }
    297   else
    298     {
    299       *tid = thread;
    300     }
    301 
    302 #if defined(_UWIN)
    303   if (result == 0)
    304     pthread_count++;
    305 #endif
    306   return (result);
    307 
    308 }				/* pthread_create */
    309