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