* bsd_helper.cc (ipcexit_hookthread): Fix whitespace and handle leak.

* bsd_mutex.cc: Include stdlib.h, sys/msg.h and sys/sem.h.
	(mtx_init): Initialize lock counter to 0.
	(_mtx_lock): Increment and log mutex lock counter.
	(mtx_owned): Add winpid argument. Return true only if mutex is
	actually owned by process winpid.
	(_mtx_assert): Add winpid argument accordingly.
	(_mtx_unlock): Log owner and lock count.
	(MSLEEP_MUTEX): Remove.
	(MSLEEP_SEM): Ditto.
	(MSLEEP_EVENT): Ditto.
	(msleep_event_name): Ditto.
	(msleep_cs): New global critical section.
	(msleep_cnt): New global variable indicating msleep record usage.
	(msleep_max_cnt): New global variable indicating msleep record size.
	(msleep_arr): New global pointer to msleep records.
	(msleep_init): Initialize msleep_cs. Allocate msleep_arr array.
	(_msleep): Rewrite using new msleep_cs/msleep_arr based thread
	synchronization. Don't be shy with debug output.
	(wakeup): Rewrite using new msleep_cs/msleep_arr based thread
	synchronization.
	* bsd_mutex.h (struct mtx): Add lock counter for better debugging.
	(mtx_owned): Declare with winpid argument.
	(_mtx_assert): Ditto.
	(mtx_assert): Define with winpid argument.
	* cygserver.cc (version): Remove.
	(SERVER_VERSION): New define, decoupling server version information
	from source code control system.
	(print_version): Simplify printing server version.
	* process.cc (process::process): Fix wrong bracketing (and handle leak).
	(process::~process): Only try to close _signal_arrived if valid.
	* sysv_sem.cc: Include sys/smallprint.h.
	(semundo_clear): Define with additional struct thread pointer argument.
	Accomodate throughout.
	(SEMUNDO_LOCKASSERT): Define with winpid argument. Accomodate
	throughout.
	(struct sem_undo): Define un_proc as pid_t on Cygwin. Accomodate
	throughout.
	(seminit): Improve debugging by adding the semid to the mutex name.
	(semget): Correctly print key value as 64 bit hex value in debug
	output.
	(semexit_myhook): Remove Cygwin specific unlocking of mutexes owned
	by exiting process.  Keep semaphore global lock throughout whole
	function to avoid races.
	* sysv_shm.cc (GIANT_REQUIRED): Define empty on Cygwin. We know that
	Giant is locked.
This commit is contained in:
Corinna Vinschen 2005-04-06 11:11:07 +00:00
parent f0fdfd3454
commit dafef5e249
8 changed files with 232 additions and 205 deletions

View File

@ -1,3 +1,52 @@
2005-04-06 Corinna Vinschen <corinna@vinschen.de>
* bsd_helper.cc (ipcexit_hookthread): Fix whitespace and handle leak.
* bsd_mutex.cc: Include stdlib.h, sys/msg.h and sys/sem.h.
(mtx_init): Initialize lock counter to 0.
(_mtx_lock): Increment and log mutex lock counter.
(mtx_owned): Add winpid argument. Return true only if mutex is
actually owned by process winpid.
(_mtx_assert): Add winpid argument accordingly.
(_mtx_unlock): Log owner and lock count.
(MSLEEP_MUTEX): Remove.
(MSLEEP_SEM): Ditto.
(MSLEEP_EVENT): Ditto.
(msleep_event_name): Ditto.
(msleep_cs): New global critical section.
(msleep_cnt): New global variable indicating msleep record usage.
(msleep_max_cnt): New global variable indicating msleep record size.
(msleep_arr): New global pointer to msleep records.
(msleep_init): Initialize msleep_cs. Allocate msleep_arr array.
(_msleep): Rewrite using new msleep_cs/msleep_arr based thread
synchronization. Don't be shy with debug output.
(wakeup): Rewrite using new msleep_cs/msleep_arr based thread
synchronization.
* bsd_mutex.h (struct mtx): Add lock counter for better debugging.
(mtx_owned): Declare with winpid argument.
(_mtx_assert): Ditto.
(mtx_assert): Define with winpid argument.
* cygserver.cc (version): Remove.
(SERVER_VERSION): New define, decoupling server version information
from source code control system.
(print_version): Simplify printing server version.
* process.cc (process::process): Fix wrong bracketing (and handle leak).
(process::~process): Only try to close _signal_arrived if valid.
* sysv_sem.cc: Include sys/smallprint.h.
(semundo_clear): Define with additional struct thread pointer argument.
Accomodate throughout.
(SEMUNDO_LOCKASSERT): Define with winpid argument. Accomodate
throughout.
(struct sem_undo): Define un_proc as pid_t on Cygwin. Accomodate
throughout.
(seminit): Improve debugging by adding the semid to the mutex name.
(semget): Correctly print key value as 64 bit hex value in debug
output.
(semexit_myhook): Remove Cygwin specific unlocking of mutexes owned
by exiting process. Keep semaphore global lock throughout whole
function to avoid races.
* sysv_shm.cc (GIANT_REQUIRED): Define empty on Cygwin. We know that
Giant is locked.
2005-04-01 Corinna Vinschen <corinna@vinschen.de> 2005-04-01 Corinna Vinschen <corinna@vinschen.de>
* bsd_mutex.cc (_msleep): Whitespace fix. * bsd_mutex.cc (_msleep): Whitespace fix.

View File

