* Author:
* Dick Porter (dick@ximian.com)
*
- * (C) 2002-2006 Novell, Inc.
+ * (C) 2002-2011 Novell, Inc.
+ * Copyright 2011 Xamarin Inc
*/
#include <config.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
+#include <signal.h>
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <mono/io-layer/wapi.h>
#include <mono/io-layer/wapi-private.h>
#include <mono/io-layer/handles-private.h>
-#include <mono/io-layer/mono-mutex.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
+#include <mono/utils/mono-mutex.h>
#undef DEBUG_REFS
+#if 0
+#define DEBUG(...) g_message(__VA_ARGS__)
+#else
+#define DEBUG(...)
+#endif
+
static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
static pid_t _wapi_pid;
static mono_once_t pid_init_once = MONO_ONCE_INIT;
-static gpointer _wapi_handle_real_new (WapiHandleType type, gpointer handle_specific);
+static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
static void pid_init (void)
{
}
-static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
+static mono_mutex_t scan_mutex;
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
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;
gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
-
- if (_WAPI_SHARED_HANDLE (type)) {
- 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
+ DEBUG ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
- _wapi_handle_unref (handle);
+ _wapi_handle_unref_full (handle, TRUE);
}
}
}
g_free (_wapi_private_handles [i]);
}
-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_init:
+ *
+ * Initialize the io-layer.
+ */
+void
+wapi_init (void)
{
g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
== WAPI_HANDLE_COUNT);
if (_wapi_shm_enabled ())
_wapi_collection_init ();
#endif
+ _wapi_io_init ();
+ mono_mutex_init (&scan_mutex);
- /* Can't call wapi_handle_new as it calls us recursively */
- _wapi_global_signal_handle = _wapi_handle_real_new (WAPI_HANDLE_EVENT, NULL);
+ _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
_wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
_wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
+
/* 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
g_atexit (handle_cleanup);
}
+void
+wapi_cleanup (void)
+{
+ g_assert (_wapi_has_shut_down == FALSE);
+
+ _wapi_has_shut_down = TRUE;
+
+ _wapi_error_cleanup ();
+ _wapi_thread_cleanup ();
+}
+
static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
WapiHandleType type,
gpointer handle_specific)
thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
g_assert (thr_ret == 0);
- thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
+ thr_ret = mono_mutex_init (&handle->signal_mutex);
g_assert (thr_ret == 0);
if (handle_specific != NULL) {
return(0);
}
-static gpointer _wapi_handle_real_new (WapiHandleType type, gpointer handle_specific)
+gpointer
+_wapi_handle_new (WapiHandleType type, gpointer handle_specific)
{
guint32 handle_idx = 0;
gpointer handle;
int thr_ret;
-
-#ifdef DEBUG
- g_message ("%s: Creating new handle of type %s", __func__,
+
+ g_assert (_wapi_has_shut_down == FALSE);
+
+ DEBUG ("%s: Creating new handle of type %s", __func__,
_wapi_handle_typename[type]);
-#endif
g_assert(!_WAPI_FD_HANDLE(type));
handle = GUINT_TO_POINTER (handle_idx);
-#ifdef DEBUG
- g_message ("%s: Allocated new handle %p", __func__, handle);
-#endif
+ DEBUG ("%s: Allocated new handle %p", __func__, handle);
if (_WAPI_SHARED_HANDLE(type)) {
/* Add the shared section too */
ref = _wapi_handle_new_shared (type, handle_specific);
if (ref == 0) {
_wapi_handle_collect ();
- _wapi_process_reap ();
ref = _wapi_handle_new_shared (type, handle_specific);
if (ref == 0) {
/* FIXME: grow the arrays */
}
_WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
-#ifdef DEBUG
- g_message ("%s: New shared handle at offset 0x%x", __func__,
+ DEBUG ("%s: New shared handle at offset 0x%x", __func__,
ref);
-#endif
}
done:
return(handle);
}
-gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
-{
- g_assert (_wapi_has_shut_down == FALSE);
-
- mono_once (&shared_init_once, shared_init);
-
- return _wapi_handle_real_new (type, handle_specific);
-}
-
gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
gboolean timestamp)
{
g_assert (_wapi_has_shut_down == FALSE);
- mono_once (&shared_init_once, shared_init);
-
-#ifdef DEBUG
- g_message ("%s: Creating new handle of type %s to offset %d", __func__,
+ DEBUG ("%s: Creating new handle of type %s to offset %d", __func__,
_wapi_handle_typename[type], offset);
-#endif
g_assert(!_WAPI_FD_HANDLE(type));
g_assert(_WAPI_SHARED_HANDLE(type));
if (handle != INVALID_HANDLE_VALUE) {
_wapi_handle_ref (handle);
-#ifdef DEBUG
- g_message ("%s: Returning old handle %p referencing 0x%x",
+ DEBUG ("%s: Returning old handle %p referencing 0x%x",
__func__, handle, offset);
-#endif
return (handle);
}
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
+ DEBUG ("%s: Handle at 0x%x unused", __func__, offset);
goto done;
}
if (shared->type != type) {
-#ifdef DEBUG
- g_message ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
+ DEBUG ("%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;
}
_WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
InterlockedIncrement ((gint32 *)&shared->handle_refs);
-#ifdef DEBUG
- g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
-#endif
+ DEBUG ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
done:
_wapi_handle_unlock_shared_handles ();
g_assert (_wapi_has_shut_down == FALSE);
- mono_once (&shared_init_once, shared_init);
-
-#ifdef DEBUG
- g_message ("%s: Creating new handle of type %s", __func__,
+ DEBUG ("%s: Creating new handle of type %s", __func__,
_wapi_handle_typename[type]);
-#endif
g_assert(_WAPI_FD_HANDLE(type));
g_assert(!_WAPI_SHARED_HANDLE(type));
if (fd >= _wapi_fd_reserve) {
-#ifdef DEBUG
- g_message ("%s: fd %d is too big", __func__, fd);
-#endif
+ DEBUG ("%s: fd %d is too big", __func__, fd);
return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
}
handle = &_WAPI_PRIVATE_HANDLES(fd);
if (handle->type != WAPI_HANDLE_UNUSED) {
-#ifdef DEBUG
- g_message ("%s: fd %d is already in use!", __func__, fd);
-#endif
+ DEBUG ("%s: fd %d is already in use!", __func__, fd);
/* FIXME: clean up this handle? We can't do anything
* with the fd, cos thats the new one
*/
}
-#ifdef DEBUG
- g_message ("%s: Assigning new fd handle %d", __func__, fd);
-#endif
+ DEBUG ("%s: Assigning new fd handle %d", __func__, fd);
/* Prevent file share entries racing with us, when the file
* handle is only half initialised
* unreffed if the check function returns FALSE, so callers must not
* rely on the handle persisting (unless the check function returns
* TRUE)
+ * The caller owns the returned handle.
*/
gpointer _wapi_search_handle (WapiHandleType type,
gboolean (*check)(gpointer test, gpointer user),
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__);
-#endif
+ DEBUG ("%s: Looking at other shared handles...", __func__);
for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
shared = &_wapi_shared_layout->handles[i];
continue;
}
-#ifdef DEBUG
- g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
-#endif
+ DEBUG ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
/* It's possible that the shared part
* of this handle has now been blown
g_assert(_WAPI_SHARED_HANDLE(type));
-#ifdef DEBUG
- g_message ("%s: Lookup for handle named [%s] type %s", __func__,
+ DEBUG ("%s: Lookup for handle named [%s] type %s", __func__,
utf8_name, _wapi_handle_typename[type]);
-#endif
/* Do a handle collection before starting to look, so that any
* stale cruft gets removed
continue;
}
-#ifdef DEBUG
- g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
-#endif
+ DEBUG ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
-#ifdef DEBUG
- g_message ("%s: name is [%s]", __func__, sharedns->name);
-#endif
+ DEBUG ("%s: name is [%s]", __func__, sharedns->name);
if (strcmp (sharedns->name, utf8_name) == 0) {
if (shared_handle_data->type != type) {
/* Its the wrong type, so fail now */
-#ifdef DEBUG
- g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
-#endif
+ DEBUG ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
ret = -1;
goto done;
} else {
-#ifdef DEBUG
- g_message ("%s: handle 0x%x matches name and type", __func__, i);
-#endif
+ DEBUG ("%s: handle 0x%x matches name and type", __func__, i);
ret = i;
goto done;
}
}
/* The handle must not be locked on entry to this function */
-void _wapi_handle_unref (gpointer handle)
+static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
{
guint32 idx = GPOINTER_TO_UINT(handle);
- gboolean destroy = FALSE;
+ gboolean destroy = FALSE, early_exit = FALSE;
int thr_ret;
if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
thr_ret = mono_mutex_lock (&scan_mutex);
-#ifdef DEBUG
- g_message ("%s: Destroying handle %p", __func__, handle);
-#endif
+ DEBUG ("%s: Destroying handle %p", __func__, handle);
memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
sizeof (struct _WapiHandleUnshared));
* "unlock_and_destroy" atomic function.
*/
thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
- g_assert (thr_ret == 0);
-
- thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
- g_assert (thr_ret == 0);
+ /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
+ if (thr_ret == EBUSY && ignore_private_busy_handles) {
+ early_exit = TRUE;
+ } else {
+ if (thr_ret != 0)
+ g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
+
+ thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
+ if (thr_ret == EBUSY && ignore_private_busy_handles)
+ early_exit = TRUE;
+ else if (thr_ret != 0)
+ g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
+ }
} else {
struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
g_assert (thr_ret == 0);
pthread_cleanup_pop (0);
+ if (early_exit)
+ return;
if (is_shared) {
_wapi_handle_unlock_shared_handles ();
}
}
}
+void _wapi_handle_unref (gpointer handle)
+{
+ _wapi_handle_unref_full (handle, FALSE);
+}
+
void _wapi_handle_register_capabilities (WapiHandleType type,
WapiHandleCapability caps)
{
type = _WAPI_PRIVATE_HANDLES(idx).type;
-#ifdef DEBUG
- g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
+ DEBUG ("%s: testing 0x%x against 0x%x (%d)", __func__,
handle_caps[type], caps, handle_caps[type] & caps);
-#endif
return((handle_caps[type] & caps) != 0);
}
}
}
-guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
+guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
{
guint32 idx = GPOINTER_TO_UINT(handle);
WapiHandleType type;
if (handle_ops[type] != NULL &&
handle_ops[type]->special_wait != NULL) {
- return(handle_ops[type]->special_wait (handle, timeout));
+ return(handle_ops[type]->special_wait (handle, timeout, alertable));
} else {
return(WAIT_FAILED);
}
gpointer handle = handles[i];
guint32 idx = GPOINTER_TO_UINT(handle);
-#ifdef DEBUG
- g_message ("%s: attempting to lock %p", __func__, handle);
-#endif
+ DEBUG ("%s: attempting to lock %p", __func__, handle);
type = _WAPI_PRIVATE_HANDLES(idx).type;
if (thr_ret != 0) {
/* Bummer */
-#ifdef DEBUG
- g_message ("%s: attempt failed for %p: %s", __func__,
+ DEBUG ("%s: attempt failed for %p: %s", __func__,
handle, strerror (thr_ret));
-#endif
thr_ret = _wapi_handle_unlock_shared_handles ();
g_assert (thr_ret == 0);
iter=1;
}
-#ifdef DEBUG
- g_message ("%s: Backing off for %d ms", __func__,
+ DEBUG ("%s: Backing off for %d ms", __func__,
iter*10);
-#endif
_wapi_handle_spin (10 * iter);
goto again;
}
}
-#ifdef DEBUG
- g_message ("%s: Locked all handles", __func__);
-#endif
+ DEBUG ("%s: Locked all handles", __func__);
count=0;
*lowest=numhandles;
type = _WAPI_PRIVATE_HANDLES(idx).type;
-#ifdef DEBUG
- g_message ("%s: Checking handle %p", __func__, handle);
-#endif
+ DEBUG ("%s: Checking handle %p", __func__, handle);
if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
(_wapi_handle_ops_isowned (handle) == TRUE)) ||
_WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
count++;
-#ifdef DEBUG
- g_message ("%s: Handle %p signalled", __func__,
+ DEBUG ("%s: Handle %p signalled", __func__,
handle);
-#endif
if(*lowest>i) {
*lowest=i;
}
}
}
-#ifdef DEBUG
- g_message ("%s: %d event handles signalled", __func__, count);
-#endif
+ DEBUG ("%s: %d event handles signalled", __func__, count);
if ((waitall == TRUE && count == numhandles) ||
(waitall == FALSE && count > 0)) {
ret=FALSE;
}
-#ifdef DEBUG
- g_message ("%s: Returning %d", __func__, ret);
-#endif
+ DEBUG ("%s: Returning %d", __func__, ret);
*retcount=count;
for(i=0; i<numhandles; i++) {
gpointer handle = handles[i];
-#ifdef DEBUG
- g_message ("%s: unlocking handle %p", __func__, handle);
-#endif
+ DEBUG ("%s: unlocking handle %p", __func__, handle);
thr_ret = _wapi_handle_unlock_handle (handle);
g_assert (thr_ret == 0);
int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
{
-#ifdef DEBUG
- g_message ("%s: waiting for %p", __func__, handle);
-#endif
+ DEBUG ("%s: waiting for %p", __func__, handle);
return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
}
int _wapi_handle_timedwait_signal_handle (gpointer handle,
struct timespec *timeout, gboolean alertable, gboolean poll)
{
-#ifdef DEBUG
- g_message ("%s: waiting for %p (type %s)", __func__, handle,
+ DEBUG ("%s: waiting for %p (type %s)", __func__, handle,
_wapi_handle_typename[_wapi_handle_type (handle)]);
-#endif
if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
file_share_hash_lock ();
g_hash_table_remove (file_share_hash, share_info);
file_share_hash_unlock ();
+ /* The hashtable dtor frees share_info */
} else {
memset (share_info, '\0', sizeof(struct _WapiFileShare));
}
*/
static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
{
+#if defined(__native_client__)
+ g_assert_not_reached ();
+#else
if (kill (share_info->opened_by_pid, 0) == -1 &&
(errno == ESRCH ||
errno == EPERM)) {
* owned by someone else) so mark this share info as
* dead
*/
-#ifdef DEBUG
- g_message ("%s: Didn't find it, destroying entry", __func__);
-#endif
+ DEBUG ("%s: Didn't find it, destroying entry", __func__);
- memset (share_info, '\0', sizeof(struct _WapiFileShare));
+ _wapi_free_share_info (share_info);
}
+#endif
}
#ifdef __linux__
struct _WapiHandle_file *file_handle = &handle->u.file;
if (file_handle->share_info == share_info) {
-#ifdef DEBUG
- g_message ("%s: handle 0x%x has this file open!",
+ DEBUG ("%s: handle 0x%x has this file open!",
__func__, i);
-#endif
goto done;
}
continue;
}
-#ifdef DEBUG
- g_message ("%s: Looking in %s", __func__, subdir);
-#endif
+ DEBUG ("%s: Looking in %s", __func__, subdir);
proc_fds = TRUE;
stat (path, &link_stat);
if (link_stat.st_dev == share_info->device &&
link_stat.st_ino == share_info->inode) {
-#ifdef DEBUG
- g_message ("%s: Found it at %s",
+ DEBUG ("%s: Found it at %s",
__func__, path);
-#endif
found = TRUE;
}
_wapi_handle_check_share_by_pid (share_info);
} else if (found == FALSE) {
/* Blank out this entry, as it is stale */
-#ifdef DEBUG
- g_message ("%s: Didn't find it, destroying entry", __func__);
-#endif
+ DEBUG ("%s: Didn't find it, destroying entry", __func__);
- memset (share_info, '\0', sizeof(struct _WapiFileShare));
+ _wapi_free_share_info (share_info);
}
done:
if (_WAPI_SHARED_HANDLE(handle->type)) {
struct _WapiHandleShared *shared_data;
-#ifdef DEBUG
- 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
+ DEBUG ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
-#ifdef DEBUG
- g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
-#endif
+ DEBUG ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
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__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
-#endif
+ DEBUG ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
g_assert (file_handle->share_info != NULL);
-#ifdef DEBUG
- 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
+ DEBUG ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
}