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