OSDN Git Service

* select.cc (select_stuff::wait): Temporarily disallow APCS.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / cygtls.cc
1 /* cygtls.cc
2
3    Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
4
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
7 details. */
8
9 #include "winsup.h"
10 #define USE_SYS_TYPES_FD_SET
11 #include "cygtls.h"
12 #include <syslog.h>
13 #include <stdlib.h>
14 #include "path.h"
15 #include "fhandler.h"
16 #include "dtable.h"
17 #include "cygheap.h"
18 #include "sigproc.h"
19 #include "exception.h"
20
21 class sentry
22 {
23   static muto lock;
24   int destroy;
25 public:
26   void init ();
27   bool acquired () {return lock.acquired ();}
28   sentry () {destroy = 0;}
29   sentry (DWORD wait) {destroy = lock.acquire (wait);}
30   ~sentry () {if (destroy) lock.release ();}
31   friend void _cygtls::init ();
32 };
33
34 muto NO_COPY sentry::lock;
35
36 static size_t NO_COPY nthreads;
37
38 #define THREADLIST_CHUNK 256
39
40 void
41 _cygtls::init ()
42 {
43   if (cygheap->threadlist)
44     memset (cygheap->threadlist, 0, cygheap->sthreads * sizeof (cygheap->threadlist[0]));
45   else
46     {
47       cygheap->sthreads = THREADLIST_CHUNK;
48       cygheap->threadlist = (_cygtls **) ccalloc_abort (HEAP_TLS, cygheap->sthreads,
49                                                         sizeof (cygheap->threadlist[0]));
50     }
51   sentry::lock.init ("sentry_lock");
52 }
53
54 /* Two calls to get the stack right... */
55 void
56 _cygtls::call (DWORD (*func) (void *, void *), void *arg)
57 {
58   char buf[CYGTLS_PADSIZE];
59   /* Initialize this thread's ability to respond to things like
60      SIGSEGV or SIGFPE. */
61   exception protect;
62   _my_tls.call2 (func, arg, buf);
63 }
64
65 void
66 _cygtls::call2 (DWORD (*func) (void *, void *), void *arg, void *buf)
67 {
68   init_thread (buf, func);
69   DWORD res = func (arg, buf);
70   remove (INFINITE);
71   /* Don't call ExitThread on the main thread since we may have been
72      dynamically loaded.  */
73   if ((void *) func != (void *) dll_crt0_1
74       && (void *) func != (void *) dll_dllcrt0_1)
75     ExitThread (res);
76 }
77
78 void
79 _cygtls::init_thread (void *x, DWORD (*func) (void *, void *))
80 {
81   if (x)
82     {
83       memset (this, 0, sizeof (*this));
84       _REENT_INIT_PTR (&local_clib);
85       stackptr = stack;
86       if (_GLOBAL_REENT)
87         {
88           local_clib._stdin = _GLOBAL_REENT->_stdin;
89           local_clib._stdout = _GLOBAL_REENT->_stdout;
90           local_clib._stderr = _GLOBAL_REENT->_stderr;
91           local_clib.__sdidinit = _GLOBAL_REENT->__sdidinit ? -1 : 0;
92           local_clib.__cleanup = _GLOBAL_REENT->__cleanup;
93           local_clib.__sglue._niobs = 3;
94           local_clib.__sglue._iobs = &_GLOBAL_REENT->__sf[0];
95         }
96     }
97
98   thread_id = GetCurrentThreadId ();
99   initialized = CYGTLS_INITIALIZED;
100   errno_addr = &(local_clib._errno);
101   locals.cw_timer = NULL;
102
103   if ((void *) func == (void *) cygthread::stub
104       || (void *) func == (void *) cygthread::simplestub)
105     return;
106
107   cygheap->user.reimpersonate ();
108
109   sentry here (INFINITE);
110   if (nthreads >= cygheap->sthreads)
111     {
112       cygheap->threadlist = (_cygtls **)
113         crealloc_abort (cygheap->threadlist, (cygheap->sthreads += THREADLIST_CHUNK)
114                         * sizeof (cygheap->threadlist[0]));
115       memset (cygheap->threadlist + nthreads, 0, THREADLIST_CHUNK * sizeof (cygheap->threadlist[0]));
116     }
117
118   cygheap->threadlist[nthreads++] = this;
119 }
120
121 void
122 _cygtls::fixup_after_fork ()
123 {
124   if (sig)
125     {
126       pop ();
127       sig = 0;
128     }
129   stacklock = spinning = 0;
130   locals.select.sockevt = NULL;
131   locals.cw_timer = NULL;
132   wq.thread_ev = NULL;
133 }
134
135 #define free_local(x) \
136   if (locals.x) \
137     { \
138       free (locals.x); \
139       locals.x = NULL; \
140     }
141
142 void
143 _cygtls::remove (DWORD wait)
144 {
145   initialized = 0;
146   if (exit_state >= ES_FINAL)
147     return;
148
149   debug_printf ("wait %p", wait);
150
151   /* FIXME: Need some sort of atthreadexit function to allow things like
152      select to control this themselves. */
153
154   /* Close handle and free memory used by select. */
155   if (locals.select.sockevt)
156     {
157       CloseHandle (locals.select.sockevt);
158       locals.select.sockevt = NULL;
159       free_local (select.ser_num);
160       free_local (select.w4);
161     }
162   /* Free memory used by network functions. */
163   free_local (ntoa_buf);
164   free_local (protoent_buf);
165   free_local (servent_buf);
166   free_local (hostent_buf);
167   /* Free temporary TLS path buffers. */
168   locals.pathbufs.destroy ();
169
170   do
171     {
172       sentry here (wait);
173       if (here.acquired ())
174         {
175           for (size_t i = 0; i < nthreads; i++)
176             if (this == cygheap->threadlist[i])
177               {
178                 if (i < --nthreads)
179                   cygheap->threadlist[i] = cygheap->threadlist[nthreads];
180                 debug_printf ("removed %p element %d", this, i);
181                 break;
182               }
183         }
184     } while (0);
185   remove_wq (wait);
186 }
187
188 void
189 _cygtls::push (__stack_t addr)
190 {
191   *stackptr++ = (__stack_t) addr;
192 }
193
194
195 _cygtls *
196 _cygtls::find_tls (int sig)
197 {
198   static int NO_COPY threadlist_ix;
199
200   debug_printf ("signal %d\n", sig);
201   sentry here (INFINITE);
202
203   _cygtls *res = NULL;
204   threadlist_ix = -1;
205
206   myfault efault;
207   if (efault.faulted ())
208     cygheap->threadlist[threadlist_ix]->remove (INFINITE);
209
210   while (++threadlist_ix < (int) nthreads)
211     if (sigismember (&(cygheap->threadlist[threadlist_ix]->sigwait_mask), sig))
212       {
213         res = cygheap->threadlist[threadlist_ix];
214         break;
215       }
216   return res;
217 }
218
219 void
220 _cygtls::set_siginfo (sigpacket *pack)
221 {
222   infodata = pack->si;
223 }