summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorscottc <scottc>2002-08-06 07:14:58 +0000
committerscottc <scottc>2002-08-06 07:14:58 +0000
commit19203fb54c030d04124df3cb2cd82904c68758f3 (patch)
treed0ef2dc406c4fc86aa203de4925cd81833004383
parent5fd6104d132c65614f004d8000876c1d8cba1bda (diff)
downloadgdb-19203fb54c030d04124df3cb2cd82904c68758f3.tar.gz
Merged changes from HEAD
-rw-r--r--winsup/cygwin/ChangeLog51
-rw-r--r--winsup/cygwin/cygthread.cc61
-rw-r--r--winsup/cygwin/cygthread.h2
-rw-r--r--winsup/cygwin/debug.cc21
-rw-r--r--winsup/cygwin/debug.h3
-rw-r--r--winsup/cygwin/fhandler_tty.cc6
-rw-r--r--winsup/cygwin/grp.cc4
-rw-r--r--winsup/cygwin/how-signals-work.txt132
-rw-r--r--winsup/cygwin/security.cc7
-rw-r--r--winsup/cygwin/sigproc.cc7
-rw-r--r--winsup/cygwin/spawn.cc1
-rw-r--r--winsup/cygwin/syscalls.cc5
12 files changed, 256 insertions, 44 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 216d83b9b6d..20f4c1262b0 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,54 @@
+2002-08-06 Christopher Faylor <cgf@redhat.com>
+
+ * spawn.cc (spawn_guts): Don't set mount_h here.
+ * sigproc.cc (init_child_info): Set it here instead.
+ * shared.cc (cygwin_mount_h): Make NO_COPY.
+
+2002-08-06 Christopher Faylor <cgf@redhat.com>
+
+ * cygthread.cc (cygthread::stub): Accept flag to pass info structure to
+ thread function.
+ (cygthread::operator new): Add defense debugging output.
+ (cygthread::cygthread): Add debugging output. Set name after thread
+ has been awakened to avoid a race.
+ (cygthread::exit_thread): Use handle operator rather than using ev
+ directly.
+ (cygthread::exit_thread): Reorganize to provide debugging. Set __name
+ to NULL.
+ * cygthread.h (cygself): Define.
+ * fhandler_tty.cc (fhandler_tty_master::init): Use cygself as argument
+ so that invoked thread can access its own info.
+ (process_output): Derive cygthread info of thread from thread argument.
+ * sigproc.cc (sigproc_init): Use cygself as argument so that invoked
+ thread can access its own info.
+ (wait_sig): Derive cygthread info of thread from thread argument.
+
+2002-08-06 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * debug.h (handle_list::allocated): Remove field.
+ * debug.cc (newh): Don't malloc extra entries.
+ (add_handle): Downgrade strace message level.
+ (delete_handle): Remove case for `allocated' entries.
+
+2002-08-05 Christopher Faylor <cgf@redhat.com>
+
+ * cygthread.cc (cygthread::stub): Change event creation to manual
+ reset. Set __name after calling SetEvent to prevent races.
+ (cygthread::detach): Always reset event here to prevent races.
+
+2002-08-03 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * debug.h (WaitForMultipleObjects): Correct typo.
+
+2002-08-01 Pierre Humblet <Pierre.Humblet@ieee.org>
+
+ * security.cc (verify_token): Do not reject a token just because
+ the supplementary group list is missing Everyone or a groupsid
+ equal to usersid, or because the primary group is not in the token,
+ as long as it is equal to the usersid.
+ * syscalls.cc (seteuid32): Use common code for all successful returns.
+ * grp.cc (getgroups32): Never includes Everyone in the output.
+
2002-08-01 Christopher Faylor <cgf@redhat.com>
* cygthread.cc (cygthread::exit_thread): Define new method.
diff --git a/winsup/cygwin/cygthread.cc b/winsup/cygwin/cygthread.cc
index a4f32472de1..00eeb25d07a 100644
--- a/winsup/cygwin/cygthread.cc
+++ b/winsup/cygwin/cygthread.cc
@@ -7,10 +7,10 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
+#include <windows.h>
#include "exceptions.h"
#include "security.h"
#include "cygthread.h"
-#include <windows.h>
#undef CloseHandle
@@ -21,8 +21,9 @@ static HANDLE NO_COPY hthreads[NTHREADS];
DWORD NO_COPY cygthread::main_thread_id;
-/* Initial stub called by makethread. Performs initial per-thread
- initialization. */
+/* Initial stub called by cygthread constructor. Performs initial
+ per-thread initialization and loops waiting for new thread functions
+ to execute. */
DWORD WINAPI
cygthread::stub (VOID *arg)
{
@@ -34,21 +35,27 @@ cygthread::stub (VOID *arg)
init_exceptions (&except_entry);
cygthread *info = (cygthread *) arg;
- info->ev = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
+ info->ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
while (1)
{
if (!info->func)
ExitThread (0);
- /* Cygwin threads should not call ExitThread */
- info->func (info->arg);
+ /* Cygwin threads should not call ExitThread directly */
+ info->func (info->arg == cygself ? info : info->arg);
+ /* ...so the above should always return */
- info->__name = NULL;
+#ifdef DEBUGGING
+ info->func = NULL; // catch erroneous activation
+#endif
SetEvent (info->ev);
+ info->__name = NULL;
SuspendThread (info->h);
}
}
+/* This function runs in a secondary thread and starts up a bunch of
+ other suspended threads for use in the cygthread pool. */
DWORD WINAPI
cygthread::runner (VOID *arg)
{
@@ -59,6 +66,7 @@ cygthread::runner (VOID *arg)
return 0;
}
+/* Start things going. Called from dll_crt0_1. */
void
cygthread::init ()
{
@@ -86,7 +94,7 @@ void * cygthread::operator
new (size_t)
{
DWORD id;
- cygthread *info; /* Various information needed by the newly created thread */
+ cygthread *info;
for (;;)
{
@@ -95,6 +103,10 @@ new (size_t)
if ((id = (DWORD) InterlockedExchange ((LPLONG) &info->avail, 0)))
{
info->id = id;
+#ifdef DEBUGGING
+ if (info->__name)
+ api_fatal ("name not NULL? id %p, i %d", id, info - threads);
+#endif
return info;
}
@@ -104,10 +116,18 @@ new (size_t)
}
cygthread::cygthread (LPTHREAD_START_ROUTINE start, LPVOID param,
- const char *name): __name (name), func (start), arg (param)
+ const char *name): func (start), arg (param)
{
+#ifdef DEBUGGGING
+ if (!__name)
+ api_fatal ("name should never be NULL");
+#endif
+ thread_printf ("name %s, id %p", name, id);
while (ResumeThread (h) == 0)
Sleep (0);
+ __name = name; /* Need to set after thread has woken up to
+ ensure that it won't be cleared by exiting
+ thread. */
}
/* Return the symbolic name of the current thread for debugging.
@@ -147,25 +167,40 @@ HANDLE ()
return ev;
}
+/* Should only be called when the process is exiting since it
+ leaves an open thread slot. */
void
cygthread::exit_thread ()
{
- SetEvent (ev);
+ SetEvent (*this);
ExitThread (0);
}
+/* Detach the cygthread from the current thread. Note that the
+ theory is that cygthread's are only associated with one thread.
+ So, there should be no problems with multiple threads doing waits
+ on the one cygthread. */
void
cygthread::detach ()
{
- if (!avail)
+ if (avail)
+ system_printf ("called detach on available thread %d?", avail);
+ else
{
DWORD avail = id;
- if (__name)
+ /* Checking for __name here is just a minor optimization to avoid
+ an OS call. */
+ if (!__name)
+ thread_printf ("thread id %p returned. No need to wait.", id);
+ else
{
DWORD res = WaitForSingleObject (*this, INFINITE);
- debug_printf ("WFSO returns %d", res);
+ thread_printf ("WFSO returns %d, id %p", res, id);
}
+ ResetEvent (*this);
id = 0;
+ __name = NULL;
+ /* Mark the thread as available by setting avail to non-zero */
(void) InterlockedExchange ((LPLONG) &this->avail, avail);
}
}
diff --git a/winsup/cygwin/cygthread.h b/winsup/cygwin/cygthread.h
index b4f6cbe2fbd..7f5a594556f 100644
--- a/winsup/cygwin/cygthread.h
+++ b/winsup/cygwin/cygthread.h
@@ -29,3 +29,5 @@ class cygthread
void * operator new (size_t);
void exit_thread ();
};
+
+#define cygself NULL
diff --git a/winsup/cygwin/debug.cc b/winsup/cygwin/debug.cc
index 280cbb44d16..418f35510b8 100644
--- a/winsup/cygwin/debug.cc
+++ b/winsup/cygwin/debug.cc
@@ -101,17 +101,9 @@ newh ()
for (hl = cygheap->debug.freeh; hl < cygheap->debug.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;
- }
+ return hl;
-out:
- return hl;
+ return NULL;
}
/* Add a handle to the linked list of known handles. */
@@ -136,8 +128,8 @@ add_handle (const char *func, int ln, HANDLE h, const char *name, bool inh)
if ((hl = newh ()) == NULL)
{
here.unlock ();
- system_printf ("couldn't allocate memory for %s(%d): %s(%p)",
- func, ln, name, h);
+ debug_printf ("couldn't allocate memory for %s(%d): %s(%p)",
+ func, ln, name, h);
return;
}
hl->h = h;
@@ -160,10 +152,7 @@ delete_handle (handle_list *hl)
handle_list *hnuke = hl->next;
debug_printf ("nuking handle '%s'", hnuke->name);
hl->next = hl->next->next;
- if (hnuke->allocated)
- free (hnuke);
- else
- memset (hnuke, 0, sizeof (*hnuke));
+ memset (hnuke, 0, sizeof (*hnuke));
}
void
diff --git a/winsup/cygwin/debug.h b/winsup/cygwin/debug.h
index 90b202543c8..09a74e9170a 100644
--- a/winsup/cygwin/debug.h
+++ b/winsup/cygwin/debug.h
@@ -23,7 +23,7 @@ DWORD __stdcall WFMO (DWORD, CONST HANDLE *, BOOL, DWORD) __attribute__ ((regpar
}
#define WaitForSingleObject WFSO
-#define WaitForMultipleObject WFMO
+#define WaitForMultipleObjects WFMO
#if !defined(_DEBUG_H_)
#define _DEBUG_H_
@@ -81,7 +81,6 @@ extern int pinger;
struct handle_list
{
- BOOL allocated;
HANDLE h;
const char *name;
const char *func;
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 9a32709fcd4..b073c940cad 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -68,7 +68,7 @@ fhandler_tty_master::init (int ntty)
h = new cygthread (process_ioctl, NULL, "ttyioctl");
SetThreadPriority (*h, THREAD_PRIORITY_HIGHEST);
- output_thread = new cygthread (process_output, NULL, "ttyout");
+ output_thread = new cygthread (process_output, cygself, "ttyout");
SetThreadPriority (*output_thread, THREAD_PRIORITY_HIGHEST);
return 0;
@@ -368,7 +368,7 @@ out:
}
static DWORD WINAPI
-process_output (void *)
+process_output (void *self)
{
char buf[OUT_BUFFER_SIZE*2];
@@ -379,7 +379,7 @@ process_output (void *)
{
if (n < 0)
termios_printf ("ReadFile %E");
- cygthread *t = tty_master->output_thread;
+ cygthread *t = (cygthread *) self;
tty_master->output_thread = NULL;
t->exit_thread ();
}
diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc
index c26a6b1c752..5bfb50e1471 100644
--- a/winsup/cygwin/grp.cc
+++ b/winsup/cygwin/grp.cc
@@ -365,7 +365,8 @@ getgroups32 (int gidsetsize, __gid32_t *grouplist, __gid32_t gid,
for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
if (sid.getfromgr (gr))
for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
- if (sid == groups->Groups[pg].Sid)
+ if (sid == groups->Groups[pg].Sid &&
+ sid != well_known_world_sid)
{
if (cnt < gidsetsize)
grouplist[cnt] = gr->gr_gid;
@@ -516,5 +517,4 @@ setgroups (int ngroups, const __gid16_t *grouplist)
grouplist32[i] = grouplist[i];
}
return setgroups32 (ngroups, grouplist32);
-
}
diff --git a/winsup/cygwin/how-signals-work.txt b/winsup/cygwin/how-signals-work.txt
new file mode 100644
index 00000000000..3b36badc826
--- /dev/null
+++ b/winsup/cygwin/how-signals-work.txt
@@ -0,0 +1,132 @@
+Copyright 2001 Red Hat Inc., Christopher Faylor
+
+How do signals work?
+
+On process startup, cygwin starts a secondary thread that deals with signals.
+This thread contains a loop which blocks waiting for one of three events:
+
+1) sigcatch_main - a semaphore which, when incremented, indicates that a
+ signal may be available for the main thread. The caller waits for the
+ signal to be delivered before returning.
+
+2) sigcatch_nonmain - a semaphore which , when incremented, indicates that
+ a signal is available for a non-main thread (currently this is not truly
+ implemented). The caller waits for the signal to be delivered before
+ returning.
+
+3) sigcatch_nosync - a semaphore which, when incremented, indicates that
+ a signal may be available for the main thread. The caller does not wait
+ for the delivery of the signal before returning.
+
+So, the signal handler blocks waiting for one of these three semaphores.
+
+If one of these is activated, then the the signal handler inspects an
+array of integers looking for a non-zero value. The array corresponds
+to the normal UNIX signals + two extra locations for internal usage.
+This array is located in the 'sigtodo' array in the procinfo class.
+
+The signal thread uses the InterlockedDecrement function to atomically
+inspect elements of the array. If one one of the elements of the array
+is non-zero, then cygwin checks to see if the user has blocked the
+signal by inspecting the process signal mask. If the signal is blocked,
+then the current array element is reincremented and the next element is
+checked.
+
+If the signal is not blocked, then the function "sig_handle" is called
+with the signal number as an argument. This is a fairly straightforward
+function. It first checks to see if the signal is special in any way.
+
+A special signal is something like SIGKILL or SIGSTOP. The user has no
+control over how those signals affect a UNIX process. If a SIGKILL is
+received then sig_handle calls exit_sig to exit the process. If SIGSTOP
+is called then sig_handle calls the regular signal dispatch function
+with a special function argument "sig_handle_tty_stop". The signal
+dispatch function is described below.
+
+An uncaught signal like SIGTERM or SIGHUP will cause the process to exit
+with the standard UNIX exit values. Uncaught signals like SIGUSR1 are
+ignored, as on UNIX.
+
+If the signal has an associated signal handler, then the setup_handler
+function is eventually called. It is passed the signal, the address of
+the handler, and a standard UNIX sigaction structure. The meat of
+signal processing is in setup_handler.
+
+setup_handler has a "simple" task. It tries to stop the appropriate
+thread and redirect its execution to the signal handler function.
+Currently, the "appropriate thread" is only the main thread. Someday
+we'll have to change this to allow cygwin to interrupt other user
+threads.
+
+To accomplish its task, setup_handler first inspects the static sigsave
+structure. This structure contains information on any not-yet-handled
+signals that may have been set up by a previous call to setup_handler
+but not yet dispatched in the main thread. If the sigsave structure
+seems to be "active", then a "pending" flag is set (see below) and the
+function returns. Otherwise processing continues.
+
+After determining that sigsave is available, setup_handler will take one
+of two routes, depending on whether the main thread is executing in the
+cygwin DLL or is currently in "user" code. We'll discuss the cygwin DLL
+case first.
+
+If sigsave seems to be available, then the frame information for the
+main thread is inspected. This information is set by any cygwin
+function that is known to block (such as _read()), usually by calling
+'sigframe thisframe (mainthread)' in the cygwin function. This call
+sets up information about the current stack frame of an executing cygwin
+process. Any function which uses 'sigframe thisframe' should be signal
+aware. It should detect when a signal has arrived and return
+immediately. This method is also used throughout the DLL to ensure
+accurate frame info for the executing function. So, you'll see it
+sprinkled liberally throughout the DLL, usually at places where
+empirical tests have indicated problems finding this address via the
+brute force method stack walking method employed in setup_handler.
+
+So, if mainframe is active, that means that we have good information
+about the state of the main thread. Cygwin uses the stack frame info
+from this structure to insert a call to the assembly language function
+'sigdelayed' in place of the main thread's normal return address. So,
+when a call to (e.g.) _read returns after detecting a signal, it does
+not return to its caller. Rather, it returns to sigdelayed.
+
+The sigdelayed function saves a lot of state on the stack and sets the
+signal mask as appropriate for POSIX. It uses information from the
+sigsave structure which has been filled in by interrupt_on_return, as
+called by setup_handler. sigdelayed pushes a "call" to the function
+"sigreturn" on the stack. This will be the return address seen by the
+signal handler. After setting up the return value, modifying the signal
+mask, and saving other information on the stack, sigreturn clears the
+sigsave structure (so that setup_handler can use it) and jumps to the
+signal handler function. And, so a UNIX signal handler function is
+emulated.
+
+The signal handler function operates as normal for UNIX but, upon
+return, it does not go directly back to the return address of the
+original cygwin function. Instead it returns to the previously
+mentioned 'sigreturn' assembly language function.
+
+sigreturn resets the process mask to its state prior to calling the
+signal handler. It checks to see if any new signals have come in and
+calls the handler for them now, ensuring that the order of signal
+arrival is more or less maintained. It checks to see if a cygwin
+routine has set a special "restore this errno on returning from a
+signal" value and sets errno to this, if so. Finally, it restores all
+of the register values that were in effect when sigdelayed was called.
+
+Ok, you thought I had forgotten about the 'pending' stuff didn't you?
+Well, if you can rewind up to the discussion of sig_handle, we'll return
+to the situation where sigsave was currently active. In this case,
+setup_handler will set a "pending" flag, will reincrement the appropriate
+element of the above signal array, and will return 0 to indicate that
+the interrupt did not occur. Otherwise setup_handler returns 1.
+
+For pending signals, the theory is that the signal handler thread will
+be forced to be rerun by having some strategic cygwin function call
+sig_send with a __SIGFLUSH "argument" to it. This causes the signal
+handler to rescan the signal array looking for pending signals.
+
+This leads us to the sig_send function. This is the "client side" part
+of the signal manipulation process. sig_send is the low-level function
+called by a high level process like kill(). You would use sig_send
+to send a __SIGFLUSH to the signal thread.
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index d12e3335954..f22c7dc8f0a 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -779,13 +779,16 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL *pintern)
saw[pos] = TRUE;
else if (groups.pgsid == gsid)
sawpg = TRUE;
- else
+ else if (gsid != well_known_world_sid &&
+ gsid != usersid)
goto done;
}
for (int gidx = 0; gidx < groups.sgsids.count; gidx++)
if (!saw[gidx])
goto done;
- if (sawpg || groups.sgsids.contains (groups.pgsid))
+ if (sawpg ||
+ groups.sgsids.contains (groups.pgsid) ||
+ groups.pgsid == usersid)
ret = TRUE;
}
done:
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index 49947840ee0..4914e6a24e3 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -571,7 +571,7 @@ sigproc_init ()
signal_arrived = CreateEvent(&sec_none_nih, TRUE, FALSE, NULL);
ProtectHandle (signal_arrived);
- hwait_sig = new cygthread (wait_sig, NULL, "sig");
+ hwait_sig = new cygthread (wait_sig, cygself, "sig");
/* sync_proc_subproc is used by proc_subproc. It serialises
* access to the children and zombie arrays.
@@ -828,6 +828,7 @@ init_child_info (DWORD chtype, child_info *ch, pid_t pid, HANDLE subproc_ready)
ch->subproc_ready = subproc_ready;
ch->pppid_handle = myself->ppid_handle;
ch->fhandler_union_cb = sizeof (fhandler_union);
+ ch->mount_h = cygwin_mount_h;
}
/* Check the state of all of our children to see if any are stopped or
@@ -1030,10 +1031,10 @@ stopped_or_terminated (waitq *parent_w, _pinfo *child)
* has been handled, as per POSIX.
*/
static DWORD WINAPI
-wait_sig (VOID *)
+wait_sig (VOID *self)
{
/* Initialization */
- (void) SetThreadPriority (*hwait_sig, WAIT_SIG_PRIORITY);
+ (void) SetThreadPriority (*((cygthread *) self), WAIT_SIG_PRIORITY);
/* sigcatch_nosync - semaphore incremented by sig_dispatch_pending and
* by foreign processes to force an examination of
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 7454adc58b4..602c0af6919 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -608,7 +608,6 @@ spawn_guts (const char * prog_arg, const char *const *argv,
char sa_buf[1024];
cygbench ("spawn-guts");
- ciresrv.mount_h = cygwin_mount_h;
if (!cygheap->user.issetuid ())
{
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 4792744e026..31eed42b2e8 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -2004,7 +2004,7 @@ seteuid32 (__uid32_t uid)
else
{
CloseHandle (ptok);
- return 0; /* No change */
+ goto success; /* No change */
}
}
@@ -2025,7 +2025,7 @@ seteuid32 (__uid32_t uid)
CloseHandle (ptok);
if (!ImpersonateLoggedOnUser (cygheap->user.token))
system_printf ("Impersonating in seteuid failed: %E");
- return 0; /* No change */
+ goto success; /* No change */
}
}
}
@@ -2097,6 +2097,7 @@ seteuid32 (__uid32_t uid)
CloseHandle (sav_token);
cygheap->user.set_name (pw_new->pw_name);
cygheap->user.set_sid (usersid);
+success:
myself->uid = uid;
groups.ischanged = FALSE;
return 0;