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@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  *      51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
pthread_create(pthread_t * tid,const pthread_attr_t * attr,void * (PTW32_CDECL * start)(void *),void * arg)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