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