@ -1,6 +1,6 @@
/* bsd_helper.cc /* bsd_helper.cc
Copyright 2003, 2004 Red Hat Inc. Copyright 2003, 2004, 2005 Red Hat Inc.
This file is part of Cygwin. This file is part of Cygwin.
@ -129,7 +129,7 @@ ipcexit_hookthread (const LPVOID param)
exiting process and shmexit_myhook to keep track of shared exiting process and shmexit_myhook to keep track of shared
memory. */ memory. */
if (Giant.owner == shs->ipcblk.winpid) if (Giant.owner == shs->ipcblk.winpid)
mtx_unlock (&Giant); mtx_unlock (&Giant);
if (support_semaphores == TUN_TRUE) if (support_semaphores == TUN_TRUE)
semexit_myhook (NULL, &shs->ipcblk); semexit_myhook (NULL, &shs->ipcblk);
if (support_sharedmem == TUN_TRUE) if (support_sharedmem == TUN_TRUE)
@ -152,6 +152,7 @@ ipcexit_hookthread (const LPVOID param)
if (ipcht_entry->winpid == shs->ipcblk.winpid) if (ipcht_entry->winpid == shs->ipcblk.winpid)
{ {
SLIST_REMOVE (&ipcht_list, ipcht_entry, ipc_hookthread, sht_next); SLIST_REMOVE (&ipcht_list, ipcht_entry, ipc_hookthread, sht_next);
CloseHandle (ipcht_entry->thread);
delete ipcht_entry; delete ipcht_entry;
} }
} }

View File

