OSDN Git Service

* cygmagic: Suppress error output when figuring out if sum takes an option.
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / debug.cc
1 /* debug.cc
2
3    Copyright 1998, 1999, 2000, 2001 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 #include "exceptions.h"
11 #include "sync.h"
12 #include "sigproc.h"
13 #include "pinfo.h"
14 #include "perthread.h"
15 #include "perprocess.h"
16 #include "security.h"
17 #include "cygerrno.h"
18
19 #undef CloseHandle
20
21 static muto NO_COPY *threadname_lock = NULL;
22 #define lock_threadname() \
23   do {if (threadname_lock) threadname_lock->acquire (INFINITE); } while (0)
24
25 #define unlock_threadname() \
26   do {if (threadname_lock) threadname_lock->release (); } while (0)
27
28 typedef struct
29   {
30     DWORD id;
31     const char *name;
32   } thread_info;
33
34 static NO_COPY thread_info threads[32] = {{0, NULL}};   // increase as necessary
35 #define NTHREADS (sizeof (threads) / sizeof (threads[0]))
36
37 void
38 threadname_init ()
39 {
40   threadname_lock = new_muto (FALSE, "threadname_lock");
41 }
42
43 void __stdcall
44 regthread (const char *name, DWORD tid)
45 {
46   lock_threadname ();
47   for (DWORD i = 0; i < NTHREADS; i++)
48     if (threads[i].name == NULL || strcmp (threads[i].name, name) == 0 ||
49         threads[i].id == tid)
50       {
51         threads[i].name = name;
52         threads[i].id = tid;
53         break;
54       }
55   unlock_threadname ();
56 }
57
58 int __stdcall
59 iscygthread ()
60 {
61   DWORD tid = GetCurrentThreadId ();
62   if (tid != mainthread.id)
63     for (DWORD i = 0; i < NTHREADS && threads[i].name != NULL; i++)
64       if (threads[i].id == tid)
65         return 1;
66   return 0;
67 }
68
69 struct thread_start
70   {
71     LONG notavail;
72     LPTHREAD_START_ROUTINE func;
73     VOID *arg;
74   };
75
76 /* A place to store arguments to thread_stub since they can't be
77   stored on the stack.  An available element is !notavail. */
78 thread_start NO_COPY start_buf[NTHREADS] = {{0, NULL,NULL}};
79
80 /* Initial stub called by makethread. Performs initial per-thread
81    initialization.  */
82 static DWORD WINAPI
83 thread_stub (VOID *arg)
84 {
85   DECLARE_TLS_STORAGE;
86   LPTHREAD_START_ROUTINE threadfunc = ((thread_start *) arg)->func;
87   VOID *threadarg = ((thread_start *) arg)->arg;
88
89   exception_list except_entry;
90
91   /* Give up our slot in the start_buf array */
92   (void) InterlockedExchange (&((thread_start *) arg)->notavail, 0);
93
94   /* Initialize this thread's ability to respond to things like
95      SIGSEGV or SIGFPE. */
96   init_exceptions (&except_entry);
97
98   ExitThread (threadfunc (threadarg));
99 }
100
101 /* Wrapper for CreateThread.  Registers the thread name/id and ensures that
102    cygwin threads are properly initialized. */
103 HANDLE __stdcall
104 makethread (LPTHREAD_START_ROUTINE start, LPVOID param, DWORD flags,
105             const char *name)
106 {
107   DWORD tid;
108   HANDLE h;
109   thread_start *info;   /* Various information needed by the newly created thread */
110
111   for (;;)
112     {
113       /* Search the start_buf array for an empty slot to use */
114       for (info = start_buf; info < start_buf + NTHREADS; info++)
115         if (!InterlockedExchange (&info->notavail, 1))
116           goto out;
117
118       /* Should never hit here, but be defensive anyway. */
119       Sleep (0);
120     }
121
122 out:
123   info->func = start;   /* Real function to start */
124   info->arg = param;    /* The single parameter to the thread */
125
126   if ((h = CreateThread (&sec_none_nih, 0, thread_stub, (VOID *) info, flags,
127                          &tid)))
128     regthread (name, tid);      /* Register for debugging output. */
129
130   return h;
131 }
132
133 /* Return the symbolic name of the current thread for debugging.
134  */
135 const char * __stdcall
136 threadname (DWORD tid, int lockit)
137 {
138   const char *res = NULL;
139   if (!tid)
140     tid = GetCurrentThreadId ();
141
142   if (lockit)
143     lock_threadname ();
144   for (DWORD i = 0; i < NTHREADS && threads[i].name != NULL; i++)
145     if (threads[i].id == tid)
146       {
147         res = threads[i].name;
148         break;
149       }
150   if (lockit)
151     unlock_threadname ();
152
153   if (!res)
154     {
155       static char buf[30] NO_COPY = {0};
156       __small_sprintf (buf, "unknown (%p)", tid);
157       res = buf;
158     }
159
160   return res;
161 }
162
163 #ifdef DEBUGGING
164 /* Here lies extra debugging routines which help track down internal
165    Cygwin problems when compiled with -DDEBUGGING . */
166 #include <stdlib.h>
167
168 typedef struct _h
169   {
170     BOOL allocated;
171     HANDLE h;
172     const char *name;
173     const char *func;
174     int ln;
175     DWORD clexec_pid;
176     struct _h *next;
177   } handle_list;
178
179 static NO_COPY handle_list starth = {0, NULL, NULL, NULL, 0, 0, NULL};
180 static NO_COPY handle_list *endh = NULL;
181
182 static handle_list NO_COPY freeh[1000] = {{0, NULL, NULL, NULL, 0, 0, NULL}};
183 #define NFREEH (sizeof (freeh) / sizeof (freeh[0]))
184
185 static muto NO_COPY *debug_lock = NULL;
186
187 #define lock_debug() \
188   do {if (debug_lock) debug_lock->acquire (INFINITE); } while (0)
189
190 #define unlock_debug() \
191   do {if (debug_lock) debug_lock->release (); } while (0)
192
193 static bool __stdcall mark_closed (const char *, int, HANDLE, const char *, BOOL);
194
195 void
196 debug_init ()
197 {
198   debug_lock = new_muto (FALSE, "debug_lock");
199 }
200
201 /* Find a registered handle in the linked list of handles. */
202 static handle_list * __stdcall
203 find_handle (HANDLE h)
204 {
205   handle_list *hl;
206   for (hl = &starth; hl->next != NULL; hl = hl->next)
207     if (hl->next->h == h)
208       goto out;
209   endh = hl;
210   hl = NULL;
211
212 out:
213   return hl;
214 }
215
216 void
217 setclexec_pid (HANDLE oh, HANDLE nh, bool setit)
218 {
219   handle_list *hl = find_handle (oh);
220   if (hl)
221     {
222       hl->clexec_pid = setit ? GetCurrentProcessId () : 0;
223       hl->h = nh;
224     }
225 }
226
227 /* Create a new handle record */
228 static handle_list * __stdcall
229 newh ()
230 {
231   handle_list *hl;
232   lock_debug ();
233   for (hl = freeh; hl < freeh + NFREEH; hl++)
234     if (hl->name == NULL)
235       goto out;
236
237   /* All used up??? */
238   if ((hl = (handle_list *) malloc (sizeof *hl)) != NULL)
239     {
240       memset (hl, 0, sizeof (*hl));
241       hl->allocated = TRUE;
242     }
243
244 out:
245   unlock_debug ();
246   return hl;
247 }
248
249 /* Add a handle to the linked list of known handles. */
250 void __stdcall
251 add_handle (const char *func, int ln, HANDLE h, const char *name)
252 {
253   handle_list *hl;
254   lock_debug ();
255
256   if ((hl = find_handle (h)))
257     {
258       hl = hl->next;
259       system_printf ("%s:%d - multiple attempts to add handle %s<%p>", func,
260                      ln, name, h);
261       system_printf (" previously allocated by %s:%d(%s<%p>)",
262                      hl->func, hl->ln, hl->name, hl->h);
263       goto out;         /* Already did this once */
264     }
265
266   if ((hl = newh ()) == NULL)
267     {
268       unlock_debug ();
269       system_printf ("couldn't allocate memory for %s(%d): %s(%p)",
270                      func, ln, name, h);
271       return;
272     }
273   hl->h = h;
274   hl->name = name;
275   hl->func = func;
276   hl->ln = ln;
277   hl->next = NULL;
278   endh->next = hl;
279   endh = hl;
280
281 out:
282   unlock_debug ();
283 }
284
285 static void __stdcall
286 delete_handle (handle_list *hl)
287 {
288   handle_list *hnuke = hl->next;
289   hl->next = hl->next->next;
290   if (hnuke->allocated)
291     free (hnuke);
292   else
293     memset (hnuke, 0, sizeof (*hnuke));
294 }
295
296 void
297 debug_fixup_after_fork ()
298 {
299   handle_list *hl;
300   for (hl = &starth; hl->next != NULL; hl = hl->next)
301     if (hl->next->clexec_pid)
302       delete_handle (hl);
303 }
304
305 static bool __stdcall
306 mark_closed (const char *func, int ln, HANDLE h, const char *name, BOOL force)
307 {
308   handle_list *hl;
309   lock_debug ();
310   if ((hl = find_handle (h)) && !force)
311     {
312       hl = hl->next;
313       unlock_debug ();  // race here
314       system_printf ("attempt to close protected handle %s:%d(%s<%p>)",
315                      hl->func, hl->ln, hl->name, hl->h);
316       system_printf (" by %s:%d(%s<%p>)", func, ln, name, h);
317       return FALSE;
318     }
319
320   handle_list *hln;
321   if (hl && (hln = hl->next) && strcmp (name, hln->name))
322     {
323       system_printf ("closing protected handle %s:%d(%s<%p>)",
324                      hln->func, hln->ln, hln->name, hln->h);
325       system_printf (" by %s:%d(%s<%p>)", func, ln, name, h);
326     }
327
328   if (hl)
329     delete_handle (hl);
330
331   unlock_debug ();
332   return TRUE;
333 }
334
335 /* Close a known handle.  Complain if !force and closing a known handle or
336    if the name of the handle being closed does not match the registered name. */
337 BOOL __stdcall
338 close_handle (const char *func, int ln, HANDLE h, const char *name, BOOL force)
339 {
340   BOOL ret;
341   lock_debug ();
342
343   if (!mark_closed (func, ln, h, name, force))
344     return FALSE;
345
346   ret = CloseHandle (h);
347
348   unlock_debug ();
349 #if 0 /* Uncomment to see CloseHandle failures */
350   if (!ret)
351     small_printf ("CloseHandle(%s) failed %s:%d\n", name, func, ln);
352 #endif
353   return ret;
354 }
355
356 /* Add a handle to the linked list of known handles. */
357 int __stdcall
358 __set_errno (const char *func, int ln, int val)
359 {
360   debug_printf ("%s:%d val %d", func, ln, val);
361   return _impure_ptr->_errno = val;
362 }
363 #endif /*DEBUGGING*/