Revert until we track down the RH9 bug
[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 Ximian, 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 <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/un.h>
18 #include <sys/mman.h>
19
20 #include <mono/os/gc_wrapper.h>
21
22 #include <mono/io-layer/wapi.h>
23 #include <mono/io-layer/wapi-private.h>
24 #include <mono/io-layer/handles-private.h>
25 #include <mono/io-layer/mono-mutex.h>
26 #include <mono/io-layer/shared.h>
27 #include <mono/io-layer/misc-private.h>
28 #include <mono/io-layer/daemon-messages.h>
29
30 #undef DEBUG
31 #undef HEAVY_DEBUG /* This will print handle counts on every handle created */
32
33 /* Shared threads don't seem to work yet */
34 #undef _POSIX_THREAD_PROCESS_SHARED
35
36 /*
37  * This flag _MUST_ remain set to FALSE in the daemon process.  When
38  * we exec()d a standalone daemon, that happened because shared_init()
39  * didnt get called in the daemon process.  Now we just fork() without
40  * exec(), we need to ensure that the fork() happens when shared is
41  * still FALSE.
42  *
43  * This is further complicated by the second attempt to start the
44  * daemon if the connect() fails.
45  */
46 static gboolean shared=FALSE;
47
48 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
49 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
50         NULL,
51         &_wapi_file_ops,
52         &_wapi_console_ops,
53         &_wapi_thread_ops,
54         &_wapi_sem_ops,
55         &_wapi_mutex_ops,
56         &_wapi_event_ops,
57         &_wapi_socket_ops,
58         &_wapi_find_ops,
59         &_wapi_process_ops,
60         &_wapi_pipe_ops,
61 };
62
63 static int daemon_sock;
64
65 static pthread_mutexattr_t mutex_shared_attr;
66 static pthread_condattr_t cond_shared_attr;
67
68 struct _WapiHandleShared_list **_wapi_shared_data=NULL;
69 struct _WapiHandleScratch *_wapi_shared_scratch=NULL;
70 struct _WapiHandlePrivate_list **_wapi_private_data=NULL;
71 pthread_mutex_t _wapi_shared_mutex=PTHREAD_MUTEX_INITIALIZER;
72
73 /* This holds the length of the _wapi_shared_data and
74  * _wapi_private_data arrays, so we know if a segment is off the end
75  * of the array, requiring a realloc
76  */
77 guint32 _wapi_shm_mapped_segments;
78
79 static void shared_init (void)
80 {
81         struct sockaddr_un shared_socket_address;
82         gboolean tried_once=FALSE;
83         int ret;
84
85         _wapi_shared_data=g_new0 (struct _WapiHandleShared_list *, 1);
86         _wapi_private_data=g_new0 (struct _WapiHandlePrivate_list *, 1);
87         
88 attach_again:
89
90 #ifndef DISABLE_SHARED_HANDLES
91         if(getenv ("MONO_DISABLE_SHM"))
92 #endif
93         {
94                 shared=FALSE;
95 #ifndef DISABLE_SHARED_HANDLES
96         } else {
97                 /* Ensure that shared==FALSE while _wapi_shm_attach()
98                  * calls fork()
99                  */
100                 shared=FALSE;
101                 
102                 shared=_wapi_shm_attach (&_wapi_shared_data[0],
103                                          &_wapi_shared_scratch);
104                 if(shared==FALSE) {
105                         g_warning ("Failed to attach shared memory! "
106                                    "Falling back to non-shared handles");
107                 }
108 #endif /* DISABLE_SHARED_HANDLES */
109         }
110         
111
112         if(shared==TRUE) {
113                 daemon_sock=socket (PF_UNIX, SOCK_STREAM, 0);
114                 shared_socket_address.sun_family=AF_UNIX;
115                 memcpy (shared_socket_address.sun_path,
116                         _wapi_shared_data[0]->daemon, MONO_SIZEOF_SUNPATH);
117                 ret=connect (daemon_sock,
118                              (struct sockaddr *)&shared_socket_address,
119                              sizeof(struct sockaddr_un));
120                 if(ret==-1) {
121                         if(tried_once==TRUE) {
122                                 g_warning (G_GNUC_PRETTY_FUNCTION
123                                            ": connect to daemon failed: %s",
124                                            g_strerror (errno));
125                                 /* Fall back to private handles */
126                                 shared=FALSE;
127                         } else {
128                                 /* It's possible that the daemon
129                                  * crashed without destroying the
130                                  * shared memory segment (thus fooling
131                                  * subsequent processes into thinking
132                                  * the daemon is still active).
133                                  * 
134                                  * Destroy the shared memory segment
135                                  * and try once more.  This won't
136                                  * break running apps, but no new apps
137                                  * will be able to see the current
138                                  * shared memory segment.
139                                  */
140                                 tried_once=TRUE;
141                                 _wapi_shm_destroy ();
142                                 
143                                 goto attach_again;
144                         }
145                 }
146         }
147
148         if(shared==FALSE) {
149 #ifdef DEBUG
150                 g_message (G_GNUC_PRETTY_FUNCTION
151                            ": Using process-private handles");
152 #endif
153                 _wapi_shared_data[0]=g_new0 (struct _WapiHandleShared_list, 1);
154                 _wapi_shared_data[0]->num_segments=1;
155
156                 _wapi_shared_scratch=g_new0 (struct _WapiHandleScratch, 1);
157         }
158         _wapi_private_data[0]=g_new0 (struct _WapiHandlePrivate_list, 1);
159         _wapi_shm_mapped_segments=1;
160
161         pthread_mutexattr_init (&mutex_shared_attr);
162         pthread_condattr_init (&cond_shared_attr);
163
164 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
165         pthread_mutexattr_setpshared (&mutex_shared_attr,
166                                       PTHREAD_PROCESS_SHARED);
167         pthread_condattr_setpshared (&cond_shared_attr,
168                                      PTHREAD_PROCESS_SHARED);
169 #endif
170 }
171
172 #ifdef HEAVY_DEBUG
173 static void
174 print_handle_count (gint mask)
175 {
176         gint *count, num_handles;
177         gint i;
178         static const gchar *names [] = {"WAPI_HANDLE_UNUSED",
179                                   "WAPI_HANDLE_FILE",
180                                   "WAPI_HANDLE_CONSOLE",
181                                   "WAPI_HANDLE_THREAD",
182                                   "WAPI_HANDLE_SEM",
183                                   "WAPI_HANDLE_MUTEX",
184                                   "WAPI_HANDLE_EVENT",
185                                   "WAPI_HANDLE_SOCKET",
186                                   "WAPI_HANDLE_FIND",
187                                   "WAPI_HANDLE_PROCESS",
188                                   "WAPI_HANDLE_PIPE"
189                                 };
190
191
192         num_handles=_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT;
193         count=g_new0 (gint, num_handles);
194
195         for (i = 1; i < num_handles; i++) {
196                 struct _WapiHandleShared *shared;
197                 guint32 segment, idx;
198                 
199                 _wapi_handle_segment (GUINT_TO_POINTER (i), &segment, &idx);
200                 _wapi_handle_ensure_mapped (segment);
201                 
202                 shared = &_wapi_handle_get_shared_segment (segment)->handles[idx];
203                 count [shared->type]++;
204         }
205
206         for (i = 0; i < num_handles; i++)
207                 if ((i & mask) == i) /* Always prints the UNUSED count */
208                         g_print ("%s: %d\n", names [i], count [i]);
209
210         g_free (count);
211 }
212 #endif /* HEAVY_DEBUG */
213
214 /*
215  * _wapi_handle_new_internal:
216  * @type: Init handle to this type
217  *
218  * Search for a free handle and initialize it. Return the handle on
219  * success and 0 on failure.
220  */
221 guint32 _wapi_handle_new_internal (WapiHandleType type)
222 {
223         guint32 segment, idx;
224         guint32 i, j;
225         static guint32 last=1;
226         
227         /* A linear scan should be fast enough.  Start from the last
228          * allocation, assuming that handles are allocated more often
229          * than they're freed. Leave 0 (NULL) as a guard
230          */
231 #ifdef HEAVY_DEBUG
232         print_handle_count (0xFFF);
233 #endif
234 again:
235         _wapi_handle_segment (GUINT_TO_POINTER (last), &segment, &idx);
236         for(i=segment; i<_wapi_handle_get_shared_segment (0)->num_segments;
237             i++) {
238                 if(i!=segment) {
239                         idx=0;
240                 }
241                 
242                 for(j=idx; j<_WAPI_HANDLES_PER_SEGMENT; j++) {
243                         struct _WapiHandleShared *shared;
244                 
245                         /* Make sure we dont try and assign handle 0 */
246                         if (i==0 && j==0) {
247                                 continue;
248                         }
249                         
250                         shared=&_wapi_handle_get_shared_segment (i)->handles[j];
251                 
252                         if(shared->type==WAPI_HANDLE_UNUSED) {
253                                 last=(_wapi_handle_index (i, j)+1) % (_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT);
254                                 shared->type=type;
255                                 shared->signalled=FALSE;
256 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
257                                 mono_mutex_init (&shared.signal_mutex, &mutex_shared_attr);
258                                 pthread_cond_init (&shared.signal_cond, &cond_shared_attr);
259 #endif
260                                 
261                                 return(_wapi_handle_index (i, j));
262                         }
263                 }
264         }
265
266         if(last>1) {
267                 /* Try again from the beginning */
268                 last=1;
269                 goto again;
270         }
271
272         /* Will need a new segment.  The caller will sort it out */
273
274         return(0);
275 }
276
277 gpointer _wapi_handle_new (WapiHandleType type)
278 {
279         static mono_once_t shared_init_once = MONO_ONCE_INIT;
280         static pthread_mutex_t scan_mutex=PTHREAD_MUTEX_INITIALIZER;
281         guint32 handle_idx, idx, segment;
282         gpointer handle;
283         WapiHandleRequest new={0};
284         WapiHandleResponse new_resp={0};
285 #if HAVE_BOEHM_GC
286         gboolean tried_collect=FALSE;
287 #endif
288         
289         mono_once (&shared_init_once, shared_init);
290
291 again:
292         if(shared==TRUE) {
293                 new.type=WapiHandleRequestType_New;
294                 new.u.new.type=type;
295         
296                 _wapi_daemon_request_response (daemon_sock, &new, &new_resp);
297         
298                 if (new_resp.type==WapiHandleResponseType_New) {
299                         handle_idx=new_resp.u.new.handle;
300                 } else {
301                         g_warning (G_GNUC_PRETTY_FUNCTION
302                                    ": bogus daemon response, type %d",
303                                    new_resp.type);
304                         g_assert_not_reached ();
305                 }
306         } else {
307                 pthread_mutex_lock (&scan_mutex);
308                 handle_idx=_wapi_handle_new_internal (type);
309                 if(handle_idx==0) {
310                         /* Try and get a new segment, and have another go */
311                         segment=_wapi_handle_get_shared_segment (0)->num_segments;
312                         _wapi_handle_ensure_mapped (segment);
313                         
314                         if(_wapi_handle_get_shared_segment (segment)!=NULL) {
315                                 /* Got a new segment */
316                                 _wapi_handle_get_shared_segment (0)->num_segments++;
317                                 handle_idx=_wapi_handle_new_internal (type);
318                         } else {
319                                 /* Map failed.  Just return 0 meaning
320                                  * "out of handles"
321                                  */
322                         }
323                 }
324                 
325                 _wapi_handle_segment (GUINT_TO_POINTER (handle_idx), &segment, &idx);
326                 _wapi_handle_get_shared_segment (segment)->handles[idx].ref++;
327                 pthread_mutex_unlock (&scan_mutex);
328         }
329                 
330         if(handle_idx==0) {
331                 g_warning (G_GNUC_PRETTY_FUNCTION ": Ran out of handles!");
332
333 #if HAVE_BOEHM_GC
334                 /* See if we can reclaim some handles by forcing a GC
335                  * collection
336                  */
337                 if(tried_collect==FALSE) {
338                         g_warning (G_GNUC_PRETTY_FUNCTION
339                                    ": Seeing if GC collection helps...");
340                         GC_gcollect (); /* FIXME: we should wait for finalizers to be called */
341                         tried_collect=TRUE;
342                         goto again;
343                 } else {
344                         g_warning (G_GNUC_PRETTY_FUNCTION
345                                    ": didn't help, returning error");
346                 }
347 #endif
348         
349                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
350         }
351
352         _wapi_handle_segment (GUINT_TO_POINTER (handle_idx), &segment, &idx);
353         _wapi_handle_ensure_mapped (segment);
354
355         if(_wapi_private_data!=NULL) {
356                 _wapi_handle_get_private_segment (segment)->handles[idx].type=type;
357         }
358         
359 #if !defined(_POSIX_THREAD_PROCESS_SHARED) || _POSIX_THREAD_PROCESS_SHARED == -1
360         mono_mutex_init (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex, &mutex_shared_attr);
361         pthread_cond_init (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond, &cond_shared_attr);
362 #endif
363         handle=GUINT_TO_POINTER (handle_idx);
364
365 #ifdef DEBUG
366         g_message (G_GNUC_PRETTY_FUNCTION ": Allocated new handle %p", handle);
367 #endif
368         
369         return(handle);
370 }
371
372 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
373                               gpointer *shared, gpointer *private)
374 {
375         struct _WapiHandleShared *shared_handle_data;
376         struct _WapiHandlePrivate *private_handle_data;
377         guint32 idx;
378         guint32 segment;
379
380         _wapi_handle_segment (handle, &segment, &idx);
381         _wapi_handle_ensure_mapped (segment);
382         
383         shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
384
385         if(shared!=NULL) {
386                 *shared=&shared_handle_data->u;
387         }
388         
389         if(private!=NULL) {
390                 private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
391
392                 *private=&private_handle_data->u;
393         }
394
395         if(shared_handle_data->type!=type) {
396                 /* If shared type is UNUSED, see if the private type
397                  * matches what we are looking for - this can happen
398                  * when the handle is being destroyed and the
399                  * close_private function is looking up the private
400                  * data
401                  */
402                 if(shared_handle_data->type==WAPI_HANDLE_UNUSED &&
403                    (private!=NULL && private_handle_data->type==type)) {
404                         return(TRUE);
405                 } else {
406                         return(FALSE);
407                 }
408         }
409         
410         return(TRUE);
411 }
412
413 gpointer _wapi_search_handle (WapiHandleType type,
414                               gboolean (*check)(gpointer test, gpointer user),
415                               gpointer user_data,
416                               gpointer *shared, gpointer *private)
417 {
418         struct _WapiHandleShared *shared_handle_data;
419         struct _WapiHandlePrivate *private_handle_data;
420         guint32 i, segment, idx;
421
422         for(i=1; i<_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT; i++) {
423                 struct _WapiHandleShared *shared;
424                 
425                 _wapi_handle_segment (GUINT_TO_POINTER (i), &segment, &idx);
426                 _wapi_handle_ensure_mapped (segment);
427                 
428                 shared=&_wapi_handle_get_shared_segment (segment)->handles[idx];
429                 
430                 if(shared->type==type) {
431                         if(check (GUINT_TO_POINTER (i), user_data)==TRUE) {
432                                 break;
433                         }
434                 }
435         }
436
437         if(i==_wapi_handle_get_shared_segment (0)->num_segments * _WAPI_HANDLES_PER_SEGMENT) {
438                 return(GUINT_TO_POINTER (0));
439         }
440         
441         if(shared!=NULL) {
442                 shared_handle_data=&_wapi_handle_get_shared_segment (segment)->handles[idx];
443
444                 *shared=&shared_handle_data->u;
445         }
446         
447         if(private!=NULL) {
448                 private_handle_data=&_wapi_handle_get_private_segment (segment)->handles[idx];
449
450                 *private=&private_handle_data->u;
451         }
452         
453         return(GUINT_TO_POINTER (i));
454 }
455
456 void _wapi_handle_ref (gpointer handle)
457 {
458         if(shared==TRUE) {
459                 WapiHandleRequest req={0};
460                 WapiHandleResponse resp={0};
461         
462                 req.type=WapiHandleRequestType_Open;
463                 req.u.open.handle=GPOINTER_TO_UINT (handle);
464         
465                 _wapi_daemon_request_response (daemon_sock, &req, &resp);
466                 if(resp.type!=WapiHandleResponseType_Open) {
467                         g_warning (G_GNUC_PRETTY_FUNCTION
468                                    ": bogus daemon response, type %d",
469                                    resp.type);
470                         g_assert_not_reached ();
471                 }
472         } else {
473                 guint32 idx, segment;
474
475                 _wapi_handle_segment (handle, &segment, &idx);
476                 
477                 _wapi_handle_get_shared_segment (segment)->handles[idx].ref++;
478         
479 #ifdef DEBUG
480                 g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d",
481                            handle,
482                            _wapi_handle_get_shared_segment (segment)->handles[idx].ref);
483 #endif
484         }
485 }
486
487 void _wapi_handle_unref (gpointer handle)
488 {
489         guint32 idx, segment;
490         gboolean destroy;
491
492         _wapi_handle_segment (handle, &segment, &idx);
493         
494         if(shared==TRUE) {
495                 WapiHandleRequest req={0};
496                 WapiHandleResponse resp={0};
497         
498                 req.type=WapiHandleRequestType_Close;
499                 req.u.close.handle=GPOINTER_TO_UINT (handle);
500         
501                 _wapi_daemon_request_response (daemon_sock, &req, &resp);
502                 if(resp.type!=WapiHandleResponseType_Close) {
503                         g_warning (G_GNUC_PRETTY_FUNCTION
504                                    ": bogus daemon response, type %d",
505                                    resp.type);
506                         g_assert_not_reached ();
507                 } else {
508                         destroy=resp.u.close.destroy;
509                 }
510         } else {
511                 _wapi_handle_get_shared_segment (segment)->handles[idx].ref--;
512         
513 #ifdef DEBUG
514                 g_message (G_GNUC_PRETTY_FUNCTION ": handle %p ref now %d", handle, _wapi_handle_get_shared_segment (segment)->handles[idx].ref);
515 #endif
516
517                 /* Possible race condition here if another thread refs
518                  * the handle between here and setting the type to
519                  * UNUSED.  I could lock a mutex, but I'm not sure
520                  * that allowing a handle reference to reach 0 isn't
521                  * an application bug anyway.
522                  */
523                 destroy=(_wapi_handle_get_shared_segment (segment)->handles[idx].ref==0);
524         }
525
526         if(destroy==TRUE) {
527 #ifdef DEBUG
528                 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle %p",
529                            handle);
530 #endif
531                 
532                 if(shared==FALSE) {
533                         _wapi_handle_ops_close_shared (handle);
534
535                         mono_mutex_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
536                         pthread_cond_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond);
537                         memset (&_wapi_handle_get_shared_segment (segment)->handles[idx].u, '\0', sizeof(_wapi_handle_get_shared_segment (segment)->handles[idx].u));
538                 
539                 }
540 #if !defined(_POSIX_THREAD_PROCESS_SHARED) || _POSIX_THREAD_PROCESS_SHARED == -1
541                 else {
542                         mono_mutex_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
543                         pthread_cond_destroy (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond);
544                 }
545 #endif
546
547                 _wapi_handle_ops_close_private (handle);
548                 _wapi_handle_get_shared_segment (segment)->handles[idx].type=WAPI_HANDLE_UNUSED;
549         }
550 }
551
552 #define HDRSIZE sizeof(struct _WapiScratchHeader)
553
554 static pthread_mutex_t _wapi_scratch_mutex=PTHREAD_MUTEX_INITIALIZER;
555
556 /* _wapi_scratch_mutex must be held when this function is called in
557  * the non-shared case
558  */
559 static void _wapi_handle_scratch_expand (void)
560 {
561         guint32 old_len, new_len;
562                 
563         old_len=sizeof(struct _WapiHandleScratch) +
564                 _wapi_shared_scratch->data_len;
565         new_len=old_len+_WAPI_SHM_SCRATCH_SIZE;
566                 
567         if(_wapi_shared_scratch->is_shared==TRUE) {
568                 /* expand via mmap() */
569                 _wapi_shared_scratch=_wapi_shm_file_expand (_wapi_shared_scratch, WAPI_SHM_SCRATCH, 0, old_len, new_len);
570         } else {
571                 _wapi_shared_scratch=_wapi_g_renew0 (_wapi_shared_scratch, old_len, new_len);
572         }
573         _wapi_shared_scratch->data_len+=_WAPI_SHM_SCRATCH_SIZE;
574 }
575
576 /* _wapi_scratch_mutex must be held when this function is called in
577  * the non-shared case
578  */
579 static guint32 _wapi_handle_scratch_locate_space (guint32 bytes)
580 {
581         guint32 idx=0, last_idx=0;
582         struct _WapiScratchHeader *hdr, *last_hdr;
583         gboolean last_was_free=FALSE;
584         guchar *storage=_wapi_shared_scratch->scratch_data;
585         
586 #ifdef DEBUG
587         g_message (G_GNUC_PRETTY_FUNCTION
588                    ": looking for %d bytes of scratch space (%d bytes total)",
589                    bytes, _wapi_shared_scratch->data_len);
590 #endif
591         
592         while(idx< _wapi_shared_scratch->data_len) {
593                 hdr=(struct _WapiScratchHeader *)&storage[idx];
594                 
595                 /* Do a simple first-fit allocation, coalescing
596                  * adjacent free blocks as we progress through the
597                  * scratch space
598                  */
599                 if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
600                    hdr->length >= bytes + HDRSIZE) {
601                         /* found space */
602                         guint32 old_length=hdr->length;
603 #ifdef DEBUG
604                         g_message (G_GNUC_PRETTY_FUNCTION ": found suitable free size at %d, length %d", idx, hdr->length);
605 #endif
606
607                         hdr->flags &= ~WAPI_SHM_SCRATCH_FREE;
608                         hdr->length=bytes;
609                         idx += HDRSIZE;
610
611                         /* Put a new header in at the end of the used
612                          * space
613                          */
614                         hdr=(struct _WapiScratchHeader *)&storage[idx+bytes];
615                         hdr->flags |= WAPI_SHM_SCRATCH_FREE;
616                         hdr->length = old_length-bytes-HDRSIZE;
617
618 #ifdef DEBUG
619                         g_message (G_GNUC_PRETTY_FUNCTION ": new header at %d, length %d", idx+bytes, hdr->length);
620 #endif
621                         
622                         /*
623                          * It was memset(0..) when free/made so no need to do it here
624                          */
625
626                         return(idx);
627                 } else if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
628                           last_was_free == FALSE) {
629 #ifdef DEBUG
630                         g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous used)", idx, hdr->length);
631 #endif
632
633                         /* save this point in case we can coalesce it with
634                          * the next block, if that is free.
635                          */
636                         last_was_free=TRUE;
637                         last_idx=idx;
638                         last_hdr=hdr;
639                         idx+=(hdr->length+HDRSIZE);
640                 } else if (hdr->flags & WAPI_SHM_SCRATCH_FREE &&
641                            last_was_free == TRUE) {
642 #ifdef DEBUG
643                         g_message (G_GNUC_PRETTY_FUNCTION ": found too-small free block at %d, length %d (previous free)", idx, hdr->length);
644 #endif
645
646                         /* This block and the previous are both free,
647                          * so coalesce them
648                          */
649                         last_hdr->length += (hdr->length + HDRSIZE);
650
651                         /* If the new block is now big enough, use it
652                          * (next time round the loop)
653                          */
654                         if(last_hdr->length >= bytes + HDRSIZE) {
655                                 idx=last_idx;
656                         } else {
657                                 /* leave the last free info as it is,
658                                  * in case the next block is also free
659                                  * and can be coalesced too
660                                  */
661                                 idx=last_idx+last_hdr->length+HDRSIZE;
662                         }
663                 } else {
664 #ifdef DEBUG
665                         g_message (G_GNUC_PRETTY_FUNCTION
666                                    ": found used block at %d, length %d", idx,
667                                    hdr->length);
668 #endif
669
670                         /* must be used, try next chunk */
671                         idx+=(hdr->length+HDRSIZE);
672
673                         /* Don't let the coalescing blow away this block */
674                         last_was_free=FALSE;
675
676                         /* But remember where the last block started */
677                         last_idx=idx;
678                 }
679         }
680
681         /* Not enough free space.  last_idx points to the last block.
682          * If it's free, just tack on more space and update the
683          * length.  If it's allocated, it must have fit right into the
684          * available space, so add more space and add a new header
685          * after this block.
686          */
687         _wapi_handle_scratch_expand ();
688         storage=_wapi_shared_scratch->scratch_data;
689         
690         hdr=(struct _WapiScratchHeader *)&storage[last_idx];
691         if(hdr->flags & WAPI_SHM_SCRATCH_FREE) {
692                 hdr->length+=_WAPI_SHM_SCRATCH_SIZE;
693         } else {
694                 idx=(hdr->length+HDRSIZE);
695                 hdr=(struct _WapiScratchHeader *)&storage[idx];
696                 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
697                 hdr->length = _WAPI_SHM_SCRATCH_SIZE-HDRSIZE;
698         }
699
700         /* The caller will try again */
701         return(0);
702 }
703
704 /*
705  * _wapi_handle_scratch_store_internal:
706  * @bytes: Allocate no. bytes
707  *
708  * Like malloc(3) except its for the shared memory segment's scratch
709  * part. Memory block returned is zeroed out.
710  */
711 guint32 _wapi_handle_scratch_store_internal (guint32 bytes, gboolean *remap)
712 {
713         guchar *storage;
714         guint32 idx;
715         struct _WapiScratchHeader *hdr;
716
717 #ifdef DEBUG
718         g_message (G_GNUC_PRETTY_FUNCTION ": storing %d bytes", bytes);
719 #endif
720         
721         *remap=FALSE;
722         
723         if(_wapi_shared_scratch->data_len==0) {
724                 /* Need to expand the data array for the first use */
725 #ifdef DEBUG
726                 g_message (G_GNUC_PRETTY_FUNCTION
727                            ": setting up scratch space");
728 #endif
729
730                 _wapi_handle_scratch_expand ();
731                 *remap=TRUE;
732         }
733
734         storage=_wapi_shared_scratch->scratch_data;
735         hdr=(struct _WapiScratchHeader *)&storage[0];
736         if(hdr->flags==0 && hdr->length==0) {
737                 /* Need to initialise scratch data */
738                 hdr->flags |= WAPI_SHM_SCRATCH_FREE;
739                 hdr->length = _wapi_shared_scratch->data_len - HDRSIZE;
740         }
741
742         idx=_wapi_handle_scratch_locate_space (bytes);
743         if(idx==0) {
744                 /* Some more space will have been allocated, so try again */
745 #ifdef DEBUG
746                 g_message (G_GNUC_PRETTY_FUNCTION ": trying again");
747 #endif
748
749                 idx=_wapi_handle_scratch_locate_space (bytes);
750                 *remap=TRUE;
751         }
752         
753         return(idx);
754 }
755
756 guint32 _wapi_handle_scratch_store (gconstpointer data, guint32 bytes)
757 {
758         guint32 idx, store_bytes;
759         gboolean remap;
760
761 #ifdef DEBUG
762         g_message (G_GNUC_PRETTY_FUNCTION ": storing %d bytes", bytes);
763 #endif
764
765         /* No point storing no data */
766         if(bytes==0) {
767                 return(0);
768         }
769
770         /* Align bytes to 32 bits (needed for sparc at least) */
771         store_bytes = (((bytes) + 3) & (~3));
772
773         pthread_mutex_lock (&_wapi_scratch_mutex);
774
775         if(shared==TRUE) {
776                 WapiHandleRequest scratch={0};
777                 WapiHandleResponse scratch_resp={0};
778                 guint32 old_len=sizeof(struct _WapiHandleScratch) +
779                         _wapi_shared_scratch->data_len;
780                 
781                 scratch.type=WapiHandleRequestType_Scratch;
782                 scratch.u.scratch.length=store_bytes;
783         
784                 _wapi_daemon_request_response (daemon_sock, &scratch,
785                                                &scratch_resp);
786         
787                 if(scratch_resp.type==WapiHandleResponseType_Scratch) {
788                         idx=scratch_resp.u.scratch.idx;
789                         remap=scratch_resp.u.scratch.remap;
790                 } else {
791                         g_warning (G_GNUC_PRETTY_FUNCTION
792                                    ": bogus daemon response, type %d",
793                                    scratch_resp.type);
794                         g_assert_not_reached ();
795                 }
796         
797                 if(remap==TRUE) {
798                         munmap (_wapi_shared_scratch, old_len);
799                         _wapi_shared_scratch=_wapi_shm_file_map (WAPI_SHM_SCRATCH, 0, NULL);
800                 }
801         } else {
802                 idx=_wapi_handle_scratch_store_internal (store_bytes, &remap);
803                 if(idx==0) {
804                         /* Failed to allocate space */
805                         pthread_mutex_unlock (&_wapi_scratch_mutex);
806                         return(0);
807                 }
808         }
809
810 #ifdef DEBUG
811         g_message (G_GNUC_PRETTY_FUNCTION
812                    ": stored [%s] at %d (len %d, aligned len %d)",
813                    (char *)data, idx, bytes, store_bytes);
814 #endif
815         
816         memcpy (&_wapi_shared_scratch->scratch_data[idx], data, bytes);
817
818         pthread_mutex_unlock (&_wapi_scratch_mutex);
819         
820         return(idx);
821 }
822
823 guint32 _wapi_handle_scratch_store_string_array (gchar **data)
824 {
825         guint32 *stored_strings, count=0, i, idx;
826         gchar **strings;
827         
828         /* No point storing no data */
829         if(data==NULL) {
830                 return(0);
831         }
832
833         strings=data;
834         while(*strings!=NULL) {
835                 count++;
836                 strings++;
837         }
838         
839 #ifdef DEBUG
840         g_message (G_GNUC_PRETTY_FUNCTION ": %d strings to store", count);
841 #endif
842         
843         if(count==0) {
844                 return(0);
845         }
846
847         /* stored_strings[0] is the count */
848         stored_strings=g_new0 (guint32, count+1);
849         stored_strings[0]=count;
850         
851         strings=data;
852         for(i=0; i<count; i++) {
853                 stored_strings[i+1]=_wapi_handle_scratch_store (strings[i], strlen (strings[i]));
854         }
855
856         idx=_wapi_handle_scratch_store (stored_strings,
857                                         sizeof(guint32)*(count+1));
858         
859         return(idx);
860 }
861
862 gpointer _wapi_handle_scratch_lookup (guint32 idx)
863 {
864         struct _WapiScratchHeader *hdr;
865         gpointer ret;
866         guchar *storage;
867         
868         if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
869                 return(NULL);
870         }
871
872         pthread_mutex_lock (&_wapi_scratch_mutex);
873         
874         storage=_wapi_shared_scratch->scratch_data;
875         
876         hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
877         ret=g_malloc0 (hdr->length+1);
878         memcpy (ret, &storage[idx], hdr->length);
879
880         pthread_mutex_unlock (&_wapi_scratch_mutex);
881
882         return(ret);
883 }
884
885 gchar **_wapi_handle_scratch_lookup_string_array (guint32 idx)
886 {
887         gchar **strings;
888         guint32 *stored_strings;
889         guint32 count, i;
890         
891         if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
892                 return(NULL);
893         }
894
895         stored_strings=_wapi_handle_scratch_lookup (idx);
896         if(stored_strings==NULL) {
897                 return(NULL);
898         }
899         
900         /* stored_strings[0] is the number of strings, the index of
901          * each string follows
902          */
903         count=stored_strings[0];
904         
905 #ifdef DEBUG
906         g_message (G_GNUC_PRETTY_FUNCTION
907                    ": looking up an array of %d strings", count);
908 #endif
909         
910         /* NULL-terminate the array */
911         strings=g_new0 (gchar *, count+1);
912         
913         for(i=0; i<count; i++) {
914                 strings[i]=_wapi_handle_scratch_lookup (stored_strings[i+1]);
915
916 #ifdef DEBUG
917                 g_message (G_GNUC_PRETTY_FUNCTION ": string %d is [%s]", i,
918                            strings[i]);
919 #endif
920         }
921
922         g_free (stored_strings);
923         
924         return(strings);
925 }
926
927 /*
928  * _wapi_handle_scratch_delete_internal:
929  * @idx: Index to free block
930  *
931  * Like free(3) except its for the shared memory segment's scratch
932  * part.
933  */
934 void _wapi_handle_scratch_delete_internal (guint32 idx)
935 {
936         struct _WapiScratchHeader *hdr;
937         guchar *storage;
938         
939         if(idx < HDRSIZE || idx > _wapi_shared_scratch->data_len) {
940                 return;
941         }
942
943         pthread_mutex_lock (&_wapi_scratch_mutex);
944         
945         storage=_wapi_shared_scratch->scratch_data;
946         
947         hdr=(struct _WapiScratchHeader *)&storage[idx - HDRSIZE];
948         memset (&storage[idx], '\0', hdr->length);
949         hdr->flags |= WAPI_SHM_SCRATCH_FREE;
950         
951         /* We could coalesce forwards here if the next block is also
952          * free, but the _store() function will do that anyway.
953          */
954
955         pthread_mutex_unlock (&_wapi_scratch_mutex);
956 }
957
958 void _wapi_handle_scratch_delete (guint32 idx)
959 {
960         if(shared==TRUE) {
961                 WapiHandleRequest scratch_free={0};
962                 WapiHandleResponse scratch_free_resp={0};
963         
964                 scratch_free.type=WapiHandleRequestType_ScratchFree;
965                 scratch_free.u.scratch_free.idx=idx;
966         
967                 _wapi_daemon_request_response (daemon_sock, &scratch_free,
968                                                &scratch_free_resp);
969         
970                 if(scratch_free_resp.type!=WapiHandleResponseType_ScratchFree) {
971                         g_warning (G_GNUC_PRETTY_FUNCTION
972                                    ": bogus daemon response, type %d",
973                                    scratch_free_resp.type);
974                         g_assert_not_reached ();
975                 }
976         } else {
977                 _wapi_handle_scratch_delete_internal (idx);
978         }
979 }
980
981 void _wapi_handle_scratch_delete_string_array (guint32 idx)
982 {
983         guint32 *stored_strings;
984         guint32 count, i;
985         
986         stored_strings=_wapi_handle_scratch_lookup (idx);
987         if(stored_strings==NULL) {
988                 return;
989         }
990         
991         /* stored_strings[0] is the number of strings, the index of
992          * each string follows
993          */
994         count=stored_strings[0];
995         
996 #ifdef DEBUG
997         g_message (G_GNUC_PRETTY_FUNCTION ": deleting an array of %d strings",
998                    count);
999 #endif
1000         
1001         for(i=1; i<count; i++) {
1002                 _wapi_handle_scratch_delete (stored_strings[i]);
1003         }
1004         
1005         _wapi_handle_scratch_delete (idx);
1006
1007         g_free (stored_strings);
1008 }
1009
1010 void _wapi_handle_register_capabilities (WapiHandleType type,
1011                                          WapiHandleCapability caps)
1012 {
1013         handle_caps[type]=caps;
1014 }
1015
1016 gboolean _wapi_handle_test_capabilities (gpointer handle,
1017                                          WapiHandleCapability caps)
1018 {
1019         guint32 idx, segment;
1020         WapiHandleType type;
1021
1022         _wapi_handle_segment (handle, &segment, &idx);
1023         
1024         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1025
1026 #ifdef DEBUG
1027         g_message (G_GNUC_PRETTY_FUNCTION ": testing 0x%x against 0x%x (%d)",
1028                    handle_caps[type], caps, handle_caps[type] & caps);
1029 #endif
1030         
1031         return((handle_caps[type] & caps)!=0);
1032 }
1033
1034 void _wapi_handle_ops_close_shared (gpointer handle)
1035 {
1036         guint32 idx, segment;
1037         WapiHandleType type;
1038
1039         _wapi_handle_segment (handle, &segment, &idx);
1040         
1041         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1042
1043         if(handle_ops[type]!=NULL && handle_ops[type]->close_shared!=NULL) {
1044                 handle_ops[type]->close_shared (handle);
1045         }
1046 }
1047
1048 void _wapi_handle_ops_close_private (gpointer handle)
1049 {
1050         guint32 idx, segment;
1051         WapiHandleType type;
1052
1053         _wapi_handle_segment (handle, &segment, &idx);
1054
1055         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1056
1057         /* When a handle in the process of being destroyed the shared
1058          * type has already been set to UNUSED
1059          */
1060         if(type==WAPI_HANDLE_UNUSED && _wapi_private_data!=NULL) {
1061                 type=_wapi_handle_get_private_segment (segment)->handles[idx].type;
1062         }
1063
1064         if(handle_ops[type]!=NULL && handle_ops[type]->close_private!=NULL) {
1065                 handle_ops[type]->close_private (handle);
1066         }
1067 }
1068
1069 void _wapi_handle_ops_signal (gpointer handle)
1070 {
1071         guint32 idx, segment;
1072         WapiHandleType type;
1073
1074         _wapi_handle_segment (handle, &segment, &idx);
1075
1076         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1077
1078         if(handle_ops[type]!=NULL && handle_ops[type]->signal!=NULL) {
1079                 handle_ops[type]->signal (handle);
1080         }
1081 }
1082
1083 void _wapi_handle_ops_own (gpointer handle)
1084 {
1085         guint32 idx, segment;
1086         WapiHandleType type;
1087
1088         _wapi_handle_segment (handle, &segment, &idx);
1089         
1090         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1091
1092         if(handle_ops[type]!=NULL && handle_ops[type]->own_handle!=NULL) {
1093                 handle_ops[type]->own_handle (handle);
1094         }
1095 }
1096
1097 gboolean _wapi_handle_ops_isowned (gpointer handle)
1098 {
1099         guint32 idx, segment;
1100         WapiHandleType type;
1101
1102         _wapi_handle_segment (handle, &segment, &idx);
1103         
1104         type=_wapi_handle_get_shared_segment (segment)->handles[idx].type;
1105
1106         if(handle_ops[type]!=NULL && handle_ops[type]->is_owned!=NULL) {
1107                 return(handle_ops[type]->is_owned (handle));
1108         } else {
1109                 return(FALSE);
1110         }
1111 }
1112
1113 /**
1114  * CloseHandle:
1115  * @handle: The handle to release
1116  *
1117  * Closes and invalidates @handle, releasing any resources it
1118  * consumes.  When the last handle to a temporary or non-persistent
1119  * object is closed, that object can be deleted.  Closing the same
1120  * handle twice is an error.
1121  *
1122  * Return value: %TRUE on success, %FALSE otherwise.
1123  */
1124 gboolean CloseHandle(gpointer handle)
1125 {
1126         _wapi_handle_unref (handle);
1127         
1128         return(TRUE);
1129 }
1130
1131 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1132                                                gpointer *handles,
1133                                                gboolean waitall,
1134                                                guint32 *retcount,
1135                                                guint32 *lowest)
1136 {
1137         guint32 count, i, iter=0;
1138         gboolean ret;
1139         
1140         /* Lock all the handles, with backoff */
1141 again:
1142         for(i=0; i<numhandles; i++) {
1143                 guint32 idx, segment;
1144                 
1145                 _wapi_handle_segment (handles[i], &segment, &idx);
1146                 
1147 #ifdef DEBUG
1148                 g_message (G_GNUC_PRETTY_FUNCTION ": attempting to lock %p",
1149                            handles[i]);
1150 #endif
1151
1152                 ret=mono_mutex_trylock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
1153                 if(ret!=0) {
1154                         /* Bummer */
1155                         struct timespec sleepytime;
1156                         
1157 #ifdef DEBUG
1158                         g_message (G_GNUC_PRETTY_FUNCTION ": attempt failed for %p", handles[i]);
1159 #endif
1160
1161                         while(i--) {
1162                                 _wapi_handle_segment (handles[i], &segment, &idx);
1163                                 mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
1164                         }
1165
1166                         /* If iter ever reaches 100 the nanosleep will
1167                          * return EINVAL immediately, but we have a
1168                          * design flaw if that happens.
1169                          */
1170                         iter++;
1171                         if(iter==100) {
1172                                 g_warning (G_GNUC_PRETTY_FUNCTION
1173                                            ": iteration overflow!");
1174                                 iter=1;
1175                         }
1176                         
1177                         sleepytime.tv_sec=0;
1178                         sleepytime.tv_nsec=10000000 * iter;     /* 10ms*iter */
1179                         
1180 #ifdef DEBUG
1181                         g_message (G_GNUC_PRETTY_FUNCTION
1182                                    ": Backing off for %d ms", iter*10);
1183 #endif
1184                         nanosleep (&sleepytime, NULL);
1185                         
1186                         goto again;
1187                 }
1188         }
1189         
1190 #ifdef DEBUG
1191         g_message (G_GNUC_PRETTY_FUNCTION ": Locked all handles");
1192 #endif
1193
1194         count=0;
1195         *lowest=numhandles;
1196         
1197         for(i=0; i<numhandles; i++) {
1198                 guint32 idx, segment;
1199
1200                 _wapi_handle_segment (handles[i], &segment, &idx);
1201                 
1202 #ifdef DEBUG
1203                 g_message (G_GNUC_PRETTY_FUNCTION ": Checking handle %p",
1204                            handles[i]);
1205 #endif
1206
1207                 if(((_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_OWN)==TRUE) &&
1208                     (_wapi_handle_ops_isowned (handles[i])==TRUE)) ||
1209                    (_wapi_handle_get_shared_segment (segment)->handles[idx].signalled==TRUE)) {
1210                         count++;
1211                         
1212 #ifdef DEBUG
1213                         g_message (G_GNUC_PRETTY_FUNCTION
1214                                    ": Handle %p signalled", handles[i]);
1215 #endif
1216                         if(*lowest>i) {
1217                                 *lowest=i;
1218                         }
1219                 }
1220         }
1221         
1222 #ifdef DEBUG
1223         g_message (G_GNUC_PRETTY_FUNCTION ": %d event handles signalled",
1224                    count);
1225 #endif
1226
1227         if((waitall==TRUE && count==numhandles) ||
1228            (waitall==FALSE && count>0)) {
1229                 ret=TRUE;
1230         } else {
1231                 ret=FALSE;
1232         }
1233         
1234 #ifdef DEBUG
1235         g_message (G_GNUC_PRETTY_FUNCTION ": Returning %d", ret);
1236 #endif
1237
1238         *retcount=count;
1239         
1240         return(ret);
1241 }
1242
1243 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1244 {
1245         guint32 i;
1246         
1247         for(i=0; i<numhandles; i++) {
1248                 guint32 idx, segment;
1249
1250                 _wapi_handle_segment (handles[i], &segment, &idx);
1251
1252 #ifdef DEBUG
1253                 g_message (G_GNUC_PRETTY_FUNCTION ": unlocking handle %p",
1254                            handles[i]);
1255 #endif
1256
1257                 mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex);
1258         }
1259 }
1260
1261 /* Process-shared handles (currently only process and thread handles
1262  * are allowed, and they only work because once signalled they can't
1263  * become unsignalled) are waited for by one process and signalled by
1264  * another.  Without process-shared conditions, the waiting process
1265  * will block forever.  To get around this, the four handle waiting
1266  * functions use a short timeout when _POSIX_THREAD_PROCESS_SHARED is
1267  * not available.  They also return "success" if the fake timeout
1268  * expired, and let the caller check signal status.
1269  */
1270 int _wapi_handle_wait_signal (void)
1271 {
1272 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1273         return(mono_cond_wait (&_wapi_handle_get_shared_segment (0)->signal_cond,
1274                                &_wapi_handle_get_shared_segment (0)->signal_mutex));
1275 #else
1276         struct timespec fake_timeout;
1277         int ret;
1278         
1279         _wapi_calc_timeout (&fake_timeout, 100);
1280
1281         ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
1282                                  &_wapi_handle_get_private_segment (0)->signal_mutex,
1283                                  &fake_timeout);
1284         if(ret==ETIMEDOUT) {
1285                 ret=0;
1286         }
1287
1288         return(ret);
1289 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1290 }
1291
1292 int _wapi_handle_timedwait_signal (struct timespec *timeout)
1293 {
1294 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1295         return(mono_cond_timedwait (&_wapi_handle_get_shared_segment (0)->signal_cond,
1296                                     &_wapi_handle_get_shared_segment (0)->signal_mutex,
1297                                     timeout));
1298 #else
1299         struct timespec fake_timeout;
1300         int ret;
1301         
1302         _wapi_calc_timeout (&fake_timeout, 100);
1303         
1304         if((fake_timeout.tv_sec>timeout->tv_sec) ||
1305            (fake_timeout.tv_sec==timeout->tv_sec &&
1306             fake_timeout.tv_nsec > timeout->tv_nsec)) {
1307                 /* Real timeout is less than 100ms time */
1308                 ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
1309                                          &_wapi_handle_get_private_segment (0)->signal_mutex,
1310                                          timeout);
1311         } else {
1312                 ret=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond,
1313                                          &_wapi_handle_get_private_segment (0)->signal_mutex,
1314                                          &fake_timeout);
1315                 if(ret==ETIMEDOUT) {
1316                         ret=0;
1317                 }
1318         }
1319         
1320         return(ret);
1321 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1322 }
1323
1324 int _wapi_handle_wait_signal_handle (gpointer handle)
1325 {
1326 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1327         guint32 idx, segment;
1328
1329         _wapi_handle_segment (handle, &segment, &idx);
1330         
1331         return(mono_cond_wait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1332                                &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex));
1333 #else
1334         guint32 idx, segment;
1335         struct timespec fake_timeout;
1336         int ret;
1337         
1338         _wapi_handle_segment (handle, &segment, &idx);
1339         _wapi_calc_timeout (&fake_timeout, 100);
1340         
1341         ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1342                                  &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1343                                  &fake_timeout);
1344         if(ret==ETIMEDOUT) {
1345                 ret=0;
1346         }
1347
1348         return(ret);
1349 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1350 }
1351
1352 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1353                                           struct timespec *timeout)
1354 {
1355 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1356         guint32 idx, segment;
1357
1358         _wapi_handle_segment (handle, &segment, &idx);
1359         
1360         return(mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1361                                     &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1362                                     timeout));
1363 #else
1364         guint32 idx, segment;
1365         struct timespec fake_timeout;
1366         int ret;
1367         
1368         _wapi_handle_segment (handle, &segment, &idx);
1369         _wapi_calc_timeout (&fake_timeout, 100);
1370         
1371         if((fake_timeout.tv_sec>timeout->tv_sec) ||
1372            (fake_timeout.tv_sec==timeout->tv_sec &&
1373             fake_timeout.tv_nsec > timeout->tv_nsec)) {
1374                 /* Real timeout is less than 100ms time */
1375                 ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1376                                          &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1377                                          timeout);
1378         } else {
1379                 ret=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment)->handles[idx].signal_cond,
1380                                          &_wapi_handle_get_shared_segment (segment)->handles[idx].signal_mutex,
1381                                          &fake_timeout);
1382                 if(ret==ETIMEDOUT) {
1383                         ret=0;
1384                 }
1385         }
1386         
1387         return(ret);
1388 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1389 }
1390
1391 gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env, guint32 dir,
1392                                     gboolean inherit, guint32 flags,
1393                                     gpointer stdin_handle,
1394                                     gpointer stdout_handle,
1395                                     gpointer stderr_handle,
1396                                     gpointer *process_handle,
1397                                     gpointer *thread_handle, guint32 *pid,
1398                                     guint32 *tid)
1399 {
1400         WapiHandleRequest fork_proc={0};
1401         WapiHandleResponse fork_proc_resp={0};
1402         int in_fd, out_fd, err_fd;
1403         
1404         if(shared!=TRUE) {
1405                 return(FALSE);
1406         }
1407
1408         fork_proc.type=WapiHandleRequestType_ProcessFork;
1409         fork_proc.u.process_fork.cmd=cmd;
1410         fork_proc.u.process_fork.env=env;
1411         fork_proc.u.process_fork.dir=dir;
1412         fork_proc.u.process_fork.stdin_handle=GPOINTER_TO_UINT (stdin_handle);
1413         fork_proc.u.process_fork.stdout_handle=GPOINTER_TO_UINT (stdout_handle);
1414         fork_proc.u.process_fork.stderr_handle=GPOINTER_TO_UINT (stderr_handle);
1415         fork_proc.u.process_fork.inherit=inherit;
1416         fork_proc.u.process_fork.flags=flags;
1417         
1418         in_fd=_wapi_file_handle_to_fd (stdin_handle);
1419         out_fd=_wapi_file_handle_to_fd (stdout_handle);
1420         err_fd=_wapi_file_handle_to_fd (stderr_handle);
1421
1422         if(in_fd==-1 || out_fd==-1 || err_fd==-1) {
1423                 /* We were given duff handles */
1424                 /* FIXME: error code */
1425                 return(FALSE);
1426         }
1427         
1428         _wapi_daemon_request_response_with_fds (daemon_sock, &fork_proc,
1429                                                 &fork_proc_resp, in_fd,
1430                                                 out_fd, err_fd);
1431         if(fork_proc_resp.type==WapiHandleResponseType_ProcessFork) {
1432                 *process_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.process_handle);
1433                 *thread_handle=GUINT_TO_POINTER (fork_proc_resp.u.process_fork.thread_handle);
1434                 *pid=fork_proc_resp.u.process_fork.pid;
1435                 *tid=fork_proc_resp.u.process_fork.tid;
1436
1437                 /* If there was an internal error, the handles will be
1438                  * 0.  If there was an error forking or execing, the
1439                  * handles will have values, and process_handle's
1440                  * exec_errno will be set, and the handle will be
1441                  * signalled immediately.
1442                  */
1443                 if(process_handle==0 || thread_handle==0) {
1444                         return(FALSE);
1445                 } else {
1446                         return(TRUE);
1447                 }
1448         } else {
1449                 g_warning (G_GNUC_PRETTY_FUNCTION
1450                            ": bogus daemon response, type %d",
1451                            fork_proc_resp.type);
1452                 g_assert_not_reached ();
1453         }
1454         
1455         return(FALSE);
1456 }