diff options
author | rbcollins <rbcollins> | 2002-01-04 03:56:03 +0000 |
---|---|---|
committer | rbcollins <rbcollins> | 2002-01-04 03:56:03 +0000 |
commit | d686b8f6442a3304135c48c7aaffabafbb7ac772 (patch) | |
tree | 9f3a2af0fc62caec88e52cc44521f85beb39e0e9 /winsup/cygwin/debug.cc | |
parent | 4f314ae7456a93c8003de818664572a744400bef (diff) | |
download | gdb-d686b8f6442a3304135c48c7aaffabafbb7ac772.tar.gz |
Merged changes from HEAD
Diffstat (limited to 'winsup/cygwin/debug.cc')
-rw-r--r-- | winsup/cygwin/debug.cc | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/winsup/cygwin/debug.cc b/winsup/cygwin/debug.cc new file mode 100644 index 00000000000..76cce92ff82 --- /dev/null +++ b/winsup/cygwin/debug.cc @@ -0,0 +1,363 @@ +/* debug.cc + + Copyright 1998, 1999, 2000, 2001 Red Hat, Inc. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" +#include "exceptions.h" +#include "sync.h" +#include "sigproc.h" +#include "pinfo.h" +#include "perthread.h" +#include "perprocess.h" +#include "security.h" +#include "cygerrno.h" + +#undef CloseHandle + +static muto NO_COPY *threadname_lock = NULL; +#define lock_threadname() \ + do {if (threadname_lock) threadname_lock->acquire (INFINITE); } while (0) + +#define unlock_threadname() \ + do {if (threadname_lock) threadname_lock->release (); } while (0) + +typedef struct + { + DWORD id; + const char *name; + } thread_info; + +static NO_COPY thread_info threads[32] = {{0, NULL}}; // increase as necessary +#define NTHREADS (sizeof (threads) / sizeof (threads[0])) + +void +threadname_init () +{ + threadname_lock = new_muto (FALSE, "threadname_lock"); +} + +void __stdcall +regthread (const char *name, DWORD tid) +{ + lock_threadname (); + for (DWORD i = 0; i < NTHREADS; i++) + if (threads[i].name == NULL || strcmp (threads[i].name, name) == 0 || + threads[i].id == tid) + { + threads[i].name = name; + threads[i].id = tid; + break; + } + unlock_threadname (); +} + +int __stdcall +iscygthread () +{ + DWORD tid = GetCurrentThreadId (); + if (tid != mainthread.id) + for (DWORD i = 0; i < NTHREADS && threads[i].name != NULL; i++) + if (threads[i].id == tid) + return 1; + return 0; +} + +struct thread_start + { + LONG notavail; + LPTHREAD_START_ROUTINE func; + VOID *arg; + }; + +/* A place to store arguments to thread_stub since they can't be + stored on the stack. An available element is !notavail. */ +thread_start NO_COPY start_buf[NTHREADS] = {{0, NULL,NULL}}; + +/* Initial stub called by makethread. Performs initial per-thread + initialization. */ +static DWORD WINAPI +thread_stub (VOID *arg) +{ + DECLARE_TLS_STORAGE; + LPTHREAD_START_ROUTINE threadfunc = ((thread_start *) arg)->func; + VOID *threadarg = ((thread_start *) arg)->arg; + + exception_list except_entry; + + /* Give up our slot in the start_buf array */ + (void) InterlockedExchange (&((thread_start *) arg)->notavail, 0); + + /* Initialize this thread's ability to respond to things like + SIGSEGV or SIGFPE. */ + init_exceptions (&except_entry); + + ExitThread (threadfunc (threadarg)); +} + +/* Wrapper for CreateThread. Registers the thread name/id and ensures that + cygwin threads are properly initialized. */ +HANDLE __stdcall +makethread (LPTHREAD_START_ROUTINE start, LPVOID param, DWORD flags, + const char *name) +{ + DWORD tid; + HANDLE h; + thread_start *info; /* Various information needed by the newly created thread */ + + for (;;) + { + /* Search the start_buf array for an empty slot to use */ + for (info = start_buf; info < start_buf + NTHREADS; info++) + if (!InterlockedExchange (&info->notavail, 1)) + goto out; + + /* Should never hit here, but be defensive anyway. */ + Sleep (0); + } + +out: + info->func = start; /* Real function to start */ + info->arg = param; /* The single parameter to the thread */ + + if ((h = CreateThread (&sec_none_nih, 0, thread_stub, (VOID *) info, flags, + &tid))) + regthread (name, tid); /* Register for debugging output. */ + + return h; +} + +/* Return the symbolic name of the current thread for debugging. + */ +const char * __stdcall +threadname (DWORD tid, int lockit) +{ + const char *res = NULL; + if (!tid) + tid = GetCurrentThreadId (); + + if (lockit) + lock_threadname (); + for (DWORD i = 0; i < NTHREADS && threads[i].name != NULL; i++) + if (threads[i].id == tid) + { + res = threads[i].name; + break; + } + if (lockit) + unlock_threadname (); + + if (!res) + { + static char buf[30] NO_COPY = {0}; + __small_sprintf (buf, "unknown (%p)", tid); + res = buf; + } + + return res; +} + +#ifdef DEBUGGING +/* Here lies extra debugging routines which help track down internal + Cygwin problems when compiled with -DDEBUGGING . */ +#include <stdlib.h> + +typedef struct _h + { + BOOL allocated; + HANDLE h; + const char *name; + const char *func; + int ln; + DWORD clexec_pid; + struct _h *next; + } handle_list; + +static NO_COPY handle_list starth = {0, NULL, NULL, NULL, 0, 0, NULL}; +static NO_COPY handle_list *endh = NULL; + +static handle_list NO_COPY freeh[1000] = {{0, NULL, NULL, NULL, 0, 0, NULL}}; +#define NFREEH (sizeof (freeh) / sizeof (freeh[0])) + +static muto NO_COPY *debug_lock = NULL; + +#define lock_debug() \ + do {if (debug_lock) debug_lock->acquire (INFINITE); } while (0) + +#define unlock_debug() \ + do {if (debug_lock) debug_lock->release (); } while (0) + +static bool __stdcall mark_closed (const char *, int, HANDLE, const char *, BOOL); + +void +debug_init () +{ + debug_lock = new_muto (FALSE, "debug_lock"); +} + +/* Find a registered handle in the linked list of handles. */ +static handle_list * __stdcall +find_handle (HANDLE h) +{ + handle_list *hl; + for (hl = &starth; hl->next != NULL; hl = hl->next) + if (hl->next->h == h) + goto out; + endh = hl; + hl = NULL; + +out: + return hl; +} + +void +setclexec_pid (HANDLE oh, HANDLE nh, bool setit) +{ + handle_list *hl = find_handle (oh); + if (hl) + { + hl->clexec_pid = setit ? GetCurrentProcessId () : 0; + hl->h = nh; + } +} + +/* Create a new handle record */ +static handle_list * __stdcall +newh () +{ + handle_list *hl; + lock_debug (); + for (hl = freeh; hl < freeh + NFREEH; hl++) + if (hl->name == NULL) + goto out; + + /* All used up??? */ + if ((hl = (handle_list *) malloc (sizeof *hl)) != NULL) + { + memset (hl, 0, sizeof (*hl)); + hl->allocated = TRUE; + } + +out: + unlock_debug (); + return hl; +} + +/* Add a handle to the linked list of known handles. */ +void __stdcall +add_handle (const char *func, int ln, HANDLE h, const char *name) +{ + handle_list *hl; + lock_debug (); + + if ((hl = find_handle (h))) + { + hl = hl->next; + system_printf ("%s:%d - multiple attempts to add handle %s<%p>", func, + ln, name, h); + system_printf (" previously allocated by %s:%d(%s<%p>)", + hl->func, hl->ln, hl->name, hl->h); + goto out; /* Already did this once */ + } + + if ((hl = newh ()) == NULL) + { + unlock_debug (); + system_printf ("couldn't allocate memory for %s(%d): %s(%p)", + func, ln, name, h); + return; + } + hl->h = h; + hl->name = name; + hl->func = func; + hl->ln = ln; + hl->next = NULL; + endh->next = hl; + endh = hl; + +out: + unlock_debug (); +} + +static void __stdcall +delete_handle (handle_list *hl) +{ + handle_list *hnuke = hl->next; + hl->next = hl->next->next; + if (hnuke->allocated) + free (hnuke); + else + memset (hnuke, 0, sizeof (*hnuke)); +} + +void +debug_fixup_after_fork () +{ + handle_list *hl; + for (hl = &starth; hl->next != NULL; hl = hl->next) + if (hl->next->clexec_pid) + delete_handle (hl); +} + +static bool __stdcall +mark_closed (const char *func, int ln, HANDLE h, const char *name, BOOL force) +{ + handle_list *hl; + lock_debug (); + if ((hl = find_handle (h)) && !force) + { + hl = hl->next; + unlock_debug (); // race here + system_printf ("attempt to close protected handle %s:%d(%s<%p>)", + hl->func, hl->ln, hl->name, hl->h); + system_printf (" by %s:%d(%s<%p>)", func, ln, name, h); + return FALSE; + } + + handle_list *hln; + if (hl && (hln = hl->next) && strcmp (name, hln->name)) + { + system_printf ("closing protected handle %s:%d(%s<%p>)", + hln->func, hln->ln, hln->name, hln->h); + system_printf (" by %s:%d(%s<%p>)", func, ln, name, h); + } + + if (hl) + delete_handle (hl); + + unlock_debug (); + return TRUE; +} + +/* Close a known handle. Complain if !force and closing a known handle or + if the name of the handle being closed does not match the registered name. */ +BOOL __stdcall +close_handle (const char *func, int ln, HANDLE h, const char *name, BOOL force) +{ + BOOL ret; + lock_debug (); + + if (!mark_closed (func, ln, h, name, force)) + return FALSE; + + ret = CloseHandle (h); + + unlock_debug (); +#if 0 /* Uncomment to see CloseHandle failures */ + if (!ret) + small_printf ("CloseHandle(%s) failed %s:%d\n", name, func, ln); +#endif + return ret; +} + +/* Add a handle to the linked list of known handles. */ +int __stdcall +__set_errno (const char *func, int ln, int val) +{ + debug_printf ("%s:%d val %d", func, ln, val); + return _impure_ptr->_errno = val; +} +#endif /*DEBUGGING*/ |