3 Copyright 1998, 1999, 2000, 2001 Red Hat, Inc.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 #include "exceptions.h"
14 #include "perthread.h"
15 #include "perprocess.h"
21 static muto NO_COPY *threadname_lock = NULL;
22 #define lock_threadname() \
23 do {if (threadname_lock) threadname_lock->acquire (INFINITE); } while (0)
25 #define unlock_threadname() \
26 do {if (threadname_lock) threadname_lock->release (); } while (0)
34 static NO_COPY thread_info threads[32] = {{0, NULL}}; // increase as necessary
35 #define NTHREADS (sizeof (threads) / sizeof (threads[0]))
40 threadname_lock = new_muto (FALSE, "threadname_lock");
44 regthread (const char *name, DWORD tid)
47 for (DWORD i = 0; i < NTHREADS; i++)
48 if (threads[i].name == NULL || strcmp (threads[i].name, name) == 0 ||
51 threads[i].name = name;
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)
72 LPTHREAD_START_ROUTINE func;
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}};
80 /* Initial stub called by makethread. Performs initial per-thread
83 thread_stub (VOID *arg)
86 LPTHREAD_START_ROUTINE threadfunc = ((thread_start *) arg)->func;
87 VOID *threadarg = ((thread_start *) arg)->arg;
89 exception_list except_entry;
91 /* Give up our slot in the start_buf array */
92 (void) InterlockedExchange (&((thread_start *) arg)->notavail, 0);
94 /* Initialize this thread's ability to respond to things like
96 init_exceptions (&except_entry);
98 ExitThread (threadfunc (threadarg));
101 /* Wrapper for CreateThread. Registers the thread name/id and ensures that
102 cygwin threads are properly initialized. */
104 makethread (LPTHREAD_START_ROUTINE start, LPVOID param, DWORD flags,
109 thread_start *info; /* Various information needed by the newly created thread */
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))
118 /* Should never hit here, but be defensive anyway. */
123 info->func = start; /* Real function to start */
124 info->arg = param; /* The single parameter to the thread */
126 if ((h = CreateThread (&sec_none_nih, 0, thread_stub, (VOID *) info, flags,
128 regthread (name, tid); /* Register for debugging output. */
133 /* Return the symbolic name of the current thread for debugging.
135 const char * __stdcall
136 threadname (DWORD tid, int lockit)
138 const char *res = NULL;
140 tid = GetCurrentThreadId ();
144 for (DWORD i = 0; i < NTHREADS && threads[i].name != NULL; i++)
145 if (threads[i].id == tid)
147 res = threads[i].name;
151 unlock_threadname ();
155 static char buf[30] NO_COPY = {0};
156 __small_sprintf (buf, "unknown (%p)", tid);
164 /* Here lies extra debugging routines which help track down internal
165 Cygwin problems when compiled with -DDEBUGGING . */
179 static NO_COPY handle_list starth = {0, NULL, NULL, NULL, 0, 0, NULL};
180 static NO_COPY handle_list *endh = NULL;
182 static handle_list NO_COPY freeh[1000] = {{0, NULL, NULL, NULL, 0, 0, NULL}};
183 #define NFREEH (sizeof (freeh) / sizeof (freeh[0]))
185 static muto NO_COPY *debug_lock = NULL;
187 #define lock_debug() \
188 do {if (debug_lock) debug_lock->acquire (INFINITE); } while (0)
190 #define unlock_debug() \
191 do {if (debug_lock) debug_lock->release (); } while (0)
193 static bool __stdcall mark_closed (const char *, int, HANDLE, const char *, BOOL);
198 debug_lock = new_muto (FALSE, "debug_lock");
201 /* Find a registered handle in the linked list of handles. */
202 static handle_list * __stdcall
203 find_handle (HANDLE h)
206 for (hl = &starth; hl->next != NULL; hl = hl->next)
207 if (hl->next->h == h)
217 setclexec_pid (HANDLE oh, HANDLE nh, bool setit)
219 handle_list *hl = find_handle (oh);
222 hl->clexec_pid = setit ? GetCurrentProcessId () : 0;
227 /* Create a new handle record */
228 static handle_list * __stdcall
233 for (hl = freeh; hl < freeh + NFREEH; hl++)
234 if (hl->name == NULL)
238 if ((hl = (handle_list *) malloc (sizeof *hl)) != NULL)
240 memset (hl, 0, sizeof (*hl));
241 hl->allocated = TRUE;
249 /* Add a handle to the linked list of known handles. */
251 add_handle (const char *func, int ln, HANDLE h, const char *name)
256 if ((hl = find_handle (h)))
259 system_printf ("%s:%d - multiple attempts to add handle %s<%p>", func,
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 */
266 if ((hl = newh ()) == NULL)
269 system_printf ("couldn't allocate memory for %s(%d): %s(%p)",
285 static void __stdcall
286 delete_handle (handle_list *hl)
288 handle_list *hnuke = hl->next;
289 hl->next = hl->next->next;
290 if (hnuke->allocated)
293 memset (hnuke, 0, sizeof (*hnuke));
297 debug_fixup_after_fork ()
300 for (hl = &starth; hl->next != NULL; hl = hl->next)
301 if (hl->next->clexec_pid)
305 static bool __stdcall
306 mark_closed (const char *func, int ln, HANDLE h, const char *name, BOOL force)
310 if ((hl = find_handle (h)) && !force)
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);
321 if (hl && (hln = hl->next) && strcmp (name, hln->name))
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);
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. */
338 close_handle (const char *func, int ln, HANDLE h, const char *name, BOOL force)
343 if (!mark_closed (func, ln, h, name, force))
346 ret = CloseHandle (h);
349 #if 0 /* Uncomment to see CloseHandle failures */
351 small_printf ("CloseHandle(%s) failed %s:%d\n", name, func, ln);
356 /* Add a handle to the linked list of known handles. */
358 __set_errno (const char *func, int ln, int val)
360 debug_printf ("%s:%d val %d", func, ln, val);
361 return _impure_ptr->_errno = val;