@ -14,6 +14,9 @@ details. */
#define __BSD_VISIBLE 1 #define __BSD_VISIBLE 1
#include <sys/smallprint.h> #include <sys/smallprint.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include "process.h" #include "process.h"
#include "cygserver_ipc.h" #include "cygserver_ipc.h"
@ -26,6 +29,7 @@ mtx_init (mtx *m, const char *name, const void *, int)
{ {
m->name = name; m->name = name;
m->owner = 0; m->owner = 0;
m->cnt = 0;
/* Can't use Windows Mutexes here since Windows Mutexes are only /* Can't use Windows Mutexes here since Windows Mutexes are only
unlockable by the lock owner. */ unlockable by the lock owner. */
m->h = CreateSemaphore (NULL, 1, 1, NULL); m->h = CreateSemaphore (NULL, 1, 1, NULL);
@ -36,30 +40,32 @@ mtx_init (mtx *m, const char *name, const void *, int)
void void
_mtx_lock (mtx *m, DWORD winpid, const char *file, int line) _mtx_lock (mtx *m, DWORD winpid, const char *file, int line)
{ {
_log (file, line, LOG_DEBUG, "Try locking mutex %s", m->name); _log (file, line, LOG_DEBUG, "Try locking mutex %s (%u) (hold: %u)",
m->name, winpid, m->owner);
if (WaitForSingleObject (m->h, INFINITE) != WAIT_OBJECT_0) if (WaitForSingleObject (m->h, INFINITE) != WAIT_OBJECT_0)
_panic (file, line, "wait for %s in %d failed, %E", m->name, winpid); _panic (file, line, "wait for %s in %d failed, %E", m->name, winpid);
m->owner = winpid; m->owner = winpid;
_log (file, line, LOG_DEBUG, "Locked mutex %s", m->name); _log (file, line, LOG_DEBUG, "Locked mutex %s/%u (%u)",
m->name, ++m->cnt, winpid);
} }
int int
mtx_owned (mtx *m) mtx_owned (mtx *m, DWORD winpid)
{ {
return m->owner > 0; return m->owner == winpid;
} }
void void
_mtx_assert (mtx *m, int what, const char *file, int line) _mtx_assert (mtx *m, int what, DWORD winpid, const char *file, int line)
{ {
switch (what) switch (what)
{ {
case MA_OWNED: case MA_OWNED:
if (!mtx_owned (m)) if (!mtx_owned (m, winpid))
_panic (file, line, "Mutex %s not owned", m->name); _panic (file, line, "Mutex %s not owned", m->name);
break; break;
case MA_NOTOWNED: case MA_NOTOWNED:
if (mtx_owned (m)) if (mtx_owned (m, winpid))
_panic (file, line, "Mutex %s is owned", m->name); _panic (file, line, "Mutex %s is owned", m->name);
break; break;
default: default:
@ -70,6 +76,8 @@ _mtx_assert (mtx *m, int what, const char *file, int line)
void void
_mtx_unlock (mtx *m, const char *file, int line) _mtx_unlock (mtx *m, const char *file, int line)
{ {
DWORD owner = m->owner;
unsigned long cnt = m->cnt;
m->owner = 0; m->owner = 0;
/* Cautiously check if mtx_destroy has been called (shutdown). /* Cautiously check if mtx_destroy has been called (shutdown).
In that case, m->h is NULL. */ In that case, m->h is NULL. */
@ -82,7 +90,8 @@ _mtx_unlock (mtx *m, const char *file, int line)
|| (wincap.is_winnt () && GetLastError () != ERROR_TOO_MANY_POSTS)) || (wincap.is_winnt () && GetLastError () != ERROR_TOO_MANY_POSTS))
_panic (file, line, "release of mutex %s failed, %E", m->name); _panic (file, line, "release of mutex %s failed, %E", m->name);
} }
_log (file, line, LOG_DEBUG, "Unlocked mutex %s", m->name); _log (file, line, LOG_DEBUG, "Unlocked mutex %s/%u (owner: %u)",
m->name, cnt, owner);
} }
void void
@ -98,22 +107,6 @@ mtx_destroy (mtx *m)
* Helper functions for msleep/wakeup. * Helper functions for msleep/wakeup.
*/ */
/* Values for which */
#define MSLEEP_MUTEX 0
#define MSLEEP_SEM 1
#define MSLEEP_EVENT 2
static char *
msleep_event_name (void *ident, char *name, int which)
{
if (wincap.has_terminal_services ())
__small_sprintf (name, "Global\\cygserver.msleep.evt.%1d.%08x",
which, ident);
else
__small_sprintf (name, "cygserver.msleep.evt.%1d.%08x", which, ident);
return name;
}
static int static int
win_priority (int priority) win_priority (int priority)
{ {
@ -172,13 +165,36 @@ set_priority (int priority)
* flag the mutex is not entered before returning. * flag the mutex is not entered before returning.
*/ */
static HANDLE msleep_glob_evt; static HANDLE msleep_glob_evt;
CRITICAL_SECTION msleep_cs;
static long msleep_cnt;
static long msleep_max_cnt;
static struct msleep_record {
void *ident;
HANDLE wakeup_evt;
LONG threads;
} *msleep_arr;
void void
msleep_init (void) msleep_init (void)
{ {
extern struct msginfo msginfo;
extern struct seminfo seminfo;
msleep_glob_evt = CreateEvent (NULL, TRUE, FALSE, NULL); msleep_glob_evt = CreateEvent (NULL, TRUE, FALSE, NULL);
if (!msleep_glob_evt) if (!msleep_glob_evt)
panic ("CreateEvent in msleep_init failed: %E"); panic ("CreateEvent in msleep_init failed: %E");
InitializeCriticalSection (&msleep_cs);
long msgmni = support_msgqueues ? msginfo.msgmni : 0;
long semmni = support_semaphores ? seminfo.semmni : 0;
TUNABLE_INT_FETCH ("kern.ipc.msgmni", &msgmni);
TUNABLE_INT_FETCH ("kern.ipc.semmni", &semmni);
debug ("Try allocating msgmni (%d) + semmni (%d) msleep records",
msgmni, semmni);
msleep_max_cnt = msgmni + semmni;
msleep_arr = (struct msleep_record *) calloc (msleep_max_cnt,
sizeof (struct msleep_record));
if (!msleep_arr)
panic ("Allocating msleep records in msleep_init failed: %d", errno);
} }
int int
@ -186,46 +202,47 @@ _msleep (void *ident, struct mtx *mtx, int priority,
const char *wmesg, int timo, struct thread *td) const char *wmesg, int timo, struct thread *td)
{ {
int ret = -1; int ret = -1;
char name[64]; int i;
/* The mutex is used to indicate an ident specific critical section. while (1)
The critical section is needed to synchronize access to the {
semaphore and eventually the event object. The whole idea is EnterCriticalSection (&msleep_cs);
that a wakeup is *guaranteed* to wakeup *all* threads. If that's for (i = 0; i < msleep_cnt; ++i)
not synchronized, sleeping threads could return into the msleep if (msleep_arr[i].ident == ident)
function before all other threads have called CloseHandle(evt). break;
That's bad, since the event still exists and is signalled! */ if (!msleep_arr[i].ident)
HANDLE mutex = CreateMutex (NULL, FALSE, {
msleep_event_name (ident, name, MSLEEP_MUTEX)); debug ("New ident %x, index %d", ident, i);
if (!mutex) if (i >= msleep_max_cnt)
panic ("CreateMutex in msleep (%s) failed: %E", wmesg); panic ("Too many idents to wait for.\n");
WaitForSingleObject (mutex, INFINITE); msleep_arr[i].ident = ident;
msleep_arr[i].wakeup_evt = CreateEvent (NULL, TRUE, FALSE, NULL);
if (!msleep_arr[i].wakeup_evt)
panic ("CreateEvent in msleep (%s) failed: %E", wmesg);
msleep_arr[i].threads = 1;
++msleep_cnt;
LeaveCriticalSection (&msleep_cs);
break;
}
else if (WaitForSingleObject (msleep_arr[i].wakeup_evt, 0)
!= WAIT_OBJECT_0)
{
++msleep_arr[i].threads;
LeaveCriticalSection (&msleep_cs);
break;
}
/* Otherwise wakeup has been called, so sleep to wait until all
formerly waiting threads have left and retry. */
LeaveCriticalSection (&msleep_cs);
Sleep (1L);
}
/* Ok, we're in the critical section now. We create an ident specific
semaphore, which is used to synchronize the waiting threads. */
HANDLE sem = CreateSemaphore (NULL, 0, LONG_MAX,
msleep_event_name (ident, name, MSLEEP_SEM));
if (!sem)
panic ("CreateSemaphore in msleep (%s) failed: %E", wmesg);
/* This thread is one more thread sleeping. The semaphore value is
so used as a counter of sleeping threads. That info is needed by
the wakeup function. */
ReleaseSemaphore (sem, 1, NULL);
/* Leave critical section. */
ReleaseMutex (mutex);
HANDLE evt = CreateEvent (NULL, TRUE, FALSE,
msleep_event_name (ident, name, MSLEEP_EVENT));
if (!evt)
panic ("CreateEvent in msleep (%s) failed: %E", wmesg);
if (mtx) if (mtx)
mtx_unlock (mtx); mtx_unlock (mtx);
int old_priority = set_priority (priority); int old_priority = set_priority (priority);
HANDLE obj[4] = HANDLE obj[4] =
{ {
evt, msleep_arr[i].wakeup_evt,
msleep_glob_evt, msleep_glob_evt,
td->client->handle (), td->client->handle (),
td->client->signal_arrived () td->client->signal_arrived ()
@ -241,37 +258,45 @@ _msleep (void *ident, struct mtx *mtx, int priority,
{ {
case WAIT_OBJECT_0: /* wakeup() has been called. */ case WAIT_OBJECT_0: /* wakeup() has been called. */
ret = 0; ret = 0;
debug ("msleep wakeup called");
break; break;
case WAIT_OBJECT_0 + 1: /* Shutdown event (triggered by wakeup_all). */ case WAIT_OBJECT_0 + 1: /* Shutdown event (triggered by wakeup_all). */
priority |= PDROP; priority |= PDROP;
/*FALLTHRU*/ /*FALLTHRU*/
case WAIT_OBJECT_0 + 2: /* The dependent process has exited. */ case WAIT_OBJECT_0 + 2: /* The dependent process has exited. */
debug ("msleep process exit or shutdown");
ret = EIDRM; ret = EIDRM;
break; break;
case WAIT_OBJECT_0 + 3: /* Signal for calling process arrived. */ case WAIT_OBJECT_0 + 3: /* Signal for calling process arrived. */
debug ("msleep process got signal");
ret = EINTR; ret = EINTR;
break; break;
case WAIT_TIMEOUT: case WAIT_TIMEOUT:
ret = EWOULDBLOCK; ret = EWOULDBLOCK;
break; break;
default: default:
panic ("wait in msleep (%s) failed, %E", wmesg); /* There's a chance that a process has been terminated before
WaitForMultipleObjects has been called. In this case the handles
might be invalid. The error code returned is ERROR_INVALID_HANDLE.
Since we can trust the values of these handles otherwise, we
treat an ERROR_INVALID_HANDLE as a normal process termination and
hope for the best. */
if (GetLastError () != ERROR_INVALID_HANDLE)
panic ("wait in msleep (%s) failed, %E", wmesg);
ret = EIDRM;
break; break;
} }
CloseHandle (evt); EnterCriticalSection (&msleep_cs);
/* wakeup has reset the semaphore to 0. Now indicate that this thread if (--msleep_arr[i].threads == 0)
has called CloseHandle (evt) and enter the critical section. The {
critical section is still hold by wakeup, until all formerly sleeping CloseHandle (msleep_arr[i].wakeup_evt);
threads have indicated that the event has been dismissed. That's msleep_arr[i].ident = NULL;
the signal for wakeup that it's the only thread still holding a --msleep_cnt;
handle to the event object. wakeup will then close the last handle if (i < msleep_cnt)
and leave the critical section. */ msleep_arr[i] = msleep_arr[msleep_cnt];
ReleaseSemaphore (sem, 1, NULL); }
WaitForSingleObject (mutex, INFINITE); LeaveCriticalSection (&msleep_cs);
CloseHandle (sem);
ReleaseMutex (mutex);
CloseHandle (mutex);
set_priority (old_priority); set_priority (old_priority);
@ -286,70 +311,15 @@ _msleep (void *ident, struct mtx *mtx, int priority,
int int
wakeup (void *ident) wakeup (void *ident)
{ {
char name[64]; int i;
LONG threads;
HANDLE evt = OpenEvent (EVENT_MODIFY_STATE, FALSE,
msleep_event_name (ident, name, MSLEEP_EVENT));
if (!evt) /* No thread is waiting. */
{
/* Another round of different error codes returned by 9x and NT
systems. Oh boy... */
if ( (!wincap.is_winnt () && GetLastError () != ERROR_INVALID_NAME)
|| (wincap.is_winnt () && GetLastError () != ERROR_FILE_NOT_FOUND))
panic ("OpenEvent (%s) in wakeup failed: %E", name);
return 0;
}
/* The mutex is used to indicate an ident specific critical section.
The critical section is needed to synchronize access to the
semaphore and eventually the event object. The whole idea is
that a wakeup is *guaranteed* to wakeup *all* threads. If that's
not synchronized, sleeping threads could return into the msleep
function before all other threads have called CloseHandle(evt).
That's bad, since the event still exists and is signalled! */
HANDLE mutex = OpenMutex (MUTEX_ALL_ACCESS, FALSE,
msleep_event_name (ident, name, MSLEEP_MUTEX));
if (!mutex)
panic ("OpenMutex (%s) in wakeup failed: %E", name);
WaitForSingleObject (mutex, INFINITE);
/* Ok, we're in the critical section now. We create an ident specific
semaphore, which is used to synchronize the waiting threads. */
HANDLE sem = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE,
msleep_event_name (ident, name, MSLEEP_SEM));
if (!sem)
panic ("OpenSemaphore (%s) in wakeup failed: %E", name);
ReleaseSemaphore (sem, 1, &threads);
/* `threads' is the number of waiting threads. Now reset the semaphore
to 0 and wait for this number of threads to indicate that they have
called CloseHandle (evt). Then it's save to do the same here in
wakeup, which then means that the event object is destroyed and
can get safely recycled. */
for (int i = threads + 1; i > 0; --i)
WaitForSingleObject (sem, INFINITE);
if (!SetEvent (evt))
panic ("SetEvent (%s) in wakeup failed, %E", name);
/* Now wait for all threads which were waiting for this wakeup. */
while (threads-- > 0)
WaitForSingleObject (sem, INFINITE);
/* Now our handle is the last handle to this event object. */
CloseHandle (evt);
/* But paranoia rulez, so we check here again. */
evt = OpenEvent (EVENT_MODIFY_STATE, FALSE,
msleep_event_name (ident, name, MSLEEP_EVENT));
if (evt)
panic ("Event %s has not been destroyed. Obviously I can't count :-(",
name);
CloseHandle (sem);
/* Leave critical section (all of wakeup is critical). */
ReleaseMutex (mutex);
CloseHandle (mutex);
EnterCriticalSection (&msleep_cs);
for (i = 0; i < msleep_cnt; ++i)
if (msleep_arr[i].ident == ident)
break;
if (msleep_arr[i].ident)
SetEvent (msleep_arr[i].wakeup_evt);
LeaveCriticalSection (&msleep_cs);
return 0; return 0;
} }

View File

@ -1,6 +1,6 @@
/* bsd_mutex.h: BSD Mutex helper /* bsd_mutex.h: BSD Mutex helper
Copyright 2003 Red Hat, Inc. Copyright 2003, 2005 Red Hat, Inc.
This file is part of Cygwin. This file is part of Cygwin.
@ -25,6 +25,7 @@ struct mtx {
HANDLE h; HANDLE h;
const char *name; const char *name;
DWORD owner; DWORD owner;
unsigned long cnt;
}; };
/* Some BSD kernel global mutex. */ /* Some BSD kernel global mutex. */
@ -33,9 +34,9 @@ extern struct mtx Giant;
void mtx_init (mtx *, const char *, const void *, int); void mtx_init (mtx *, const char *, const void *, int);
void _mtx_lock (mtx *, DWORD winpid, const char *, int); void _mtx_lock (mtx *, DWORD winpid, const char *, int);
#define mtx_lock(m) _mtx_lock((m), (td->ipcblk->winpid), __FILE__, __LINE__) #define mtx_lock(m) _mtx_lock((m), (td->ipcblk->winpid), __FILE__, __LINE__)
int mtx_owned (mtx *); int mtx_owned (mtx *, DWORD);
void _mtx_assert(mtx *, int, const char *, int); void _mtx_assert(mtx *, int, DWORD winpid, const char *, int);
#define mtx_assert(m,w) _mtx_assert((m),(w),__FILE__,__LINE__) #define mtx_assert(m,w,p) _mtx_assert((m),(w),(p),__FILE__,__LINE__)
void _mtx_unlock (mtx *, const char *, int); void _mtx_unlock (mtx *, const char *, int);
#define mtx_unlock(m) _mtx_unlock((m),__FILE__,__LINE__) #define mtx_unlock(m) _mtx_unlock((m),__FILE__,__LINE__)

View File

@ -1,6 +1,6 @@
/* cygserver.cc /* cygserver.cc
Copyright 2001, 2002, 2003, 2004 Red Hat Inc. Copyright 2001, 2002, 2003, 2004, 2005 Red Hat Inc.
Written by Egor Duda <deo@logos-m.ru> Written by Egor Duda <deo@logos-m.ru>
@ -37,8 +37,7 @@ details. */
#define DEF_CONFIG_FILE "" SYSCONFDIR "/cygserver.conf" #define DEF_CONFIG_FILE "" SYSCONFDIR "/cygserver.conf"
// Version string. #define SERVER_VERSION "1.12"
static const char version[] = "$Revision$";
GENERIC_MAPPING access_mapping; GENERIC_MAPPING access_mapping;
@ -496,24 +495,6 @@ print_usage (const char *const pgm)
static void static void
print_version () print_version ()
{ {
char *vn = NULL;
const char *const colon = strchr (version, ':');
if (!colon)
{
vn = strdup ("?");
}
else
{
vn = strdup (colon + 2); // Skip ": "
char *const spc = strchr (vn, ' ');
if (spc)
*spc = '\0';
}
char buf[200]; char buf[200];
snprintf (buf, sizeof (buf), "%d.%d.%d(%d.%d/%d/%d)-(%d.%d.%d.%d) %s", snprintf (buf, sizeof (buf), "%d.%d.%d(%d.%d/%d/%d)-(%d.%d.%d.%d) %s",
cygwin_version.dll_major / 1000, cygwin_version.dll_major / 1000,
@ -531,12 +512,10 @@ print_version ()
log (LOG_INFO, "(cygwin) %s\n" log (LOG_INFO, "(cygwin) %s\n"
"API version %s\n" "API version %s\n"
"Copyright 2001, 2002, 2003 Red Hat, Inc.\n" "Copyright 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.\n"
"Compiled on %s\n" "Compiled on %s\n"
"Default configuration file is %s", "Default configuration file is %s",
vn, buf, __DATE__, DEF_CONFIG_FILE); SERVER_VERSION, buf, __DATE__, DEF_CONFIG_FILE);
free (vn);
} }
/* /*

View File

@ -68,9 +68,11 @@ process::process (const pid_t cygpid, const DWORD winpid, HANDLE signal_arrived)
if (!DuplicateHandle (_hProcess, signal_arrived, if (!DuplicateHandle (_hProcess, signal_arrived,
GetCurrentProcess (), &_signal_arrived, GetCurrentProcess (), &_signal_arrived,
0, FALSE, DUPLICATE_SAME_ACCESS)) 0, FALSE, DUPLICATE_SAME_ACCESS))
system_printf ("error getting signal_arrived to server (%lu)", {
GetLastError ()); system_printf ("error getting signal_arrived to server (%lu)",
_signal_arrived = INVALID_HANDLE_VALUE; GetLastError ());
_signal_arrived = INVALID_HANDLE_VALUE;
}
} }
InitializeCriticalSection (&_access); InitializeCriticalSection (&_access);
debug ("initialized (%lu)", _cygpid); debug ("initialized (%lu)", _cygpid);
@ -80,7 +82,8 @@ process::~process ()
{ {
debug ("deleting (%lu)", _cygpid); debug ("deleting (%lu)", _cygpid);
DeleteCriticalSection (&_access); DeleteCriticalSection (&_access);
CloseHandle (_signal_arrived); if (_signal_arrived && _signal_arrived != INVALID_HANDLE_VALUE)
CloseHandle (_signal_arrived);
CloseHandle (_hProcess); CloseHandle (_hProcess);
} }

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/kern/sysv_sem.c,v 1.70 2004/05/30 20
#include "cygserver.h" #include "cygserver.h"
#include "process.h" #include "process.h"
#include "cygserver_ipc.h" #include "cygserver_ipc.h"
#include <sys/smallprint.h>
#ifdef __CYGWIN__ #ifdef __CYGWIN__
#define __semctl semctl #define __semctl semctl
@ -53,7 +54,7 @@ static int semvalid(int semid, struct semid_ds *semaptr);
static struct sem_undo *semu_alloc(struct thread *td); static struct sem_undo *semu_alloc(struct thread *td);
static int semundo_adjust(struct thread *td, struct sem_undo **supptr, static int semundo_adjust(struct thread *td, struct sem_undo **supptr,
int semid, int semnum, int adjval); int semid, int semnum, int adjval);
static void semundo_clear(int semid, int semnum); static void semundo_clear(int semid, int semnum, struct thread *td);
#ifndef _SYS_SYSPROTO_H_ #ifndef _SYS_SYSPROTO_H_
struct __semctl_args; struct __semctl_args;
@ -88,7 +89,7 @@ static eventhandler_tag semexit_tag;
#define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX); #define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX);
#define SEMUNDO_HOOKLOCK() _mtx_lock(&SEMUNDO_MTX, p->winpid, __FILE__, __LINE__); #define SEMUNDO_HOOKLOCK() _mtx_lock(&SEMUNDO_MTX, p->winpid, __FILE__, __LINE__);
#define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX); #define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX);
#define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how)); #define SEMUNDO_LOCKASSERT(how,pid) mtx_assert(&SEMUNDO_MTX, (how), (pid));
struct sem { struct sem {
u_short semval; /* semaphore value */ u_short semval; /* semaphore value */
@ -108,7 +109,11 @@ struct undo {
struct sem_undo { struct sem_undo {
SLIST_ENTRY(sem_undo) un_next; /* ptr to next active undo structure */ SLIST_ENTRY(sem_undo) un_next; /* ptr to next active undo structure */
#ifdef __CYGWIN__
DWORD un_proc; /* owner of this structure */
#else
struct proc *un_proc; /* owner of this structure */ struct proc *un_proc; /* owner of this structure */
#endif
short un_cnt; /* # of active entries */ short un_cnt; /* # of active entries */
struct undo un_ent[1]; /* undo entries */ struct undo un_ent[1]; /* undo entries */
}; };
@ -240,10 +245,18 @@ seminit(void)
sema[i].sem_perm.seq = 0; sema[i].sem_perm.seq = 0;
} }
for (i = 0; i < seminfo.semmni; i++) for (i = 0; i < seminfo.semmni; i++)
mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF); {
char *buf = (char *)malloc (16);
__small_sprintf (buf, "semid[%d]", i);
mtx_init(&sema_mtx[i], buf, NULL, MTX_DEF);
}
for (i = 0; i < seminfo.semmnu; i++) { for (i = 0; i < seminfo.semmnu; i++) {
struct sem_undo *suptr = SEMU(i); struct sem_undo *suptr = SEMU(i);
#ifdef __CYGWIN__
suptr->un_proc = 0;
#else
suptr->un_proc = NULL; suptr->un_proc = NULL;
#endif
} }
SLIST_INIT(&semu_list); SLIST_INIT(&semu_list);
mtx_init(&sem_mtx, "sem", NULL, MTX_DEF); mtx_init(&sem_mtx, "sem", NULL, MTX_DEF);
@ -351,7 +364,7 @@ semu_alloc(struct thread *td)
struct sem_undo **supptr; struct sem_undo **supptr;
int attempt; int attempt;
SEMUNDO_LOCKASSERT(MA_OWNED); SEMUNDO_LOCKASSERT(MA_OWNED, td->td_proc->winpid);
/* /*
* Try twice to allocate something. * Try twice to allocate something.
* (we'll purge an empty structure after the first pass so * (we'll purge an empty structure after the first pass so
@ -366,10 +379,14 @@ semu_alloc(struct thread *td)
for (i = 0; i < seminfo.semmnu; i++) { for (i = 0; i < seminfo.semmnu; i++) {
suptr = SEMU(i); suptr = SEMU(i);
#ifdef __CYGWIN__
if (suptr->un_proc == 0) {
#else
if (suptr->un_proc == NULL) { if (suptr->un_proc == NULL) {
#endif
SLIST_INSERT_HEAD(&semu_list, suptr, un_next); SLIST_INSERT_HEAD(&semu_list, suptr, un_next);
suptr->un_cnt = 0; suptr->un_cnt = 0;
suptr->un_proc = td->td_proc; suptr->un_proc = td->td_proc->winpid;
return(suptr); return(suptr);
} }
} }
@ -386,7 +403,11 @@ semu_alloc(struct thread *td)
SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list,
un_next) { un_next) {
if (suptr->un_cnt == 0) { if (suptr->un_cnt == 0) {
#ifdef __CYGWIN__
suptr->un_proc = 0;
#else
suptr->un_proc = NULL; suptr->un_proc = NULL;
#endif
did_something = 1; did_something = 1;
*supptr = SLIST_NEXT(suptr, un_next); *supptr = SLIST_NEXT(suptr, un_next);
break; break;
@ -421,7 +442,7 @@ semundo_adjust(struct thread *td, struct sem_undo **supptr, int semid,
struct undo *sunptr; struct undo *sunptr;
int i; int i;
SEMUNDO_LOCKASSERT(MA_OWNED); SEMUNDO_LOCKASSERT(MA_OWNED, td->td_proc->winpid);
/* Look for and remember the sem_undo if the caller doesn't provide /* Look for and remember the sem_undo if the caller doesn't provide
it */ it */
@ -429,7 +450,7 @@ semundo_adjust(struct thread *td, struct sem_undo **supptr, int semid,
if (suptr == NULL) { if (suptr == NULL) {
SLIST_FOREACH(suptr, &semu_list, un_next) { SLIST_FOREACH(suptr, &semu_list, un_next) {
#ifdef __CYGWIN__ #ifdef __CYGWIN__
if (suptr->un_proc->cygpid == p->cygpid) { if (suptr->un_proc == p->winpid) {
#else #else
if (suptr->un_proc == p) { if (suptr->un_proc == p) {
#endif #endif
@ -486,11 +507,11 @@ semundo_adjust(struct thread *td, struct sem_undo **supptr, int semid,
} }
static void static void
semundo_clear(int semid, int semnum) semundo_clear(int semid, int semnum, struct thread *td)
{ {
struct sem_undo *suptr; struct sem_undo *suptr;
SEMUNDO_LOCKASSERT(MA_OWNED); SEMUNDO_LOCKASSERT(MA_OWNED, td->td_proc->winpid);
SLIST_FOREACH(suptr, &semu_list, un_next) { SLIST_FOREACH(suptr, &semu_list, un_next) {
struct undo *sunptr = &suptr->un_ent[0]; struct undo *sunptr = &suptr->un_ent[0];
int i = 0; int i = 0;
@ -647,7 +668,7 @@ __semctl(struct thread *td, struct __semctl_args *uap)
} }
semaptr->sem_perm.mode = 0; semaptr->sem_perm.mode = 0;
SEMUNDO_LOCK(); SEMUNDO_LOCK();
semundo_clear(semid, -1); semundo_clear(semid, -1, td);
SEMUNDO_UNLOCK(); SEMUNDO_UNLOCK();
wakeup(semaptr); wakeup(semaptr);
break; break;
@ -770,7 +791,7 @@ __semctl(struct thread *td, struct __semctl_args *uap)
} }
semaptr->sem_base[semnum].semval = real_arg.val; semaptr->sem_base[semnum].semval = real_arg.val;
SEMUNDO_LOCK(); SEMUNDO_LOCK();
semundo_clear(semid, semnum); semundo_clear(semid, semnum, td);
SEMUNDO_UNLOCK(); SEMUNDO_UNLOCK();
wakeup(semaptr); wakeup(semaptr);
break; break;
@ -808,7 +829,7 @@ raced:
semaptr->sem_base[i].semval = usval; semaptr->sem_base[i].semval = usval;
} }
SEMUNDO_LOCK(); SEMUNDO_LOCK();
semundo_clear(semid, -1); semundo_clear(semid, -1, td);
SEMUNDO_UNLOCK(); SEMUNDO_UNLOCK();
wakeup(semaptr); wakeup(semaptr);
break; break;
@ -821,7 +842,7 @@ raced:
if (error == 0) if (error == 0)
td->td_retval[0] = rval; td->td_retval[0] = rval;
done2: done2:
if (mtx_owned(sema_mtxp)) if (mtx_owned(sema_mtxp, td->td_proc->winpid))
mtx_unlock(sema_mtxp); mtx_unlock(sema_mtxp);
if (array != NULL) if (array != NULL)
sys_free(array, M_TEMP); sys_free(array, M_TEMP);
@ -850,7 +871,7 @@ semget(struct thread *td, struct semget_args *uap)
struct ucred *cred = td->td_ucred; struct ucred *cred = td->td_ucred;
#endif #endif
DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); DPRINTF(("semget(0x%X, %d, 0%o)\n", key, nsems, semflg));
if (!jail_sysvipc_allowed && jailed(td->td_ucred)) if (!jail_sysvipc_allowed && jailed(td->td_ucred))
return (ENOSYS); return (ENOSYS);
@ -1056,7 +1077,7 @@ semop(struct thread *td, struct semop_args *uap)
semptr = &semaptr->sem_base[sopptr->sem_num]; semptr = &semaptr->sem_base[sopptr->sem_num];
DPRINTF(( DPRINTF((
"semop: semaptr=%x, sem_base=%x, " "semop: semaptr=%x, sem_base=%x, "
"semptr=%x, sem[%d]=%d : op=%d, flag=%s\n", "semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
semaptr, semaptr->sem_base, semptr, semaptr, semaptr->sem_base, semptr,
sopptr->sem_num, semptr->semval, sopptr->sem_op, sopptr->sem_num, semptr->semval, sopptr->sem_op,
@ -1252,18 +1273,6 @@ semexit_myhook(void *arg, struct proc *p)
struct sem_undo *suptr; struct sem_undo *suptr;
struct sem_undo **supptr; struct sem_undo **supptr;
#ifdef __CYGWIN__
/*
* Search all mutexes, if some of them are still owned by the
* leaving process. If so, unlock them.
*/
if (sem_mtx.owner == p->winpid)
mtx_unlock(&sem_mtx);
for (int i = 0; i < seminfo.semmni; i++)
if (sema_mtx[i].owner == p->winpid)
mtx_unlock(&sema_mtx[i]);
#endif /* __CYGWIN__ */
/* /*
* Go through the chain of undo vectors looking for one * Go through the chain of undo vectors looking for one
* associated with this process. * associated with this process.
@ -1271,16 +1280,20 @@ semexit_myhook(void *arg, struct proc *p)
SEMUNDO_HOOKLOCK(); SEMUNDO_HOOKLOCK();
SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, un_next) { SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, un_next) {
#ifdef __CYGWIN__ #ifdef __CYGWIN__
if (suptr->un_proc->cygpid == p->cygpid) if (suptr->un_proc == p->winpid)
#else #else
if (suptr->un_proc == p) if (suptr->un_proc == p)
#endif #endif
break; break;
} }
#ifndef __CYGWIN__
SEMUNDO_UNLOCK(); SEMUNDO_UNLOCK();
#endif
if (suptr == NULL) if (suptr == NULL) {
SEMUNDO_UNLOCK();
return; return;
}
#ifdef __CYGWIN__ #ifdef __CYGWIN__
DPRINTF(("proc @%u(%u) has undo structure with %d entries\n", DPRINTF(("proc @%u(%u) has undo structure with %d entries\n",
@ -1309,8 +1322,8 @@ semexit_myhook(void *arg, struct proc *p)
_mtx_lock(sema_mtxp, p->winpid, __FILE__, __LINE__); _mtx_lock(sema_mtxp, p->winpid, __FILE__, __LINE__);
#else #else
mtx_lock(sema_mtxp); mtx_lock(sema_mtxp);
#endif
SEMUNDO_HOOKLOCK(); SEMUNDO_HOOKLOCK();
#endif
if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
panic("semexit - semid not allocated"); panic("semexit - semid not allocated");
if (semnum >= semaptr->sem_nsems) if (semnum >= semaptr->sem_nsems)
@ -1318,13 +1331,11 @@ semexit_myhook(void *arg, struct proc *p)
DPRINTF(( DPRINTF((
#ifdef __CYGWIN__ #ifdef __CYGWIN__
"semexit: %u(%u) id=%d num=%d(adj=%d) ; sem=%d\n", "semexit: %u id=%d num=%d(adj=%d) ; sem=%d\n",
suptr->un_proc->cygpid, suptr->un_proc->winpid,
suptr->un_ent[ix].un_id,
#else #else
"semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n", "semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
suptr->un_proc, suptr->un_ent[ix].un_id,
#endif #endif
suptr->un_proc, suptr->un_ent[ix].un_id,
suptr->un_ent[ix].un_num, suptr->un_ent[ix].un_num,
suptr->un_ent[ix].un_adjval, suptr->un_ent[ix].un_adjval,
semaptr->sem_base[semnum].semval)); semaptr->sem_base[semnum].semval));
@ -1340,17 +1351,26 @@ semexit_myhook(void *arg, struct proc *p)
wakeup(semaptr); wakeup(semaptr);
DPRINTF(("semexit: back from wakeup\n")); DPRINTF(("semexit: back from wakeup\n"));
mtx_unlock(sema_mtxp); _mtx_unlock(sema_mtxp, __FILE__, __LINE__);
#ifndef __CYGWIN__
SEMUNDO_UNLOCK(); SEMUNDO_UNLOCK();
#endif
} }
} }
/* /*
* Deallocate the undo vector. * Deallocate the undo vector.
*/ */
DPRINTF(("removing vector\n")); DPRINTF(("removing vector (%u)\n", suptr->un_proc));
#ifdef __CYGWIN__
suptr->un_proc = 0;
#else
suptr->un_proc = NULL; suptr->un_proc = NULL;
#endif
*supptr = SLIST_NEXT(suptr, un_next); *supptr = SLIST_NEXT(suptr, un_next);
#ifdef __CYGWIN__
SEMUNDO_UNLOCK();
#endif
} }
#ifndef __CYGWIN__ #ifndef __CYGWIN__

View File

@ -68,7 +68,11 @@ __FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/kern/sysv_shm.c,v 1.89 2003/11/07 04
#define btoc(b) (((b) + PAGE_MASK) / PAGE_SIZE) #define btoc(b) (((b) + PAGE_MASK) / PAGE_SIZE)
#define round_page(p) ((((unsigned long)(p)) + PAGE_MASK) & ~(PAGE_MASK)) #define round_page(p) ((((unsigned long)(p)) + PAGE_MASK) & ~(PAGE_MASK))
#define ACCESSPERMS (0777) #define ACCESSPERMS (0777)
#ifdef __CYGWIN__
#define GIANT_REQUIRED
#else
#define GIANT_REQUIRED mtx_assert(&Giant, MA_OWNED) #define GIANT_REQUIRED mtx_assert(&Giant, MA_OWNED)
#endif
#define KERN_SUCCESS 0 #define KERN_SUCCESS 0
#define VM_PROT_READ PROT_READ #define VM_PROT_READ PROT_READ
#define VM_PROT_WRITE PROT_WRITE #define VM_PROT_WRITE PROT_WRITE