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