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