[runtime] Add a wrapper around atexit () since it is missing on some android versions.
[mono.git] / mono / io-layer / handles.c
1 /*
2  * handles.c:  Generic and internal operations on handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002-2011 Novell, Inc.
8  * Copyright 2011 Xamarin Inc
9  */
10
11 #include <config.h>
12 #include <glib.h>
13 #include <pthread.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <signal.h>
17 #include <string.h>
18 #include <sys/types.h>
19 #ifdef HAVE_SYS_SOCKET_H
20 #  include <sys/socket.h>
21 #endif
22 #ifdef HAVE_SYS_UN_H
23 #  include <sys/un.h>
24 #endif
25 #ifdef HAVE_SYS_MMAN_H
26 #  include <sys/mman.h>
27 #endif
28 #ifdef HAVE_DIRENT_H
29 #  include <dirent.h>
30 #endif
31 #include <sys/stat.h>
32 #ifdef HAVE_SYS_RESOURCE_H
33 #  include <sys/resource.h>
34 #endif
35
36 #include <mono/io-layer/wapi.h>
37 #include <mono/io-layer/wapi-private.h>
38 #include <mono/io-layer/handles-private.h>
39 #include <mono/io-layer/misc-private.h>
40 #include <mono/io-layer/shared.h>
41 #include <mono/io-layer/collection.h>
42 #include <mono/io-layer/process-private.h>
43
44 #include <mono/utils/mono-mutex.h>
45 #include <mono/utils/mono-proclib.h>
46 #undef DEBUG_REFS
47
48 #if 0
49 #define DEBUG(...) g_message(__VA_ARGS__)
50 #else
51 #define DEBUG(...)
52 #endif
53
54 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
55
56 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
57 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
58         NULL,
59         &_wapi_file_ops,
60         &_wapi_console_ops,
61         &_wapi_thread_ops,
62         &_wapi_sem_ops,
63         &_wapi_mutex_ops,
64         &_wapi_event_ops,
65 #ifndef DISABLE_SOCKETS
66         &_wapi_socket_ops,
67 #endif
68         &_wapi_find_ops,
69         &_wapi_process_ops,
70         &_wapi_pipe_ops,
71         &_wapi_namedmutex_ops,
72         &_wapi_namedsem_ops,
73         &_wapi_namedevent_ops,
74 };
75
76 static void _wapi_shared_details (gpointer handle_info);
77
78 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
79         NULL,
80         _wapi_file_details,
81         _wapi_console_details,
82         _wapi_shared_details,   /* thread */
83         _wapi_sem_details,
84         _wapi_mutex_details,
85         _wapi_event_details,
86         NULL,                   /* Nothing useful to see in a socket handle */
87         NULL,                   /* Nothing useful to see in a find handle */
88         _wapi_shared_details,   /* process */
89         _wapi_pipe_details,
90         _wapi_shared_details,   /* namedmutex */
91         _wapi_shared_details,   /* namedsem */
92         _wapi_shared_details,   /* namedevent */
93 };
94
95 const char *_wapi_handle_typename[] = {
96         "Unused",
97         "File",
98         "Console",
99         "Thread",
100         "Sem",
101         "Mutex",
102         "Event",
103         "Socket",
104         "Find",
105         "Process",
106         "Pipe",
107         "N.Mutex",
108         "N.Sem",
109         "N.Event",
110         "Error!!"
111 };
112
113 /*
114  * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
115  * If 4M handles are not enough... Oh, well... we will crash.
116  */
117 #define SLOT_INDEX(x)   (x / _WAPI_HANDLE_INITIAL_COUNT)
118 #define SLOT_OFFSET(x)  (x % _WAPI_HANDLE_INITIAL_COUNT)
119
120 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
121 static guint32 _wapi_private_handle_count = 0;
122 static guint32 _wapi_private_handle_slot_count = 0;
123
124 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
125
126 /*
127  * If SHM is enabled, this will point to shared memory, otherwise it will be NULL.
128  */
129 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
130
131 /*
132  * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
133  * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
134  * 4MB array.
135  */
136 static GHashTable *file_share_hash;
137 static mono_mutex_t file_share_hash_mutex;
138
139 #define file_share_hash_lock() mono_mutex_lock (&file_share_hash_mutex)
140 #define file_share_hash_unlock() mono_mutex_unlock (&file_share_hash_mutex)
141
142 guint32 _wapi_fd_reserve;
143
144 /* 
145  * This is an internal handle which is used for handling waiting for multiple handles.
146  * Threads which wait for multiple handles wait on this one handle, and when a handle
147  * is signalled, this handle is signalled too.
148  */
149 static gpointer _wapi_global_signal_handle;
150
151 /* Point to the mutex/cond inside _wapi_global_signal_handle */
152 mono_mutex_t *_wapi_global_signal_mutex;
153 pthread_cond_t *_wapi_global_signal_cond;
154
155 int _wapi_sem_id;
156 gboolean _wapi_has_shut_down = FALSE;
157
158 /* Use this instead of getpid(), to cope with linuxthreads.  It's a
159  * function rather than a variable lookup because we need to get at
160  * this before share_init() might have been called.
161  */
162 static pid_t _wapi_pid;
163 static mono_once_t pid_init_once = MONO_ONCE_INIT;
164
165 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
166
167 static void pid_init (void)
168 {
169         _wapi_pid = getpid ();
170 }
171
172 pid_t _wapi_getpid (void)
173 {
174         mono_once (&pid_init_once, pid_init);
175         
176         return(_wapi_pid);
177 }
178
179
180 static mono_mutex_t scan_mutex;
181
182 static void handle_cleanup (void)
183 {
184         int i, j, k;
185         
186         /* Every shared handle we were using ought really to be closed
187          * by now, but to make sure just blow them all away.  The
188          * exiting finalizer thread in particular races us to the
189          * program exit and doesn't always win, so it can be left
190          * cluttering up the shared file.  Anything else left over is
191          * really a bug.
192          */
193         for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
194                 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
195                         struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
196                         gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
197
198                         for(k = handle_data->ref; k > 0; k--) {
199                                 DEBUG ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
200                                         
201                                 _wapi_handle_unref_full (handle, TRUE);
202                         }
203                 }
204         }
205         
206         _wapi_shm_semaphores_remove ();
207
208         _wapi_shm_detach (WAPI_SHM_DATA);
209         _wapi_shm_detach (WAPI_SHM_FILESHARE);
210
211         if (file_share_hash) {
212                 g_hash_table_destroy (file_share_hash);
213                 mono_mutex_destroy (&file_share_hash_mutex);
214         }
215
216         for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
217                 g_free (_wapi_private_handles [i]);
218 }
219
220 int
221 wapi_getdtablesize (void)
222 {
223 #ifdef HAVE_GETRLIMIT
224         struct rlimit limit;
225         int res;
226
227         res = getrlimit (RLIMIT_NOFILE, &limit);
228         g_assert (res == 0);
229         return limit.rlim_cur;
230 #else
231         return getdtablesize ();
232 #endif
233 }
234
235 /*
236  * wapi_init:
237  *
238  *   Initialize the io-layer.
239  */
240 void
241 wapi_init (void)
242 {
243         g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
244                   == WAPI_HANDLE_COUNT);
245
246         _wapi_fd_reserve = wapi_getdtablesize ();
247
248         /* This is needed by the code in _wapi_handle_new_internal */
249         _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
250
251         do {
252                 /* 
253                  * The entries in _wapi_private_handles reserved for fds are allocated lazily to 
254                  * save memory.
255                  */
256                 /*
257                 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
258                                                         _WAPI_HANDLE_INITIAL_COUNT);
259                 */
260
261                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
262                 _wapi_private_handle_slot_count ++;
263         } while(_wapi_fd_reserve > _wapi_private_handle_count);
264
265         _wapi_shm_semaphores_init ();
266         
267         _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
268         g_assert (_wapi_shared_layout != NULL);
269         
270         if (_wapi_shm_enabled ()) {
271                 /* This allocates a 4mb array, so do it only if SHM is enabled */
272                 _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
273                 g_assert (_wapi_fileshare_layout != NULL);
274         }
275         
276 #if !defined (DISABLE_SHARED_HANDLES)
277         if (_wapi_shm_enabled ())
278                 _wapi_collection_init ();
279 #endif
280         _wapi_io_init ();
281         mono_mutex_init (&scan_mutex);
282
283         _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
284
285         _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
286         _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
287
288         wapi_processes_init ();
289
290         /* Using atexit here instead of an explicit function call in
291          * a cleanup routine lets us cope when a third-party library
292          * calls exit (eg if an X client loses the connection to its
293          * server.)
294          */
295         mono_atexit (handle_cleanup);
296 }
297
298 void
299 wapi_cleanup (void)
300 {
301         g_assert (_wapi_has_shut_down == FALSE);
302         
303         _wapi_has_shut_down = TRUE;
304
305         _wapi_error_cleanup ();
306         _wapi_thread_cleanup ();
307         wapi_processes_cleanup ();
308 }
309
310 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
311                                       WapiHandleType type,
312                                       gpointer handle_specific)
313 {
314         g_assert (_wapi_has_shut_down == FALSE);
315         
316         handle->type = type;
317         handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
318         handle->signalled = FALSE;
319         handle->handle_refs = 1;
320         
321         if (handle_specific != NULL) {
322                 memcpy (&handle->u, handle_specific, sizeof (handle->u));
323         }
324 }
325
326 static size_t _wapi_handle_struct_size (WapiHandleType type)
327 {
328         size_t type_size;
329
330         switch (type) {
331                 case WAPI_HANDLE_FILE: case WAPI_HANDLE_CONSOLE: case WAPI_HANDLE_PIPE:
332                         type_size = sizeof (struct _WapiHandle_file);
333                         break;
334                 case WAPI_HANDLE_THREAD:
335                         type_size = sizeof (struct _WapiHandle_thread);
336                         break;
337                 case WAPI_HANDLE_SEM:
338                         type_size = sizeof (struct _WapiHandle_sem);
339                         break;
340                 case WAPI_HANDLE_MUTEX:
341                         type_size = sizeof (struct _WapiHandle_mutex);
342                         break;
343                 case WAPI_HANDLE_EVENT:
344                         type_size = sizeof (struct _WapiHandle_event);
345                         break;
346                 case WAPI_HANDLE_SOCKET:
347                         type_size = sizeof (struct _WapiHandle_socket);
348                         break;
349                 case WAPI_HANDLE_FIND:
350                         type_size = sizeof (struct _WapiHandle_find);
351                         break;
352                 case WAPI_HANDLE_PROCESS:
353                         type_size = sizeof (struct _WapiHandle_process);
354                         break;
355                 case WAPI_HANDLE_NAMEDMUTEX:
356                         type_size = sizeof (struct _WapiHandle_namedmutex);
357                         break;
358                 case WAPI_HANDLE_NAMEDSEM:
359                         type_size = sizeof (struct _WapiHandle_namedsem);
360                         break;
361                 case WAPI_HANDLE_NAMEDEVENT:
362                         type_size = sizeof (struct _WapiHandle_namedevent);
363                         break;
364
365                 default:
366                         g_error ("Unknown WapiHandleType: %d\n", type);
367         }
368
369         return type_size;
370 }
371
372 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
373                                WapiHandleType type, gpointer handle_specific)
374 {
375         int thr_ret;
376         int type_size;
377         
378         g_assert (_wapi_has_shut_down == FALSE);
379         
380         handle->type = type;
381         handle->signalled = FALSE;
382         handle->ref = 1;
383         
384         if (!_WAPI_SHARED_HANDLE(type)) {
385                 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
386                 g_assert (thr_ret == 0);
387                                 
388                 thr_ret = mono_mutex_init (&handle->signal_mutex);
389                 g_assert (thr_ret == 0);
390
391                 if (handle_specific != NULL) {
392                         type_size = _wapi_handle_struct_size (type);
393                         memcpy (&handle->u, handle_specific,
394                                 type_size);
395                 }
396         }
397 }
398
399 static guint32 _wapi_handle_new_shared (WapiHandleType type,
400                                         gpointer handle_specific)
401 {
402         guint32 offset;
403         static guint32 last = 1;
404         int thr_ret;
405         
406         g_assert (_wapi_has_shut_down == FALSE);
407         
408         /* Leave the first slot empty as a guard */
409 again:
410         /* FIXME: expandable array */
411         for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
412                 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
413                 
414                 if(handle->type == WAPI_HANDLE_UNUSED) {
415                         thr_ret = _wapi_handle_lock_shared_handles ();
416                         g_assert (thr_ret == 0);
417                         
418                         if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
419                                 last = offset + 1;
420                         
421                                 _wapi_handle_init_shared (handle, type,
422                                                           handle_specific);
423
424                                 _wapi_handle_unlock_shared_handles ();
425                                 
426                                 return(offset);
427                         } else {
428                                 /* Someone else beat us to it, just
429                                  * continue looking
430                                  */
431                         }
432
433                         _wapi_handle_unlock_shared_handles ();
434                 }
435         }
436
437         if(last > 1) {
438                 /* Try again from the beginning */
439                 last = 1;
440                 goto again;
441         }
442
443         /* Will need to expand the array.  The caller will sort it out */
444
445         return(0);
446 }
447
448 /*
449  * _wapi_handle_new_internal:
450  * @type: Init handle to this type
451  *
452  * Search for a free handle and initialize it. Return the handle on
453  * success and 0 on failure.  This is only called from
454  * _wapi_handle_new, and scan_mutex must be held.
455  */
456 static guint32 _wapi_handle_new_internal (WapiHandleType type,
457                                           gpointer handle_specific)
458 {
459         guint32 i, k, count;
460         static guint32 last = 0;
461         gboolean retry = FALSE;
462         
463         g_assert (_wapi_has_shut_down == FALSE);
464         
465         /* A linear scan should be fast enough.  Start from the last
466          * allocation, assuming that handles are allocated more often
467          * than they're freed. Leave the space reserved for file
468          * descriptors
469          */
470         
471         if (last < _wapi_fd_reserve) {
472                 last = _wapi_fd_reserve;
473         } else {
474                 retry = TRUE;
475         }
476
477 again:
478         count = last;
479         for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
480                 if (_wapi_private_handles [i]) {
481                         for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
482                                 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
483
484                                 if(handle->type == WAPI_HANDLE_UNUSED) {
485                                         last = count + 1;
486                         
487                                         _wapi_handle_init (handle, type, handle_specific);
488                                         return (count);
489                                 }
490                                 count++;
491                         }
492                 }
493         }
494
495         if(retry && last > _wapi_fd_reserve) {
496                 /* Try again from the beginning */
497                 last = _wapi_fd_reserve;
498                 goto again;
499         }
500
501         /* Will need to expand the array.  The caller will sort it out */
502
503         return(0);
504 }
505
506 gpointer 
507 _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
508 {
509         guint32 handle_idx = 0;
510         gpointer handle;
511         int thr_ret;
512
513         g_assert (_wapi_has_shut_down == FALSE);
514                 
515         DEBUG ("%s: Creating new handle of type %s", __func__,
516                    _wapi_handle_typename[type]);
517
518         g_assert(!_WAPI_FD_HANDLE(type));
519         
520         thr_ret = mono_mutex_lock (&scan_mutex);
521         g_assert (thr_ret == 0);
522                 
523         while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
524                 /* Try and expand the array, and have another go */
525                 int idx = SLOT_INDEX (_wapi_private_handle_count);
526                 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
527                         break;
528                 }
529
530                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
531                                                 _WAPI_HANDLE_INITIAL_COUNT);
532
533                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
534                 _wapi_private_handle_slot_count ++;
535         }
536         
537         thr_ret = mono_mutex_unlock (&scan_mutex);
538         g_assert (thr_ret == 0);
539
540         if (handle_idx == 0) {
541                 /* We ran out of slots */
542                 handle = _WAPI_HANDLE_INVALID;
543                 goto done;
544         }
545                 
546         /* Make sure we left the space for fd mappings */
547         g_assert (handle_idx >= _wapi_fd_reserve);
548         
549         handle = GUINT_TO_POINTER (handle_idx);
550
551         DEBUG ("%s: Allocated new handle %p", __func__, handle);
552         
553         if (_WAPI_SHARED_HANDLE(type)) {
554                 /* Add the shared section too */
555                 guint32 ref;
556                 
557                 ref = _wapi_handle_new_shared (type, handle_specific);
558                 if (ref == 0) {
559                         _wapi_handle_collect ();
560                         ref = _wapi_handle_new_shared (type, handle_specific);
561                         if (ref == 0) {
562                                 /* FIXME: grow the arrays */
563                                 handle = _WAPI_HANDLE_INVALID;
564                                 goto done;
565                         }
566                 }
567                 
568                 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
569                 DEBUG ("%s: New shared handle at offset 0x%x", __func__,
570                            ref);
571         }
572                 
573 done:
574         return(handle);
575 }
576
577 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
578                                        gboolean timestamp)
579 {
580         guint32 handle_idx = 0;
581         gpointer handle = INVALID_HANDLE_VALUE;
582         int thr_ret, i, k;
583         struct _WapiHandleShared *shared;
584         
585         g_assert (_wapi_has_shut_down == FALSE);
586         
587         DEBUG ("%s: Creating new handle of type %s to offset %d", __func__,
588                    _wapi_handle_typename[type], offset);
589
590         g_assert(!_WAPI_FD_HANDLE(type));
591         g_assert(_WAPI_SHARED_HANDLE(type));
592         g_assert(offset != 0);
593
594         shared = &_wapi_shared_layout->handles[offset];
595         if (timestamp) {
596                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
597                 /* Bump up the timestamp for this offset */
598                 InterlockedExchange ((gint32 *)&shared->timestamp, now);
599         }
600                 
601         thr_ret = mono_mutex_lock (&scan_mutex);
602         g_assert (thr_ret == 0);
603
604         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
605                 if (_wapi_private_handles [i]) {
606                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
607                                 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
608                 
609                                 if (handle_data->type == type &&
610                                         handle_data->u.shared.offset == offset) {
611                                         handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
612                                         goto first_pass_done;
613                                 }
614                         }
615                 }
616         }
617
618 first_pass_done:
619         thr_ret = mono_mutex_unlock (&scan_mutex);
620         g_assert (thr_ret == 0);
621
622         if (handle != INVALID_HANDLE_VALUE) {
623                 _wapi_handle_ref (handle);
624
625                 DEBUG ("%s: Returning old handle %p referencing 0x%x",
626                            __func__, handle, offset);
627                 return (handle);
628         }
629
630         /* Prevent entries expiring under us as we search */
631         thr_ret = _wapi_handle_lock_shared_handles ();
632         g_assert (thr_ret == 0);
633         
634         if (shared->type == WAPI_HANDLE_UNUSED) {
635                 /* Someone deleted this handle while we were working */
636                 DEBUG ("%s: Handle at 0x%x unused", __func__, offset);
637                 goto done;
638         }
639
640         if (shared->type != type) {
641                 DEBUG ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
642                            __func__, offset, offset,
643                            _wapi_handle_typename[shared->type],
644                            _wapi_handle_typename[type]);
645                 goto done;
646         }
647         
648         thr_ret = mono_mutex_lock (&scan_mutex);
649         g_assert (thr_ret == 0);
650         
651         while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
652                 /* Try and expand the array, and have another go */
653                 int idx = SLOT_INDEX (_wapi_private_handle_count);
654                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
655                                                 _WAPI_HANDLE_INITIAL_COUNT);
656
657                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
658                 _wapi_private_handle_slot_count ++;
659         }
660                 
661         thr_ret = mono_mutex_unlock (&scan_mutex);
662         g_assert (thr_ret == 0);
663                 
664         /* Make sure we left the space for fd mappings */
665         g_assert (handle_idx >= _wapi_fd_reserve);
666         
667         handle = GUINT_TO_POINTER (handle_idx);
668                 
669         _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
670         InterlockedIncrement ((gint32 *)&shared->handle_refs);
671         
672         DEBUG ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
673         
674 done:
675         _wapi_handle_unlock_shared_handles ();
676
677         return(handle);
678 }
679
680 static void
681 init_handles_slot (int idx)
682 {
683         int thr_ret;
684
685         thr_ret = mono_mutex_lock (&scan_mutex);
686         g_assert (thr_ret == 0);
687
688         if (_wapi_private_handles [idx] == NULL) {
689                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
690                                                                                           _WAPI_HANDLE_INITIAL_COUNT);
691                 g_assert (_wapi_private_handles [idx]);
692         }
693
694         thr_ret = mono_mutex_unlock (&scan_mutex);
695         g_assert (thr_ret == 0);
696 }
697
698 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
699                               gpointer handle_specific)
700 {
701         struct _WapiHandleUnshared *handle;
702         int thr_ret;
703         
704         g_assert (_wapi_has_shut_down == FALSE);
705         
706         DEBUG ("%s: Creating new handle of type %s", __func__,
707                    _wapi_handle_typename[type]);
708         
709         g_assert(_WAPI_FD_HANDLE(type));
710         g_assert(!_WAPI_SHARED_HANDLE(type));
711         
712         if (fd >= _wapi_fd_reserve) {
713                 DEBUG ("%s: fd %d is too big", __func__, fd);
714
715                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
716         }
717
718         /* Initialize the array entries on demand */
719         if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
720                 init_handles_slot (SLOT_INDEX (fd));
721
722         handle = &_WAPI_PRIVATE_HANDLES(fd);
723         
724         if (handle->type != WAPI_HANDLE_UNUSED) {
725                 DEBUG ("%s: fd %d is already in use!", __func__, fd);
726                 /* FIXME: clean up this handle?  We can't do anything
727                  * with the fd, cos thats the new one
728                  */
729         }
730
731         DEBUG ("%s: Assigning new fd handle %d", __func__, fd);
732
733         /* Prevent file share entries racing with us, when the file
734          * handle is only half initialised
735          */
736         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
737         g_assert(thr_ret == 0);
738
739         _wapi_handle_init (handle, type, handle_specific);
740
741         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
742
743         return(GUINT_TO_POINTER(fd));
744 }
745
746 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
747                               gpointer *handle_specific)
748 {
749         struct _WapiHandleUnshared *handle_data;
750         guint32 handle_idx = GPOINTER_TO_UINT(handle);
751
752         if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
753                 return(FALSE);
754         }
755
756         /* Initialize the array entries on demand */
757         if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
758                 init_handles_slot (SLOT_INDEX (handle_idx));
759         
760         handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
761         
762         if (handle_data->type != type) {
763                 return(FALSE);
764         }
765
766         if (handle_specific == NULL) {
767                 return(FALSE);
768         }
769         
770         if (_WAPI_SHARED_HANDLE(type)) {
771                 struct _WapiHandle_shared_ref *ref;
772                 struct _WapiHandleShared *shared_handle_data;
773                         
774                 ref = &handle_data->u.shared;
775                 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
776                 
777                 if (shared_handle_data->type != type) {
778                         /* The handle must have been deleted on us
779                          */
780                         return (FALSE);
781                 }
782                 
783                 *handle_specific = &shared_handle_data->u;
784         } else {
785                 *handle_specific = &handle_data->u;
786         }
787         
788         return(TRUE);
789 }
790
791 void
792 _wapi_handle_foreach (WapiHandleType type,
793                         gboolean (*on_each)(gpointer test, gpointer user),
794                         gpointer user_data)
795 {
796         struct _WapiHandleUnshared *handle_data = NULL;
797         gpointer ret = NULL;
798         guint32 i, k;
799         int thr_ret;
800
801         thr_ret = mono_mutex_lock (&scan_mutex);
802         g_assert (thr_ret == 0);
803
804         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
805                 if (_wapi_private_handles [i]) {
806                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
807                                 handle_data = &_wapi_private_handles [i][k];
808                         
809                                 if (handle_data->type == type) {
810                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
811                                         if (on_each (ret, user_data) == TRUE)
812                                                 break;
813                                 }
814                         }
815                 }
816         }
817
818         thr_ret = mono_mutex_unlock (&scan_mutex);
819         g_assert (thr_ret == 0);
820 }
821
822 /* This might list some shared handles twice if they are already
823  * opened by this process, and the check function returns FALSE the
824  * first time.  Shared handles that are created during the search are
825  * unreffed if the check function returns FALSE, so callers must not
826  * rely on the handle persisting (unless the check function returns
827  * TRUE)
828  * The caller owns the returned handle.
829  */
830 gpointer _wapi_search_handle (WapiHandleType type,
831                               gboolean (*check)(gpointer test, gpointer user),
832                               gpointer user_data,
833                               gpointer *handle_specific,
834                               gboolean search_shared)
835 {
836         struct _WapiHandleUnshared *handle_data = NULL;
837         struct _WapiHandleShared *shared = NULL;
838         gpointer ret = NULL;
839         guint32 i, k;
840         gboolean found = FALSE;
841         int thr_ret;
842
843         thr_ret = mono_mutex_lock (&scan_mutex);
844         g_assert (thr_ret == 0);
845         
846         for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
847                 if (_wapi_private_handles [i]) {
848                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
849                                 handle_data = &_wapi_private_handles [i][k];
850                 
851                                 if (handle_data->type == type) {
852                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
853                                         if (check (ret, user_data) == TRUE) {
854                                                 _wapi_handle_ref (ret);
855                                                 found = TRUE;
856
857                                                 if (_WAPI_SHARED_HANDLE (type)) {
858                                                         shared = &_wapi_shared_layout->handles[i];
859                                                 }
860                                         
861                                                 break;
862                                         }
863                                 }
864                         }
865                 }
866         }
867
868         thr_ret = mono_mutex_unlock (&scan_mutex);
869         g_assert (thr_ret == 0);
870
871         if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
872                 /* Not found yet, so search the shared memory too */
873                 DEBUG ("%s: Looking at other shared handles...", __func__);
874
875                 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
876                         shared = &_wapi_shared_layout->handles[i];
877                         
878                         if (shared->type == type) {
879                                 /* Tell new_from_offset to not
880                                  * timestamp this handle, because
881                                  * otherwise it will ping every handle
882                                  * in the list and they will never
883                                  * expire
884                                  */
885                                 ret = _wapi_handle_new_from_offset (type, i,
886                                                                     FALSE);
887                                 if (ret == INVALID_HANDLE_VALUE) {
888                                         /* This handle was deleted
889                                          * while we were looking at it
890                                          */
891                                         continue;
892                                 }
893                                 
894                                 DEBUG ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
895
896                                 /* It's possible that the shared part
897                                  * of this handle has now been blown
898                                  * away (after new_from_offset
899                                  * successfully opened it,) if its
900                                  * timestamp is too old.  The check
901                                  * function needs to be aware of this,
902                                  * and cope if the handle has
903                                  * vanished.
904                                  */
905                                 if (check (ret, user_data) == TRUE) {
906                                         /* Timestamp this handle, but make
907                                          * sure it still exists first
908                                          */
909                                         thr_ret = _wapi_handle_lock_shared_handles ();
910                                         g_assert (thr_ret == 0);
911                                         
912                                         if (shared->type == type) {
913                                                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
914                                                 InterlockedExchange ((gint32 *)&shared->timestamp, now);
915
916                                                 found = TRUE;
917                                                 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
918                                         
919                                                 _wapi_handle_unlock_shared_handles ();
920                                                 break;
921                                         } else {
922                                                 /* It's been deleted,
923                                                  * so just keep
924                                                  * looking
925                                                  */
926                                                 _wapi_handle_unlock_shared_handles ();
927                                         }
928                                 }
929                                 
930                                 /* This isn't the handle we're looking
931                                  * for, so drop the reference we took
932                                  * in _wapi_handle_new_from_offset ()
933                                  */
934                                 _wapi_handle_unref (ret);
935                         }
936                 }
937         }
938         
939         if (!found) {
940                 ret = NULL;
941                 goto done;
942         }
943         
944         if(handle_specific != NULL) {
945                 if (_WAPI_SHARED_HANDLE(type)) {
946                         g_assert(shared->type == type);
947                         
948                         *handle_specific = &shared->u;
949                 } else {
950                         *handle_specific = &handle_data->u;
951                 }
952         }
953
954 done:
955         return(ret);
956 }
957
958 /* Returns the offset of the metadata array, or -1 on error, or 0 for
959  * not found (0 is not a valid offset)
960  */
961 gint32 _wapi_search_handle_namespace (WapiHandleType type,
962                                       gchar *utf8_name)
963 {
964         struct _WapiHandleShared *shared_handle_data;
965         guint32 i;
966         gint32 ret = 0;
967         int thr_ret;
968         
969         g_assert(_WAPI_SHARED_HANDLE(type));
970         
971         DEBUG ("%s: Lookup for handle named [%s] type %s", __func__,
972                    utf8_name, _wapi_handle_typename[type]);
973
974         /* Do a handle collection before starting to look, so that any
975          * stale cruft gets removed
976          */
977         _wapi_handle_collect ();
978         
979         thr_ret = _wapi_handle_lock_shared_handles ();
980         g_assert (thr_ret == 0);
981         
982         for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
983                 WapiSharedNamespace *sharedns;
984                 
985                 shared_handle_data = &_wapi_shared_layout->handles[i];
986
987                 /* Check mutex, event, semaphore, timer, job and
988                  * file-mapping object names.  So far only mutex,
989                  * semaphore and event are implemented.
990                  */
991                 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
992                         continue;
993                 }
994
995                 DEBUG ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
996
997                 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
998                         
999                 DEBUG ("%s: name is [%s]", __func__, sharedns->name);
1000
1001                 if (strcmp (sharedns->name, utf8_name) == 0) {
1002                         if (shared_handle_data->type != type) {
1003                                 /* Its the wrong type, so fail now */
1004                                 DEBUG ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
1005                                 ret = -1;
1006                                 goto done;
1007                         } else {
1008                                 DEBUG ("%s: handle 0x%x matches name and type", __func__, i);
1009                                 ret = i;
1010                                 goto done;
1011                         }
1012                 }
1013         }
1014
1015 done:
1016         _wapi_handle_unlock_shared_handles ();
1017         
1018         return(ret);
1019 }
1020
1021 void _wapi_handle_ref (gpointer handle)
1022 {
1023         guint32 idx = GPOINTER_TO_UINT(handle);
1024         struct _WapiHandleUnshared *handle_data;
1025
1026         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1027                 return;
1028         }
1029         
1030         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1031                 g_warning ("%s: Attempting to ref unused handle %p", __func__,
1032                            handle);
1033                 return;
1034         }
1035
1036         handle_data = &_WAPI_PRIVATE_HANDLES(idx);
1037         
1038         InterlockedIncrement ((gint32 *)&handle_data->ref);
1039
1040         /* It's possible for processes to exit before getting around
1041          * to updating timestamps in the collection thread, so if a
1042          * shared handle is reffed do the timestamp here as well just
1043          * to make sure.
1044          */
1045         if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1046                 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1047                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1048                 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1049         }
1050         
1051 #ifdef DEBUG_REFS
1052         g_message ("%s: %s handle %p ref now %d", __func__, 
1053                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1054                    handle,
1055                    _WAPI_PRIVATE_HANDLES(idx).ref);
1056 #endif
1057 }
1058
1059 /* The handle must not be locked on entry to this function */
1060 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
1061 {
1062         guint32 idx = GPOINTER_TO_UINT(handle);
1063         gboolean destroy = FALSE, early_exit = FALSE;
1064         int thr_ret;
1065
1066         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1067                 return;
1068         }
1069         
1070         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1071                 g_warning ("%s: Attempting to unref unused handle %p",
1072                            __func__, handle);
1073                 return;
1074         }
1075
1076         /* Possible race condition here if another thread refs the
1077          * handle between here and setting the type to UNUSED.  I
1078          * could lock a mutex, but I'm not sure that allowing a handle
1079          * reference to reach 0 isn't an application bug anyway.
1080          */
1081         destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1082         
1083 #ifdef DEBUG_REFS
1084         g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1085                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1086                    handle,
1087                    _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1088 #endif
1089         
1090         if(destroy==TRUE) {
1091                 /* Need to copy the handle info, reset the slot in the
1092                  * array, and _only then_ call the close function to
1093                  * avoid race conditions (eg file descriptors being
1094                  * closed, and another file being opened getting the
1095                  * same fd racing the memset())
1096                  */
1097                 struct _WapiHandleUnshared handle_data;
1098                 struct _WapiHandleShared shared_handle_data;
1099                 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1100                 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1101                 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1102
1103                 if (is_shared) {
1104                         /* If this is a shared handle we need to take
1105                          * the shared lock outside of the scan_mutex
1106                          * lock to avoid deadlocks
1107                          */
1108                         thr_ret = _wapi_handle_lock_shared_handles ();
1109                         g_assert (thr_ret == 0);
1110                 }
1111                 
1112                 thr_ret = mono_mutex_lock (&scan_mutex);
1113
1114                 DEBUG ("%s: Destroying handle %p", __func__, handle);
1115                 
1116                 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1117                         sizeof (struct _WapiHandleUnshared));
1118
1119                 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1120                         sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1121
1122                 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1123                 
1124                 if (!is_shared) {
1125                         /* Destroy the mutex and cond var.  We hope nobody
1126                          * tried to grab them between the handle unlock and
1127                          * now, but pthreads doesn't have a
1128                          * "unlock_and_destroy" atomic function.
1129                          */
1130                         thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1131                         /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
1132                         if (thr_ret == EBUSY && ignore_private_busy_handles) {
1133                                 early_exit = TRUE;
1134                         } else {
1135                                 if (thr_ret != 0)
1136                                         g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
1137
1138                                 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1139                                 if (thr_ret == EBUSY && ignore_private_busy_handles)
1140                                         early_exit = TRUE;
1141                                 else if (thr_ret != 0)
1142                                         g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
1143                         }
1144                 } else {
1145                         struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1146
1147                         memcpy (&shared_handle_data, shared,
1148                                 sizeof (struct _WapiHandleShared));
1149                         
1150                         /* It's possible that this handle is already
1151                          * pointing at a deleted shared section
1152                          */
1153 #ifdef DEBUG_REFS
1154                         g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1155 #endif
1156
1157                         if (shared->handle_refs > 0) {
1158                                 shared->handle_refs--;
1159                                 if (shared->handle_refs == 0) {
1160                                         memset (shared, '\0', sizeof (struct _WapiHandleShared));
1161                                 }
1162                         }
1163                 }
1164
1165                 thr_ret = mono_mutex_unlock (&scan_mutex);
1166                 g_assert (thr_ret == 0);
1167
1168                 if (early_exit)
1169                         return;
1170                 if (is_shared) {
1171                         _wapi_handle_unlock_shared_handles ();
1172                 }
1173                 
1174                 if (close_func != NULL) {
1175                         if (is_shared) {
1176                                 close_func (handle, &shared_handle_data.u);
1177                         } else {
1178                                 close_func (handle, &handle_data.u);
1179                         }
1180                 }
1181         }
1182 }
1183
1184 void _wapi_handle_unref (gpointer handle)
1185 {
1186         _wapi_handle_unref_full (handle, FALSE);
1187 }
1188
1189 void _wapi_handle_register_capabilities (WapiHandleType type,
1190                                          WapiHandleCapability caps)
1191 {
1192         handle_caps[type] = caps;
1193 }
1194
1195 gboolean _wapi_handle_test_capabilities (gpointer handle,
1196                                          WapiHandleCapability caps)
1197 {
1198         guint32 idx = GPOINTER_TO_UINT(handle);
1199         WapiHandleType type;
1200
1201         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1202                 return(FALSE);
1203         }
1204         
1205         type = _WAPI_PRIVATE_HANDLES(idx).type;
1206
1207         DEBUG ("%s: testing 0x%x against 0x%x (%d)", __func__,
1208                    handle_caps[type], caps, handle_caps[type] & caps);
1209         
1210         return((handle_caps[type] & caps) != 0);
1211 }
1212
1213 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1214 {
1215         if (handle_ops[type] != NULL &&
1216             handle_ops[type]->close != NULL) {
1217                 return (handle_ops[type]->close);
1218         }
1219
1220         return (NULL);
1221 }
1222
1223 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1224 {
1225         guint32 idx = GPOINTER_TO_UINT(handle);
1226         WapiHandleType type;
1227
1228         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1229                 return;
1230         }
1231         
1232         type = _WAPI_PRIVATE_HANDLES(idx).type;
1233
1234         if (handle_ops[type] != NULL &&
1235             handle_ops[type]->close != NULL) {
1236                 handle_ops[type]->close (handle, data);
1237         }
1238 }
1239
1240 void _wapi_handle_ops_signal (gpointer handle)
1241 {
1242         guint32 idx = GPOINTER_TO_UINT(handle);
1243         WapiHandleType type;
1244
1245         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1246                 return;
1247         }
1248         
1249         type = _WAPI_PRIVATE_HANDLES(idx).type;
1250
1251         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1252                 handle_ops[type]->signal (handle);
1253         }
1254 }
1255
1256 gboolean _wapi_handle_ops_own (gpointer handle)
1257 {
1258         guint32 idx = GPOINTER_TO_UINT(handle);
1259         WapiHandleType type;
1260         
1261         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1262                 return(FALSE);
1263         }
1264         
1265         type = _WAPI_PRIVATE_HANDLES(idx).type;
1266
1267         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1268                 return(handle_ops[type]->own_handle (handle));
1269         } else {
1270                 return(FALSE);
1271         }
1272 }
1273
1274 gboolean _wapi_handle_ops_isowned (gpointer handle)
1275 {
1276         guint32 idx = GPOINTER_TO_UINT(handle);
1277         WapiHandleType type;
1278
1279         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1280                 return(FALSE);
1281         }
1282         
1283         type = _WAPI_PRIVATE_HANDLES(idx).type;
1284
1285         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1286                 return(handle_ops[type]->is_owned (handle));
1287         } else {
1288                 return(FALSE);
1289         }
1290 }
1291
1292 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
1293 {
1294         guint32 idx = GPOINTER_TO_UINT(handle);
1295         WapiHandleType type;
1296         
1297         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1298                 return(WAIT_FAILED);
1299         }
1300         
1301         type = _WAPI_PRIVATE_HANDLES(idx).type;
1302         
1303         if (handle_ops[type] != NULL &&
1304             handle_ops[type]->special_wait != NULL) {
1305                 return(handle_ops[type]->special_wait (handle, timeout, alertable));
1306         } else {
1307                 return(WAIT_FAILED);
1308         }
1309 }
1310
1311 void _wapi_handle_ops_prewait (gpointer handle)
1312 {
1313         guint32 idx = GPOINTER_TO_UINT (handle);
1314         WapiHandleType type;
1315         
1316         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1317                 return;
1318         }
1319         
1320         type = _WAPI_PRIVATE_HANDLES (idx).type;
1321         
1322         if (handle_ops[type] != NULL &&
1323             handle_ops[type]->prewait != NULL) {
1324                 handle_ops[type]->prewait (handle);
1325         }
1326 }
1327
1328
1329 /**
1330  * CloseHandle:
1331  * @handle: The handle to release
1332  *
1333  * Closes and invalidates @handle, releasing any resources it
1334  * consumes.  When the last handle to a temporary or non-persistent
1335  * object is closed, that object can be deleted.  Closing the same
1336  * handle twice is an error.
1337  *
1338  * Return value: %TRUE on success, %FALSE otherwise.
1339  */
1340 gboolean CloseHandle(gpointer handle)
1341 {
1342         if (handle == NULL) {
1343                 /* Problem: because we map file descriptors to the
1344                  * same-numbered handle we can't tell the difference
1345                  * between a bogus handle and the handle to stdin.
1346                  * Assume that it's the console handle if that handle
1347                  * exists...
1348                  */
1349                 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1350                         SetLastError (ERROR_INVALID_PARAMETER);
1351                         return(FALSE);
1352                 }
1353         }
1354         if (handle == _WAPI_HANDLE_INVALID){
1355                 SetLastError (ERROR_INVALID_PARAMETER);
1356                 return(FALSE);
1357         }
1358         
1359         _wapi_handle_unref (handle);
1360         
1361         return(TRUE);
1362 }
1363
1364 /* Lots more to implement here, but this is all we need at the moment */
1365 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1366                           gpointer targetprocess, gpointer *target,
1367                           guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1368 {
1369         if (srcprocess != _WAPI_PROCESS_CURRENT ||
1370             targetprocess != _WAPI_PROCESS_CURRENT) {
1371                 /* Duplicating other process's handles is not supported */
1372                 SetLastError (ERROR_INVALID_HANDLE);
1373                 return(FALSE);
1374         }
1375         
1376         if (src == _WAPI_PROCESS_CURRENT) {
1377                 *target = _wapi_process_duplicate ();
1378         } else if (src == _WAPI_THREAD_CURRENT) {
1379                 g_assert_not_reached ();
1380         } else {
1381                 _wapi_handle_ref (src);
1382                 *target = src;
1383         }
1384         
1385         return(TRUE);
1386 }
1387
1388 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1389                                                gpointer *handles,
1390                                                gboolean waitall,
1391                                                guint32 *retcount,
1392                                                guint32 *lowest)
1393 {
1394         guint32 count, i, iter=0;
1395         gboolean ret;
1396         int thr_ret;
1397         WapiHandleType type;
1398         
1399         /* Lock all the handles, with backoff */
1400 again:
1401         thr_ret = _wapi_handle_lock_shared_handles ();
1402         g_assert (thr_ret == 0);
1403         
1404         for(i=0; i<numhandles; i++) {
1405                 gpointer handle = handles[i];
1406                 guint32 idx = GPOINTER_TO_UINT(handle);
1407
1408                 DEBUG ("%s: attempting to lock %p", __func__, handle);
1409
1410                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1411
1412                 thr_ret = _wapi_handle_trylock_handle (handle);
1413                 
1414                 if (thr_ret != 0) {
1415                         /* Bummer */
1416                         
1417                         DEBUG ("%s: attempt failed for %p: %s", __func__,
1418                                    handle, strerror (thr_ret));
1419
1420                         thr_ret = _wapi_handle_unlock_shared_handles ();
1421                         g_assert (thr_ret == 0);
1422                         
1423                         while (i--) {
1424                                 handle = handles[i];
1425                                 idx = GPOINTER_TO_UINT(handle);
1426
1427                                 thr_ret = _wapi_handle_unlock_handle (handle);
1428                                 g_assert (thr_ret == 0);
1429                         }
1430
1431                         /* If iter ever reaches 100 the nanosleep will
1432                          * return EINVAL immediately, but we have a
1433                          * design flaw if that happens.
1434                          */
1435                         iter++;
1436                         if(iter==100) {
1437                                 g_warning ("%s: iteration overflow!",
1438                                            __func__);
1439                                 iter=1;
1440                         }
1441                         
1442                         DEBUG ("%s: Backing off for %d ms", __func__,
1443                                    iter*10);
1444                         _wapi_handle_spin (10 * iter);
1445                         
1446                         goto again;
1447                 }
1448         }
1449         
1450         DEBUG ("%s: Locked all handles", __func__);
1451
1452         count=0;
1453         *lowest=numhandles;
1454         
1455         for(i=0; i<numhandles; i++) {
1456                 gpointer handle = handles[i];
1457                 guint32 idx = GPOINTER_TO_UINT(handle);
1458                 
1459                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1460
1461                 DEBUG ("%s: Checking handle %p", __func__, handle);
1462
1463                 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1464                     (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1465                    (_WAPI_SHARED_HANDLE(type) &&
1466                     WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1467                    (!_WAPI_SHARED_HANDLE(type) &&
1468                     _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1469                         count++;
1470                         
1471                         DEBUG ("%s: Handle %p signalled", __func__,
1472                                    handle);
1473                         if(*lowest>i) {
1474                                 *lowest=i;
1475                         }
1476                 }
1477         }
1478         
1479         DEBUG ("%s: %d event handles signalled", __func__, count);
1480
1481         if ((waitall == TRUE && count == numhandles) ||
1482             (waitall == FALSE && count > 0)) {
1483                 ret=TRUE;
1484         } else {
1485                 ret=FALSE;
1486         }
1487         
1488         DEBUG ("%s: Returning %d", __func__, ret);
1489
1490         *retcount=count;
1491         
1492         return(ret);
1493 }
1494
1495 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1496 {
1497         guint32 i;
1498         int thr_ret;
1499         
1500         thr_ret = _wapi_handle_unlock_shared_handles ();
1501         g_assert (thr_ret == 0);
1502         
1503         for(i=0; i<numhandles; i++) {
1504                 gpointer handle = handles[i];
1505                 
1506                 DEBUG ("%s: unlocking handle %p", __func__, handle);
1507
1508                 thr_ret = _wapi_handle_unlock_handle (handle);
1509                 g_assert (thr_ret == 0);
1510         }
1511 }
1512
1513 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
1514 {
1515         struct timespec fake_timeout;
1516         int ret;
1517
1518         if (!alertable) {
1519                 if (timeout)
1520                         ret=mono_cond_timedwait (cond, mutex, timeout);
1521                 else
1522                         ret=mono_cond_wait (cond, mutex);
1523         } else {
1524                 _wapi_calc_timeout (&fake_timeout, 100);
1525         
1526                 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1527                                                                 (fake_timeout.tv_sec == timeout->tv_sec &&
1528                                                                  fake_timeout.tv_nsec > timeout->tv_nsec))) {
1529                         /* Real timeout is less than 100ms time */
1530                         ret=mono_cond_timedwait (cond, mutex, timeout);
1531                 } else {
1532                         ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1533
1534                         /* Mask the fake timeout, this will cause
1535                          * another poll if the cond was not really signaled
1536                          */
1537                         if (ret==ETIMEDOUT) {
1538                                 ret=0;
1539                         }
1540                 }
1541         }
1542         
1543         return(ret);
1544 }
1545
1546 int _wapi_handle_wait_signal (gboolean poll)
1547 {
1548         return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
1549 }
1550
1551 int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
1552 {
1553         return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
1554 }
1555
1556 int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
1557 {
1558         DEBUG ("%s: waiting for %p", __func__, handle);
1559         
1560         return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
1561 }
1562
1563 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1564                                                                                   struct timespec *timeout, gboolean alertable, gboolean poll)
1565 {
1566         DEBUG ("%s: waiting for %p (type %s)", __func__, handle,
1567                    _wapi_handle_typename[_wapi_handle_type (handle)]);
1568         
1569         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1570                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1571                         return (0);
1572                 }
1573                 if (timeout != NULL) {
1574                         struct timespec fake_timeout;
1575                         _wapi_calc_timeout (&fake_timeout, 100);
1576                 
1577                         if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1578                                 (fake_timeout.tv_sec == timeout->tv_sec &&
1579                                  fake_timeout.tv_nsec > timeout->tv_nsec)) {
1580                                 /* FIXME: Real timeout is less than
1581                                  * 100ms time, but is it really worth
1582                                  * calculating to the exact ms?
1583                                  */
1584                                 _wapi_handle_spin (100);
1585
1586                                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1587                                         return (0);
1588                                 } else {
1589                                         return (ETIMEDOUT);
1590                                 }
1591                         }
1592                 }
1593                 _wapi_handle_spin (100);
1594                 return (0);
1595                 
1596         } else {
1597                 guint32 idx = GPOINTER_TO_UINT(handle);
1598                 int res;
1599                 pthread_cond_t *cond;
1600                 mono_mutex_t *mutex;
1601
1602                 if (alertable && !wapi_thread_set_wait_handle (handle))
1603                         return 0;
1604
1605                 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1606                 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1607
1608                 if (poll) {
1609                         /* This is needed when waiting for process handles */
1610                         res = timedwait_signal_poll_cond (cond, mutex, timeout, alertable);
1611                 } else {
1612                         if (timeout)
1613                                 res = mono_cond_timedwait (cond, mutex, timeout);
1614                         else
1615                                 res = mono_cond_wait (cond, mutex);
1616                 }
1617
1618                 if (alertable)
1619                         wapi_thread_clear_wait_handle (handle);
1620
1621                 return res;
1622         }
1623 }
1624
1625 void
1626 _wapi_free_share_info (_WapiFileShare *share_info)
1627 {
1628         if (!_wapi_shm_enabled ()) {
1629                 file_share_hash_lock ();
1630                 g_hash_table_remove (file_share_hash, share_info);
1631                 file_share_hash_unlock ();
1632                 /* The hashtable dtor frees share_info */
1633         } else {
1634                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1635         }
1636 }
1637
1638 static gint
1639 wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
1640 {
1641         const _WapiFileShare *s1 = ka;
1642         const _WapiFileShare *s2 = kb;
1643
1644         return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
1645 }
1646
1647 static guint
1648 wapi_share_info_hash (gconstpointer data)
1649 {
1650         const _WapiFileShare *s = data;
1651
1652         return s->inode;
1653 }
1654
1655 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1656                                         guint32 new_sharemode,
1657                                         guint32 new_access,
1658                                         guint32 *old_sharemode,
1659                                         guint32 *old_access,
1660                                         struct _WapiFileShare **share_info)
1661 {
1662         struct _WapiFileShare *file_share;
1663         guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1664         int thr_ret, i, first_unused = -1;
1665         gboolean exists = FALSE;
1666
1667         /* Prevents entries from expiring under us as we search
1668          */
1669         thr_ret = _wapi_handle_lock_shared_handles ();
1670         g_assert (thr_ret == 0);
1671         
1672         /* Prevent new entries racing with us */
1673         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1674         g_assert (thr_ret == 0);
1675
1676         if (!_wapi_shm_enabled ()) {
1677                 _WapiFileShare tmp;
1678
1679                 /*
1680                  * Instead of allocating a 4MB array, we use a hash table to keep track of this
1681                  * info. This is needed even if SHM is disabled, to track sharing inside
1682                  * the current process.
1683                  */
1684                 if (!file_share_hash) {
1685                         file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
1686                         mono_mutex_init_recursive (&file_share_hash_mutex);
1687                 }
1688                         
1689                 tmp.device = device;
1690                 tmp.inode = inode;
1691
1692                 file_share_hash_lock ();
1693
1694                 file_share = g_hash_table_lookup (file_share_hash, &tmp);
1695                 if (file_share) {
1696                         *old_sharemode = file_share->sharemode;
1697                         *old_access = file_share->access;
1698                         *share_info = file_share;
1699                         
1700                         InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1701                         exists = TRUE;
1702                 } else {
1703                         file_share = g_new0 (_WapiFileShare, 1);
1704
1705                         file_share->device = device;
1706                         file_share->inode = inode;
1707                         file_share->opened_by_pid = _wapi_getpid ();
1708                         file_share->sharemode = new_sharemode;
1709                         file_share->access = new_access;
1710                         file_share->handle_refs = 1;
1711                         *share_info = file_share;
1712
1713                         g_hash_table_insert (file_share_hash, file_share, file_share);
1714                 }
1715
1716                 file_share_hash_unlock ();
1717         } else {
1718                 /* If a linear scan gets too slow we'll have to fit a hash
1719                  * table onto the shared mem backing store
1720                  */
1721                 *share_info = NULL;
1722                 for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1723                         file_share = &_wapi_fileshare_layout->share_info[i];
1724
1725                         /* Make a note of an unused slot, in case we need to
1726                          * store share info
1727                          */
1728                         if (first_unused == -1 && file_share->handle_refs == 0) {
1729                                 first_unused = i;
1730                                 continue;
1731                         }
1732                 
1733                         if (file_share->handle_refs == 0) {
1734                                 continue;
1735                         }
1736                 
1737                         if (file_share->device == device &&
1738                                 file_share->inode == inode) {
1739                                 *old_sharemode = file_share->sharemode;
1740                                 *old_access = file_share->access;
1741                                 *share_info = file_share;
1742                         
1743                                 /* Increment the reference count while we
1744                                  * still have sole access to the shared area.
1745                                  * This makes the increment atomic wrt
1746                                  * collections
1747                                  */
1748                                 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1749                         
1750                                 exists = TRUE;
1751                                 break;
1752                         }
1753                 }
1754         
1755                 if (!exists) {
1756                         if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1757                                 /* No more space */
1758                         } else {
1759                                 if (first_unused == -1) {
1760                                         file_share = &_wapi_fileshare_layout->share_info[++i];
1761                                         _wapi_fileshare_layout->hwm = i;
1762                                 } else {
1763                                         file_share = &_wapi_fileshare_layout->share_info[first_unused];
1764                                 }
1765                         
1766                                 file_share->device = device;
1767                                 file_share->inode = inode;
1768                                 file_share->opened_by_pid = _wapi_getpid ();
1769                                 file_share->sharemode = new_sharemode;
1770                                 file_share->access = new_access;
1771                                 file_share->handle_refs = 1;
1772                                 *share_info = file_share;
1773                         }
1774                 }
1775
1776                 if (*share_info != NULL) {
1777                         InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1778                 }
1779         }
1780         
1781         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1782
1783         _wapi_handle_unlock_shared_handles ();
1784
1785         return(exists);
1786 }
1787
1788 /* If we don't have the info in /proc, check if the process that
1789  * opened this share info is still there (it's not a perfect method,
1790  * due to pid reuse)
1791  */
1792 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1793 {
1794 #if defined(__native_client__)
1795         g_assert_not_reached ();
1796 #else
1797         if (kill (share_info->opened_by_pid, 0) == -1 &&
1798             (errno == ESRCH ||
1799              errno == EPERM)) {
1800                 /* It's gone completely (or there's a new process
1801                  * owned by someone else) so mark this share info as
1802                  * dead
1803                  */
1804                 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1805
1806                 _wapi_free_share_info (share_info);
1807         }
1808 #endif
1809 }
1810
1811 #ifdef __linux__
1812 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1813  * question.  If there are none, reset the share info.
1814  *
1815  * This implementation is Linux-specific; legacy systems will have to
1816  * implement their own ways of finding out if a particular file is
1817  * open by a process.
1818  */
1819 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1820 {
1821         gboolean found = FALSE, proc_fds = FALSE;
1822         pid_t self = _wapi_getpid ();
1823         int pid;
1824         int thr_ret, i;
1825         
1826         /* Prevents entries from expiring under us if we remove this
1827          * one
1828          */
1829         thr_ret = _wapi_handle_lock_shared_handles ();
1830         g_assert (thr_ret == 0);
1831         
1832         /* Prevent new entries racing with us */
1833         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1834         g_assert (thr_ret == 0);
1835         
1836         /* If there is no /proc, there's nothing more we can do here */
1837         if (access ("/proc", F_OK) == -1) {
1838                 _wapi_handle_check_share_by_pid (share_info);
1839                 goto done;
1840         }
1841
1842         /* If there's another handle that thinks it owns this fd, then even
1843          * if the fd has been closed behind our back consider it still owned.
1844          * See bugs 75764 and 75891
1845          */
1846         for (i = 0; i < _wapi_fd_reserve; i++) {
1847                 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1848                         struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1849
1850                         if (i != fd &&
1851                                 handle->type == WAPI_HANDLE_FILE) {
1852                                 struct _WapiHandle_file *file_handle = &handle->u.file;
1853
1854                                 if (file_handle->share_info == share_info) {
1855                                         DEBUG ("%s: handle 0x%x has this file open!",
1856                                                            __func__, i);
1857
1858                                         goto done;
1859                                 }
1860                         }
1861                 }
1862         }
1863
1864         if (proc_fds == FALSE) {
1865                 _wapi_handle_check_share_by_pid (share_info);
1866         } else if (found == FALSE) {
1867                 /* Blank out this entry, as it is stale */
1868                 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1869
1870                 _wapi_free_share_info (share_info);
1871         }
1872
1873 done:
1874         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1875
1876         _wapi_handle_unlock_shared_handles ();
1877 }
1878 #else
1879 //
1880 // Other implementations (non-Linux)
1881 //
1882 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1883 {
1884         int thr_ret;
1885         
1886         /* Prevents entries from expiring under us if we remove this
1887          * one */
1888         thr_ret = _wapi_handle_lock_shared_handles ();
1889         g_assert (thr_ret == 0);
1890         
1891         /* Prevent new entries racing with us */
1892         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1893         g_assert (thr_ret == 0);
1894         
1895         _wapi_handle_check_share_by_pid (share_info);
1896
1897         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1898         _wapi_handle_unlock_shared_handles ();
1899 }
1900 #endif
1901
1902 void _wapi_handle_dump (void)
1903 {
1904         struct _WapiHandleUnshared *handle_data;
1905         guint32 i, k;
1906         int thr_ret;
1907         
1908         thr_ret = mono_mutex_lock (&scan_mutex);
1909         g_assert (thr_ret == 0);
1910         
1911         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1912                 if (_wapi_private_handles [i]) {
1913                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1914                                 handle_data = &_wapi_private_handles [i][k];
1915
1916                                 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1917                                         continue;
1918                                 }
1919                 
1920                                 g_print ("%3x [%7s] %s %d ",
1921                                                  i * _WAPI_HANDLE_INITIAL_COUNT + k,
1922                                                  _wapi_handle_typename[handle_data->type],
1923                                                  handle_data->signalled?"Sg":"Un",
1924                                                  handle_data->ref);
1925                                 handle_details[handle_data->type](&handle_data->u);
1926                                 g_print ("\n");
1927                         }
1928                 }
1929         }
1930
1931         thr_ret = mono_mutex_unlock (&scan_mutex);
1932         g_assert (thr_ret == 0);
1933 }
1934
1935 static void _wapi_shared_details (gpointer handle_info)
1936 {
1937         struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1938         
1939         g_print ("offset: 0x%x", shared->offset);
1940 }
1941
1942 void _wapi_handle_update_refs (void)
1943 {
1944         guint32 i, k;
1945         int thr_ret;
1946         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1947         
1948         thr_ret = _wapi_handle_lock_shared_handles ();
1949         g_assert (thr_ret == 0);
1950
1951         /* Prevent file share entries racing with us */
1952         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1953         g_assert(thr_ret == 0);
1954
1955         thr_ret = mono_mutex_lock (&scan_mutex);
1956         
1957         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1958                 if (_wapi_private_handles [i]) {
1959                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1960                                 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1961
1962                                 if (_WAPI_SHARED_HANDLE(handle->type)) {
1963                                         struct _WapiHandleShared *shared_data;
1964                                 
1965                                         DEBUG ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1966
1967                                         shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1968
1969                                         DEBUG ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
1970
1971                                         InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1972                                 } else if (handle->type == WAPI_HANDLE_FILE) {
1973                                         struct _WapiHandle_file *file_handle = &handle->u.file;
1974                                 
1975                                         DEBUG ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1976                                 
1977                                         g_assert (file_handle->share_info != NULL);
1978
1979                                         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));
1980
1981                                         InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
1982                                 }
1983                         }
1984                 }
1985         }
1986
1987         thr_ret = mono_mutex_unlock (&scan_mutex);
1988         g_assert (thr_ret == 0);
1989         
1990         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1991
1992         _wapi_handle_unlock_shared_handles ();
1993 }
1994