* Author:
* Dick Porter (dick@ximian.com)
*
- * (C) 2002-2006 Ximian, Inc.
+ * (C) 2002-2006 Novell, Inc.
*/
#include <config.h>
#include <mono/io-layer/misc-private.h>
#include <mono/io-layer/shared.h>
#include <mono/io-layer/collection.h>
+#include <mono/io-layer/process-private.h>
+#include <mono/io-layer/critical-section-private.h>
#undef DEBUG
#undef DEBUG_REFS
pthread_cond_t _wapi_global_signal_cond;
int _wapi_sem_id;
+gboolean _wapi_has_shut_down = FALSE;
/* Use this instead of getpid(), to cope with linuxthreads. It's a
* function rather than a variable lookup because we need to get at
static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
+static void handle_cleanup (void)
+{
+ int i, j, k;
+
+ _wapi_process_signal_self ();
+
+ /* Every shared handle we were using ought really to be closed
+ * by now, but to make sure just blow them all away. The
+ * exiting finalizer thread in particular races us to the
+ * program exit and doesn't always win, so it can be left
+ * cluttering up the shared file. Anything else left over is
+ * really a bug.
+ */
+ for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
+ for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
+ struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
+ int type = handle_data->type;
+
+
+ if (_WAPI_SHARED_HANDLE (type)) {
+ gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
+
+ if (type == WAPI_HANDLE_THREAD) {
+ /* Special-case thread handles
+ * because they need extra
+ * cleanup. This also avoids
+ * a race condition between
+ * the application exit and
+ * the finalizer thread - if
+ * it finishes up between now
+ * and actual app termination
+ * it will find all its handle
+ * details have been blown
+ * away, so this sets those
+ * anyway.
+ */
+ _wapi_thread_set_termination_details (handle, 0);
+ }
+
+ for(k = handle_data->ref; k > 0; k--) {
+#ifdef DEBUG
+ g_message ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
+#endif
+
+ _wapi_handle_unref (handle);
+ }
+ }
+ }
+ }
+
+ _wapi_shm_semaphores_remove ();
+
+ mono_mutex_destroy(&_wapi_global_signal_mutex);
+ pthread_cond_destroy(&_wapi_global_signal_cond);
+}
+
+void _wapi_cleanup ()
+{
+ g_assert (_wapi_has_shut_down == FALSE);
+
+ _wapi_has_shut_down = TRUE;
+
+ _wapi_critical_section_cleanup ();
+ _wapi_error_cleanup ();
+ _wapi_thread_cleanup ();
+}
+
static mono_once_t shared_init_once = MONO_ONCE_INIT;
static void shared_init (void)
{
_wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
} while(_wapi_fd_reserve > _wapi_private_handle_count);
+
+ _wapi_shm_semaphores_init ();
_wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
g_assert (_wapi_shared_layout != NULL);
-
- _wapi_shm_semaphores_init ();
_wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
g_assert (_wapi_fileshare_layout != NULL);
thr_ret = mono_mutex_init(&_wapi_global_signal_mutex, NULL);
g_assert (thr_ret == 0);
+
+ /* Using g_atexit here instead of an explicit function call in
+ * a cleanup routine lets us cope when a third-party library
+ * calls exit (eg if an X client loses the connection to its
+ * server.)
+ */
+ g_atexit (handle_cleanup);
}
static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
WapiHandleType type,
gpointer handle_specific)
{
+ g_assert (_wapi_has_shut_down == FALSE);
+
handle->type = type;
handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
handle->signalled = FALSE;
{
int thr_ret;
+ g_assert (_wapi_has_shut_down == FALSE);
+
handle->type = type;
handle->signalled = FALSE;
handle->ref = 1;
static guint32 last = 1;
int thr_ret;
+ g_assert (_wapi_has_shut_down == FALSE);
+
/* Leave the first slot empty as a guard */
again:
/* FIXME: expandable array */
static guint32 last = 0;
gboolean retry = FALSE;
+ g_assert (_wapi_has_shut_down == FALSE);
+
/* A linear scan should be fast enough. Start from the last
* allocation, assuming that handles are allocated more often
* than they're freed. Leave the space reserved for file
gpointer handle;
int thr_ret;
+ g_assert (_wapi_has_shut_down == FALSE);
+
mono_once (&shared_init_once, shared_init);
#ifdef DEBUG
struct _WapiHandleShared *shared;
guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
+ g_assert (_wapi_has_shut_down == FALSE);
+
mono_once (&shared_init_once, shared_init);
#ifdef DEBUG
shared = &_wapi_shared_layout->handles[offset];
if (timestamp) {
/* Bump up the timestamp for this offset */
- InterlockedExchange (&shared->timestamp, now);
+ InterlockedExchange ((gint32 *)&shared->timestamp, now);
}
pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
if (shared->type == WAPI_HANDLE_UNUSED) {
/* Someone deleted this handle while we were working */
+#ifdef DEBUG
+ g_message ("%s: Handle at 0x%x unused", __func__, offset);
+#endif
+ goto done;
+ }
+
+ if (shared->type != type) {
+#ifdef DEBUG
+ g_message ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
+ __func__, offset, offset,
+ _wapi_handle_typename[shared->type],
+ _wapi_handle_typename[type]);
+#endif
goto done;
}
handle = GUINT_TO_POINTER (handle_idx);
_WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
- InterlockedIncrement (&shared->handle_refs);
+ InterlockedIncrement ((gint32 *)&shared->handle_refs);
#ifdef DEBUG
- g_message ("%s: Allocated new handle %p referencing 0x%x", __func__,
- handle, offset);
+ g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
#endif
done:
struct _WapiHandleUnshared *handle;
int thr_ret;
+ g_assert (_wapi_has_shut_down == FALSE);
+
mono_once (&shared_init_once, shared_init);
#ifdef DEBUG
gpointer _wapi_search_handle (WapiHandleType type,
gboolean (*check)(gpointer test, gpointer user),
gpointer user_data,
- gpointer *handle_specific)
+ gpointer *handle_specific,
+ gboolean search_shared)
{
struct _WapiHandleUnshared *handle_data = NULL;
struct _WapiHandleShared *shared;
if (check (ret, user_data) == TRUE) {
_wapi_handle_ref (ret);
found = TRUE;
+
+ if (_WAPI_SHARED_HANDLE (type)) {
+ shared = &_wapi_shared_layout->handles[i];
+ }
+
break;
}
}
g_assert (thr_ret == 0);
pthread_cleanup_pop (0);
- if (!found && _WAPI_SHARED_HANDLE (type)) {
+ if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
/* Not found yet, so search the shared memory too */
#ifdef DEBUG
g_message ("%s: Looking at other shared handles...", __func__);
if (shared->type == type) {
guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
- InterlockedExchange (&shared->timestamp, now);
+ InterlockedExchange ((gint32 *)&shared->timestamp, now);
found = TRUE;
handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
handle_data = &_WAPI_PRIVATE_HANDLES(idx);
- InterlockedIncrement (&handle_data->ref);
+ InterlockedIncrement ((gint32 *)&handle_data->ref);
/* It's possible for processes to exit before getting around
* to updating timestamps in the collection thread, so if a
if (_WAPI_SHARED_HANDLE(handle_data->type)) {
struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
- InterlockedExchange (&shared_data->timestamp, now);
+ InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
}
#ifdef DEBUG_REFS
* could lock a mutex, but I'm not sure that allowing a handle
* reference to reach 0 isn't an application bug anyway.
*/
- destroy = (InterlockedDecrement (&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
+ destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
#ifdef DEBUG_REFS
g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
/* It's possible that this handle is already
* pointing at a deleted shared section
*/
+#ifdef DEBUG_REFS
+ g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
+#endif
+
if (shared->handle_refs > 0) {
shared->handle_refs--;
if (shared->handle_refs == 0) {
*/
gboolean CloseHandle(gpointer handle)
{
+ if (handle == NULL) {
+ /* Problem: because we map file descriptors to the
+ * same-numbered handle we can't tell the difference
+ * between a bogus handle and the handle to stdin.
+ * Assume that it's the console handle if that handle
+ * exists...
+ */
+ if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+ }
+ if (handle == _WAPI_HANDLE_INVALID){
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return(FALSE);
+ }
+
_wapi_handle_unref (handle);
return(TRUE);
}
+/* Lots more to implement here, but this is all we need at the moment */
+gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
+ gpointer targetprocess, gpointer *target,
+ guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
+{
+ if (srcprocess != _WAPI_PROCESS_CURRENT ||
+ targetprocess != _WAPI_PROCESS_CURRENT) {
+ /* Duplicating other process's handles is not supported */
+ SetLastError (ERROR_INVALID_HANDLE);
+ return(FALSE);
+ }
+
+ if (src == _WAPI_PROCESS_CURRENT) {
+ *target = _wapi_process_duplicate ();
+ } else if (src == _WAPI_THREAD_CURRENT) {
+ *target = _wapi_thread_duplicate ();
+ } else {
+ _wapi_handle_ref (src);
+ *target = src;
+ }
+
+ return(TRUE);
+}
+
gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
gpointer *handles,
gboolean waitall,
}
}
-static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout)
+static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
{
struct timespec fake_timeout;
int ret;
-
- _wapi_calc_timeout (&fake_timeout, 100);
-
- if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
- (fake_timeout.tv_sec == timeout->tv_sec &&
- fake_timeout.tv_nsec > timeout->tv_nsec))) {
- /* Real timeout is less than 100ms time */
- ret=mono_cond_timedwait (cond, mutex, timeout);
+
+ if (!alertable) {
+ if (timeout)
+ ret=mono_cond_timedwait (cond, mutex, timeout);
+ else
+ ret=mono_cond_wait (cond, mutex);
} else {
- ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
+ _wapi_calc_timeout (&fake_timeout, 100);
+
+ if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
+ (fake_timeout.tv_sec == timeout->tv_sec &&
+ fake_timeout.tv_nsec > timeout->tv_nsec))) {
+ /* Real timeout is less than 100ms time */
+ ret=mono_cond_timedwait (cond, mutex, timeout);
+ } else {
+ ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
- /* Mask the fake timeout, this will cause
- * another poll if the cond was not really signaled
- */
- if (ret==ETIMEDOUT) {
- ret=0;
+ /* Mask the fake timeout, this will cause
+ * another poll if the cond was not really signaled
+ */
+ if (ret==ETIMEDOUT) {
+ ret=0;
+ }
}
}
int _wapi_handle_wait_signal (void)
{
- return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL, TRUE);
}
int _wapi_handle_timedwait_signal (struct timespec *timeout)
{
- return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
+ return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout, TRUE);
}
-int _wapi_handle_wait_signal_handle (gpointer handle)
+int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
{
#ifdef DEBUG
g_message ("%s: waiting for %p", __func__, handle);
#endif
- return _wapi_handle_timedwait_signal_handle (handle, NULL);
+ return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable);
}
int _wapi_handle_timedwait_signal_handle (gpointer handle,
- struct timespec *timeout)
+ struct timespec *timeout, gboolean alertable)
{
#ifdef DEBUG
g_message ("%s: waiting for %p (type %s)", __func__, handle,
} else {
guint32 idx = GPOINTER_TO_UINT(handle);
- return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout);
+ return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout, alertable);
}
}
* This makes the increment atomic wrt
* collections
*/
- InterlockedIncrement (&file_share->handle_refs);
+ InterlockedIncrement ((gint32 *)&file_share->handle_refs);
exists = TRUE;
break;
}
if (*share_info != NULL) {
- InterlockedExchange (&(*share_info)->timestamp, now);
+ InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
}
thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
#endif
- InterlockedExchange (&shared_data->timestamp,
- now);
+ InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
} else if (handle->type == WAPI_HANDLE_FILE) {
struct _WapiHandle_file *file_handle = &handle->u.file;
g_message ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
#endif
- InterlockedExchange (&file_handle->share_info->timestamp, now);
+ InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
}
}
}
_wapi_handle_unlock_shared_handles ();
}
+