* Author:
* Dick Porter (dick@ximian.com)
*
- * (C) 2002 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
&_wapi_pipe_ops,
&_wapi_namedmutex_ops,
&_wapi_namedsem_ops,
+ &_wapi_namedevent_ops,
};
static void _wapi_shared_details (gpointer handle_info);
_wapi_pipe_details,
_wapi_shared_details, /* namedmutex */
_wapi_shared_details, /* namedsem */
+ _wapi_shared_details, /* namedevent */
};
const char *_wapi_handle_typename[] = {
"Pipe",
"N.Mutex",
"N.Sem",
+ "N.Event",
"Error!!"
};
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
+ * this before share_init() might have been called.
+ */
+static pid_t _wapi_pid;
+static mono_once_t pid_init_once = MONO_ONCE_INIT;
+
+static void pid_init (void)
+{
+ _wapi_pid = getpid ();
+}
+
+pid_t _wapi_getpid (void)
+{
+ mono_once (&pid_init_once, pid_init);
+
+ return(_wapi_pid);
+}
+
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
while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
/* Try and expand the array, and have another go */
int idx = SLOT_INDEX (_wapi_private_handle_count);
+ if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
+ break;
+ }
+
_wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
_WAPI_HANDLE_INITIAL_COUNT);
_wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
}
-
+
thr_ret = mono_mutex_unlock (&scan_mutex);
g_assert (thr_ret == 0);
pthread_cleanup_pop (0);
+
+ if (handle_idx == 0) {
+ /* We ran out of slots */
+ handle = _WAPI_HANDLE_INVALID;
+ goto done;
+ }
/* Make sure we left the space for fd mappings */
g_assert (handle_idx >= _wapi_fd_reserve);
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
struct _WapiHandleUnshared *handle_data;
guint32 handle_idx = GPOINTER_TO_UINT(handle);
+ if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
+ return(FALSE);
+ }
+
handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
if (handle_data->type != type) {
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 (handle_data->type == type) {
ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
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));
shared_handle_data = &_wapi_shared_layout->handles[i];
/* Check mutex, event, semaphore, timer, job and
- * file-mapping object names. So far only mutex and
- * semaphore are implemented.
+ * file-mapping object names. So far only mutex,
+ * semaphore and event are implemented.
*/
if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
continue;
{
guint32 idx = GPOINTER_TO_UINT(handle);
guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
- struct _WapiHandleUnshared *handle_data = &_WAPI_PRIVATE_HANDLES(idx);
+ struct _WapiHandleUnshared *handle_data;
+ if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
+ return;
+ }
+
if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
g_warning ("%s: Attempting to ref unused handle %p", __func__,
handle);
return;
}
+
+ 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
- g_message ("%s: handle %p ref now %d", __func__, handle,
+ g_message ("%s: %s handle %p ref now %d", __func__,
+ _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
+ handle,
_WAPI_PRIVATE_HANDLES(idx).ref);
#endif
}
gboolean destroy = FALSE;
int thr_ret;
+ if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
+ return;
+ }
+
if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
g_warning ("%s: Attempting to unref unused handle %p",
__func__, handle);
* 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: handle %p ref now %d (destroy %s)", __func__, handle,
+ g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
+ _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
+ handle,
_WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
#endif
/* 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) {
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
+ if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
+ return(FALSE);
+ }
+
type = _WAPI_PRIVATE_HANDLES(idx).type;
#ifdef DEBUG
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
+ if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
+ return;
+ }
+
type = _WAPI_PRIVATE_HANDLES(idx).type;
if (handle_ops[type] != NULL &&
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
+ if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
+ return;
+ }
+
type = _WAPI_PRIVATE_HANDLES(idx).type;
if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
+ if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
+ return(FALSE);
+ }
+
type = _WAPI_PRIVATE_HANDLES(idx).type;
if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
+ if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
+ return(FALSE);
+ }
+
type = _WAPI_PRIVATE_HANDLES(idx).type;
if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
+ if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
+ return(WAIT_FAILED);
+ }
+
type = _WAPI_PRIVATE_HANDLES(idx).type;
if (handle_ops[type] != NULL &&
}
}
+void _wapi_handle_ops_prewait (gpointer handle)
+{
+ guint32 idx = GPOINTER_TO_UINT (handle);
+ WapiHandleType type;
+
+ if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
+ return;
+ }
+
+ type = _WAPI_PRIVATE_HANDLES (idx).type;
+
+ if (handle_ops[type] != NULL &&
+ handle_ops[type]->prewait != NULL) {
+ handle_ops[type]->prewait (handle);
+ }
+}
+
/**
* CloseHandle:
*/
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);
}
}
guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
int thr_ret, i, first_unused = -1;
gboolean exists = FALSE;
-
+
/* Prevents entries from expiring under us as we search
*/
thr_ret = _wapi_handle_lock_shared_handles ();
* This makes the increment atomic wrt
* collections
*/
- InterlockedIncrement (&file_share->handle_refs);
+ InterlockedIncrement ((gint32 *)&file_share->handle_refs);
exists = TRUE;
break;
file_share->device = device;
file_share->inode = inode;
- file_share->opened_by_pid = getpid ();
+ file_share->opened_by_pid = _wapi_getpid ();
file_share->sharemode = new_sharemode;
file_share->access = new_access;
file_share->handle_refs = 1;
}
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);
void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
{
gboolean found = FALSE, proc_fds = FALSE;
- pid_t self = getpid();
+ pid_t self = _wapi_getpid ();
int pid;
int thr_ret, i;
struct _WapiHandleShared *shared_data;
#ifdef DEBUG
- g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__,
- getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
+ g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
#endif
shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
#ifdef DEBUG
- g_message ("%s: (%d) Updating timestamp of handle 0x%x",
- __func__, getpid(),
- handle->u.shared.offset);
+ 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;
#ifdef DEBUG
- g_message ("%s: (%d) handle 0x%x is FILE", __func__,
- getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
+ g_message ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
#endif
g_assert (file_handle->share_info != NULL);
#ifdef DEBUG
- g_message ("%s: (%d) Inc refs on fileshare 0x%x",
- __func__, getpid(),
- (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
+ 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 ();
}
+