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