OSDN Git Service

* miscfuncs.cc (thread_wrapper): Make sure stack is 16 byte aligned
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / miscfuncs.cc
1 /* miscfuncs.cc: misc funcs that don't belong anywhere else
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4    2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include "miscfuncs.h"
14 #include <sys/uio.h>
15 #include <assert.h>
16 #include <alloca.h>
17 #include <limits.h>
18 #include <sys/param.h>
19 #include <wchar.h>
20 #include <wingdi.h>
21 #include <winuser.h>
22 #include <winnls.h>
23 #include "cygtls.h"
24 #include "ntdll.h"
25 #include "path.h"
26 #include "fhandler.h"
27 #include "dtable.h"
28 #include "cygheap.h"
29 #include "pinfo.h"
30 #include "exception.h"
31
32 long tls_ix = -1;
33
34 const char case_folded_lower[] NO_COPY = {
35    0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
36   16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
37   32, '!', '"', '#', '$', '%', '&',  39, '(', ')', '*', '+', ',', '-', '.', '/',
38  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
39  '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
40  'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '[',  92, ']', '^', '_',
41  '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
42  'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 127,
43  128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
44  144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
45  160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
46  176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
47  192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
48  208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
49  224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
50  240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
51 };
52
53 const char case_folded_upper[] NO_COPY = {
54    0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
55   16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
56   32, '!', '"', '#', '$', '%', '&',  39, '(', ')', '*', '+', ',', '-', '.', '/',
57  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
58  '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
59  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[',  92, ']', '^', '_',
60  '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
61  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', 127,
62  128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
63  144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
64  160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
65  176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
66  192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
67  208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
68  224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
69  240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
70 };
71
72 const char isalpha_array[] NO_COPY = {
73    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
74    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
75    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
76    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
77    0,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
78 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,   0,   0,   0,   0,   0,
79    0,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
80 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,   0,   0,   0,   0,   0,
81    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
82    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
83    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
84    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
85    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
86    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
87    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
88    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
89 };
90
91 extern "C" int __stdcall
92 cygwin_wcscasecmp (const wchar_t *ws, const wchar_t *wt)
93 {
94   UNICODE_STRING us, ut;
95
96   RtlInitUnicodeString (&us, ws);
97   RtlInitUnicodeString (&ut, wt);
98   return RtlCompareUnicodeString (&us, &ut, TRUE);
99 }
100
101 extern "C" int __stdcall
102 cygwin_wcsncasecmp (const wchar_t  *ws, const wchar_t *wt, size_t n)
103 {
104   UNICODE_STRING us, ut;
105   size_t ls = 0, lt = 0;
106
107   while (ws[ls] && ls < n)
108     ++ls;
109   RtlInitCountedUnicodeString (&us, ws, ls * sizeof (WCHAR));
110   while (wt[lt] && lt < n)
111     ++lt;
112   RtlInitCountedUnicodeString (&ut, wt, lt * sizeof (WCHAR));
113   return RtlCompareUnicodeString (&us, &ut, TRUE);
114 }
115
116 extern "C" int __stdcall
117 cygwin_strcasecmp (const char *cs, const char *ct)
118 {
119   UNICODE_STRING us, ut;
120   ULONG len;
121
122   len = (strlen (cs) + 1) * sizeof (WCHAR);
123   RtlInitEmptyUnicodeString (&us, (PWCHAR) alloca (len), len);
124   us.Length = sys_mbstowcs (us.Buffer, us.MaximumLength, cs) * sizeof (WCHAR);
125   len = (strlen (ct) + 1) * sizeof (WCHAR);
126   RtlInitEmptyUnicodeString (&ut, (PWCHAR) alloca (len), len);
127   ut.Length = sys_mbstowcs (ut.Buffer, ut.MaximumLength, ct) * sizeof (WCHAR);
128   return RtlCompareUnicodeString (&us, &ut, TRUE);
129 }
130
131 extern "C" int __stdcall
132 cygwin_strncasecmp (const char *cs, const char *ct, size_t n)
133 {
134   UNICODE_STRING us, ut;
135   ULONG len;
136   size_t ls = 0, lt = 0;
137
138   while (cs[ls] && ls < n)
139     ++ls;
140   len = (ls + 1) * sizeof (WCHAR);
141   RtlInitEmptyUnicodeString (&us, (PWCHAR) alloca (len), len);
142   us.Length = sys_mbstowcs (us.Buffer, ls + 1, cs, ls) * sizeof (WCHAR);
143   while (ct[lt] && lt < n)
144     ++lt;
145   len = (lt + 1) * sizeof (WCHAR);
146   RtlInitEmptyUnicodeString (&ut, (PWCHAR) alloca (len), len);
147   ut.Length = sys_mbstowcs (ut.Buffer, lt + 1, ct, lt)  * sizeof (WCHAR);
148   return RtlCompareUnicodeString (&us, &ut, TRUE);
149 }
150
151 extern "C" char * __stdcall
152 cygwin_strlwr (char *string)
153 {
154   UNICODE_STRING us;
155   size_t len = (strlen (string) + 1) * sizeof (WCHAR);
156
157   us.MaximumLength = len; us.Buffer = (PWCHAR) alloca (len);
158   us.Length = sys_mbstowcs (us.Buffer, len, string) * sizeof (WCHAR)
159               - sizeof (WCHAR);
160   RtlDowncaseUnicodeString (&us, &us, FALSE);
161   sys_wcstombs (string, len / sizeof (WCHAR), us.Buffer);
162   return string;
163 }
164
165 extern "C" char * __stdcall
166 cygwin_strupr (char *string)
167 {
168   UNICODE_STRING us;
169   size_t len = (strlen (string) + 1) * sizeof (WCHAR);
170
171   us.MaximumLength = len; us.Buffer = (PWCHAR) alloca (len);
172   us.Length = sys_mbstowcs (us.Buffer, len, string) * sizeof (WCHAR)
173               - sizeof (WCHAR);
174   RtlUpcaseUnicodeString (&us, &us, FALSE);
175   sys_wcstombs (string, len / sizeof (WCHAR), us.Buffer);
176   return string;
177 }
178
179 int __stdcall
180 check_invalid_virtual_addr (const void *s, unsigned sz)
181 {
182   MEMORY_BASIC_INFORMATION mbuf;
183   const void *end;
184
185   for (end = (char *) s + sz; s < end;
186        s = (char *) mbuf.BaseAddress + mbuf.RegionSize)
187     if (!VirtualQuery (s, &mbuf, sizeof mbuf))
188       return EINVAL;
189   return 0;
190 }
191
192 static char __attribute__ ((noinline))
193 dummytest (volatile char *p)
194 {
195   return *p;
196 }
197
198 ssize_t
199 check_iovec (const struct iovec *iov, int iovcnt, bool forwrite)
200 {
201   if (iovcnt <= 0 || iovcnt > IOV_MAX)
202     {
203       set_errno (EINVAL);
204       return -1;
205     }
206
207   myfault efault;
208   if (efault.faulted (EFAULT))
209     return -1;
210
211   size_t tot = 0;
212
213   while (iovcnt != 0)
214     {
215       if (iov->iov_len > SSIZE_MAX || (tot += iov->iov_len) > SSIZE_MAX)
216         {
217           set_errno (EINVAL);
218           return -1;
219         }
220
221       volatile char *p = ((char *) iov->iov_base) + iov->iov_len - 1;
222       if (!iov->iov_len)
223         /* nothing to do */;
224       else if (!forwrite)
225         *p  = dummytest (p);
226       else
227         dummytest (p);
228
229       iov++;
230       iovcnt--;
231     }
232
233   assert (tot <= SSIZE_MAX);
234
235   return (ssize_t) tot;
236 }
237
238 /* Try hard to schedule another thread. */
239 void
240 yield ()
241 {
242   int prio = GetThreadPriority (GetCurrentThread ());
243   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE);
244   for (int i = 0; i < 2; i++)
245     {
246       /* MSDN implies that SleepEx(0,...) will force scheduling of other
247          threads.  Unlike SwitchToThread() the documentation does not mention
248          other cpus so, presumably (hah!), this + using a lower priority will
249          stall this thread temporarily and cause another to run.  */
250       SleepEx (0, false);
251     }
252   SetThreadPriority (GetCurrentThread (), prio);
253 }
254
255 /* Get a default value for the nice factor.  When changing these values,
256    have a look into the below function nice_to_winprio.  The values must
257    match the layout of the static "priority" array. */
258 int
259 winprio_to_nice (DWORD prio)
260 {
261   switch (prio)
262     {
263       case REALTIME_PRIORITY_CLASS:
264         return -20;
265       case HIGH_PRIORITY_CLASS:
266         return -16;
267       case ABOVE_NORMAL_PRIORITY_CLASS:
268         return -8;
269       case NORMAL_PRIORITY_CLASS:
270         return 0;
271       case BELOW_NORMAL_PRIORITY_CLASS:
272         return 8;
273       case IDLE_PRIORITY_CLASS:
274         return 16;
275     }
276   return 0;
277 }
278
279 /* Get a Win32 priority matching the incoming nice factor.  The incoming
280    nice is limited to the interval [-NZERO,NZERO-1]. */
281 DWORD
282 nice_to_winprio (int &nice)
283 {
284   static const DWORD priority[] NO_COPY =
285     {
286       REALTIME_PRIORITY_CLASS,          /*  0 */
287       HIGH_PRIORITY_CLASS,              /*  1 */
288       HIGH_PRIORITY_CLASS,
289       HIGH_PRIORITY_CLASS,
290       HIGH_PRIORITY_CLASS,
291       HIGH_PRIORITY_CLASS,
292       HIGH_PRIORITY_CLASS,
293       HIGH_PRIORITY_CLASS,              /*  7 */
294       ABOVE_NORMAL_PRIORITY_CLASS,      /*  8 */
295       ABOVE_NORMAL_PRIORITY_CLASS,
296       ABOVE_NORMAL_PRIORITY_CLASS,
297       ABOVE_NORMAL_PRIORITY_CLASS,
298       ABOVE_NORMAL_PRIORITY_CLASS,
299       ABOVE_NORMAL_PRIORITY_CLASS,
300       ABOVE_NORMAL_PRIORITY_CLASS,
301       ABOVE_NORMAL_PRIORITY_CLASS,      /* 15 */
302       NORMAL_PRIORITY_CLASS,            /* 16 */
303       NORMAL_PRIORITY_CLASS,
304       NORMAL_PRIORITY_CLASS,
305       NORMAL_PRIORITY_CLASS,
306       NORMAL_PRIORITY_CLASS,
307       NORMAL_PRIORITY_CLASS,
308       NORMAL_PRIORITY_CLASS,
309       NORMAL_PRIORITY_CLASS,            /* 23 */
310       BELOW_NORMAL_PRIORITY_CLASS,      /* 24 */
311       BELOW_NORMAL_PRIORITY_CLASS,
312       BELOW_NORMAL_PRIORITY_CLASS,
313       BELOW_NORMAL_PRIORITY_CLASS,
314       BELOW_NORMAL_PRIORITY_CLASS,
315       BELOW_NORMAL_PRIORITY_CLASS,
316       BELOW_NORMAL_PRIORITY_CLASS,
317       BELOW_NORMAL_PRIORITY_CLASS,      /* 31 */
318       IDLE_PRIORITY_CLASS,              /* 32 */
319       IDLE_PRIORITY_CLASS,
320       IDLE_PRIORITY_CLASS,
321       IDLE_PRIORITY_CLASS,
322       IDLE_PRIORITY_CLASS,
323       IDLE_PRIORITY_CLASS,
324       IDLE_PRIORITY_CLASS,
325       IDLE_PRIORITY_CLASS               /* 39 */
326     };
327   if (nice < -NZERO)
328     nice = -NZERO;
329   else if (nice > NZERO - 1)
330     nice = NZERO - 1;
331   DWORD prio = priority[nice + NZERO];
332   return prio;
333 }
334
335 /* Minimal overlapped pipe I/O implementation for signal and commune stuff. */
336
337 BOOL WINAPI
338 CreatePipeOverlapped (PHANDLE hr, PHANDLE hw, LPSECURITY_ATTRIBUTES sa)
339 {
340   int ret = fhandler_pipe::create (sa, hr, hw, 0, NULL,
341                                    FILE_FLAG_OVERLAPPED);
342   if (ret)
343     SetLastError (ret);
344   return ret == 0;
345 }
346
347 BOOL WINAPI
348 ReadPipeOverlapped (HANDLE h, PVOID buf, DWORD len, LPDWORD ret_len,
349                     DWORD timeout)
350 {
351   OVERLAPPED ov;
352   BOOL ret;
353
354   memset (&ov, 0, sizeof ov);
355   ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
356   ret = ReadFile (h, buf, len, NULL, &ov);
357   if (ret || GetLastError () == ERROR_IO_PENDING)
358     {
359       if (!ret && WaitForSingleObject (ov.hEvent, timeout) != WAIT_OBJECT_0)
360         CancelIo (h);
361       ret = GetOverlappedResult (h, &ov, ret_len, FALSE);
362     }
363   CloseHandle (ov.hEvent);
364   return ret;
365 }
366
367 BOOL WINAPI
368 WritePipeOverlapped (HANDLE h, PCVOID buf, DWORD len, LPDWORD ret_len,
369                      DWORD timeout)
370 {
371   OVERLAPPED ov;
372   BOOL ret;
373
374   memset (&ov, 0, sizeof ov);
375   ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
376   ret = WriteFile (h, buf, len, NULL, &ov);
377   if (ret || GetLastError () == ERROR_IO_PENDING)
378     {
379       if (!ret && WaitForSingleObject (ov.hEvent, timeout) != WAIT_OBJECT_0)
380         CancelIo (h);
381       ret = GetOverlappedResult (h, &ov, ret_len, FALSE);
382     }
383   CloseHandle (ov.hEvent);
384   return ret;
385 }
386
387 /* backslashify: Convert all forward slashes in src path to back slashes
388    in dst path.  Add a trailing slash to dst when trailing_slash_p arg
389    is set to 1. */
390
391 void
392 backslashify (const char *src, char *dst, bool trailing_slash_p)
393 {
394   const char *start = src;
395
396   while (*src)
397     {
398       if (*src == '/')
399         *dst++ = '\\';
400       else
401         *dst++ = *src;
402       ++src;
403     }
404   if (trailing_slash_p
405       && src > start
406       && !isdirsep (src[-1]))
407     *dst++ = '\\';
408   *dst++ = 0;
409 }
410
411 /* slashify: Convert all back slashes in src path to forward slashes
412    in dst path.  Add a trailing slash to dst when trailing_slash_p arg
413    is set to 1. */
414
415 void
416 slashify (const char *src, char *dst, bool trailing_slash_p)
417 {
418   const char *start = src;
419
420   while (*src)
421     {
422       if (*src == '\\')
423         *dst++ = '/';
424       else
425         *dst++ = *src;
426       ++src;
427     }
428   if (trailing_slash_p
429       && src > start
430       && !isdirsep (src[-1]))
431     *dst++ = '/';
432   *dst++ = 0;
433 }
434
435 /* CygwinCreateThread.
436
437    Replacement function for CreateThread.  What we do here is to remove
438    parameters we don't use and instead to add parameters we need to make
439    the function pthreads compatible. */
440
441 struct thread_wrapper_arg
442 {
443   LPTHREAD_START_ROUTINE func;
444   PVOID arg;
445   char *stackaddr;
446   char *stackbase;
447   char *commitaddr;
448 };
449
450 DWORD WINAPI
451 thread_wrapper (VOID *arg)
452 {
453   /* Just plain paranoia. */
454   if (!arg)
455     return ERROR_INVALID_PARAMETER;
456
457   /* Fetch thread wrapper info and free from cygheap. */
458   thread_wrapper_arg wrapper_arg = *(thread_wrapper_arg *) arg;
459   cfree (arg);
460
461   /* Remove _cygtls from this stack since it won't be used anymore. */
462   _my_tls.remove (0);
463
464   /* Set stack values in TEB */
465   PTEB teb = NtCurrentTeb ();
466   teb->Tib.StackBase = wrapper_arg.stackbase;
467   teb->Tib.StackLimit = wrapper_arg.commitaddr ?: wrapper_arg.stackaddr;
468   /* Set DeallocationStack value.  If we have an application-provided stack,
469      we set DeallocationStack to NULL, so NtTerminateThread does not deallocate
470      any stack.  If we created the stack in CygwinCreateThread, we set
471      DeallocationStack to the stackaddr of our own stack, so it's automatically
472      deallocated when the thread is terminated. */
473   char *dealloc_addr = (char *) teb->DeallocationStack;
474   teb->DeallocationStack = wrapper_arg.commitaddr ? wrapper_arg.stackaddr
475                                                   : NULL;
476   /* Store the OS-provided DeallocationStack address in wrapper_arg.stackaddr.
477      The below assembler code will release the OS stack after switching to our
478      new stack. */
479   wrapper_arg.stackaddr = dealloc_addr;
480
481   /* Initialize new _cygtls. */
482   _my_tls.init_thread (wrapper_arg.stackbase - CYGTLS_PADSIZE,
483                        (DWORD (*)(void*, void*)) wrapper_arg.func);
484
485   /* Copy exception list over to new stack.  I'm not quite sure how the
486      exception list is extended by Windows itself.  What's clear is that it
487      always grows downwards and that it starts right at the stackbase.
488      Therefore we first count the number of exception records and place
489      the copy at the stackbase, too, so there's still a lot of room to
490      extend the list up to where our _cygtls region starts. */
491   _exception_list *old_start = (_exception_list *) teb->Tib.ExceptionList;
492   unsigned count = 0;
493   teb->Tib.ExceptionList = NULL;
494   for (_exception_list *e_ptr = old_start;
495        e_ptr && e_ptr != (_exception_list *) -1;
496        e_ptr = e_ptr->prev)
497     ++count;
498   if (count)
499     {
500       _exception_list *new_start = (_exception_list *) wrapper_arg.stackbase
501                                                        - count;
502       teb->Tib.ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)
503                                new_start;
504       while (true)
505         {
506           new_start->handler = old_start->handler;
507           if (old_start->prev == (_exception_list *) -1)
508             {
509               new_start->prev = (_exception_list *) -1;
510               break;
511             }
512           new_start->prev = new_start + 1;
513           new_start = new_start->prev;
514           old_start = old_start->prev;
515         }
516     }
517
518   __asm__ ("\n\
519            movl  %[WRAPPER_ARG], %%ebx # Load &wrapper_arg into ebx  \n\
520            movl  (%%ebx), %%eax        # Load thread func into eax   \n\
521            movl  4(%%ebx), %%ecx       # Load thread arg into ecx    \n\
522            movl  8(%%ebx), %%edx       # Load stackaddr into edx     \n\
523            movl  12(%%ebx), %%ebx      # Load stackbase into ebx     \n\
524            subl  %[CYGTLS], %%ebx      # Subtract CYGTLS_PADSIZE     \n\
525            subl  $4, %%ebx             # Subtract another 4 bytes    \n\
526            movl  %%ebx, %%esp          # Set esp                     \n\
527            xorl  %%ebp, %%ebp          # Set ebp to 0                \n\
528            # Make gcc 3.x happy and align the stack so that it is    \n\
529            # 16 byte aligned right before the final call opcode.     \n\
530            andl  $-16, %%esp           # 16 bit align                \n\
531            addl  $-12, %%esp           # 12 bytes + 4 byte arg = 16  \n\
532            # Now we moved to the new stack.  Save thread func address\n\
533            # and thread arg on new stack                             \n\
534            pushl %%ecx                 # Push thread arg onto stack  \n\
535            pushl %%eax                 # Push thread func onto stack \n\
536            # Now it's safe to release the OS stack.                  \n\
537            pushl $0x8000               # dwFreeType: MEM_RELEASE     \n\
538            pushl $0x0                  # dwSize:     0               \n\
539            pushl %%edx                 # lpAddress:  stackaddr       \n\
540            call _VirtualFree@12        # Shoot                       \n\
541            # All set.  We can pop the thread function address from   \n\
542            # the stack and call it.  The thread arg is still on the  \n\
543            # stack in the expected spot.                             \n\
544            popl  %%eax                 # Pop thread_func address     \n\
545            call  *%%eax                # Call thread func            \n"
546            : : [WRAPPER_ARG] "r" (&wrapper_arg),
547                [CYGTLS] "i" (CYGTLS_PADSIZE));
548   /* Never return from here. */
549   ExitThread (0);
550 }
551
552 /* FIXME: This should be settable via setrlimit (RLIMIT_STACK). */
553 #define DEFAULT_STACKSIZE (512 * 1024)
554
555 HANDLE WINAPI
556 CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg,
557                     PVOID stackaddr, ULONG stacksize, ULONG guardsize,
558                     DWORD creation_flags, LPDWORD thread_id)
559 {
560   PVOID real_stackaddr = NULL;
561   ULONG real_stacksize = 0;
562   ULONG real_guardsize = 0;
563   thread_wrapper_arg *wrapper_arg;
564   HANDLE thread = NULL;
565
566   wrapper_arg = (thread_wrapper_arg *) ccalloc (HEAP_STR, 1,
567                                                 sizeof *wrapper_arg);
568   if (!wrapper_arg)
569     {
570       SetLastError (ERROR_OUTOFMEMORY);
571       return NULL;
572     }
573   wrapper_arg->func = thread_func;
574   wrapper_arg->arg = thread_arg;
575
576   /* Set stacksize. */
577   real_stacksize = stacksize ?: DEFAULT_STACKSIZE;
578   if (real_stacksize < PTHREAD_STACK_MIN)
579     real_stacksize = PTHREAD_STACK_MIN;
580   if (stackaddr)
581     {
582       /* If the application provided the stack, just use it. */
583       wrapper_arg->stackaddr = (char *) stackaddr;
584       wrapper_arg->stackbase = (char *) stackaddr + real_stacksize;
585     }
586   else
587     {
588       /* If not, we have to create the stack here. */
589       real_stacksize = roundup2 (real_stacksize, wincap.page_size ());
590       /* If no guardsize has been specified by the application, use the
591          system pagesize as default. */
592       real_guardsize = (guardsize != (ULONG) -1)
593                        ? guardsize : wincap.page_size ();
594       if (real_guardsize)
595         real_guardsize = roundup2 (real_guardsize, wincap.page_size ());
596       /* Add the guardsize to the stacksize, but only if the stacksize and
597          the guardsize have been explicitely specified. */
598       if (stacksize || guardsize != (ULONG) -1)
599         real_stacksize += real_guardsize;
600       /* Now roundup the result to the next allocation boundary. */
601       real_stacksize = roundup2 (real_stacksize,
602                                  wincap.allocation_granularity ());
603       /* Reserve stack.
604          FIXME? If the TOP_DOWN method tends to collide too much with
605          other stuff, we should provide our own mechanism to find a
606          suitable place for the stack.  Top down from the start of
607          the Cygwin DLL comes to mind. */
608       real_stackaddr = VirtualAlloc (NULL, real_stacksize,
609                                      MEM_RESERVE | MEM_TOP_DOWN,
610                                      PAGE_EXECUTE_READWRITE);
611       if (!real_stackaddr)
612         return NULL;
613       /* Set up committed region.  In contrast to the OS we commit 64K and
614          set up just a single guard page at the end. */
615       char *commitaddr = (char *) real_stackaddr
616                                   + real_stacksize
617                                   - wincap.allocation_granularity ();
618       if (!VirtualAlloc (commitaddr, wincap.page_size (), MEM_COMMIT,
619                          PAGE_EXECUTE_READWRITE | PAGE_GUARD))
620         goto err;
621       commitaddr += wincap.page_size ();
622       if (!VirtualAlloc (commitaddr, wincap.allocation_granularity ()
623                                      - wincap.page_size (), MEM_COMMIT,
624                          PAGE_EXECUTE_READWRITE))
625         goto err;
626       if (real_guardsize)
627         VirtualAlloc (real_stackaddr, real_guardsize, MEM_COMMIT,
628                       PAGE_NOACCESS);
629       wrapper_arg->stackaddr = (char *) real_stackaddr;
630       wrapper_arg->stackbase = (char *) real_stackaddr + real_stacksize;
631       wrapper_arg->commitaddr = commitaddr;
632     }
633   /* Use the STACK_SIZE_PARAM_IS_A_RESERVATION parameter so only the
634      minimum size for a thread stack is reserved by the OS.  This doesn't
635      work on Windows 2000, but we deallocate the OS stack in thread_wrapper
636      anyway, so this should be a problem only in a tight memory condition.
637      Note that we reserve a 256K stack, not 64K, otherwise the thread creation
638      might crash the process due to a stack overflow. */
639   thread = CreateThread (&sec_none_nih, 4 * PTHREAD_STACK_MIN,
640                          thread_wrapper, wrapper_arg,
641                          creation_flags | STACK_SIZE_PARAM_IS_A_RESERVATION,
642                          thread_id);
643
644 err:
645   if (!thread && real_stackaddr)
646     {
647       /* Don't report the wrong error even though VirtualFree is very unlikely
648          to fail. */
649       DWORD err = GetLastError ();
650       VirtualFree (real_stackaddr, 0, MEM_RELEASE);
651       SetLastError (err);
652     }
653   return thread;
654 }