2 * handles.c: Generic and internal operations on handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
16 #include <sys/types.h>
17 #include <sys/socket.h>
21 #include <mono/os/gc_wrapper.h>
23 #include <mono/io-layer/wapi.h>
24 #include <mono/io-layer/wapi-private.h>
25 #include <mono/io-layer/handles-private.h>
26 #include <mono/io-layer/mono-mutex.h>
27 #include <mono/io-layer/shared.h>
28 #include <mono/io-layer/misc-private.h>
29 #include <mono/io-layer/daemon-messages.h>
32 #undef HEAVY_DEBUG /* This will print handle counts on every handle created */
34 /* Shared threads don't seem to work yet */
35 #undef _POSIX_THREAD_PROCESS_SHARED
38 * This flag _MUST_ remain set to FALSE in the daemon process. When
39 * we exec()d a standalone daemon, that happened because shared_init()
40 * didnt get called in the daemon process. Now we just fork() without
41 * exec(), we need to ensure that the fork() happens when shared is
44 * This is further complicated by the second attempt to start the
45 * daemon if the connect() fails.
47 static gboolean shared
=FALSE
;
49 static WapiHandleCapability handle_caps
[WAPI_HANDLE_COUNT
]={0};
50 static struct _WapiHandleOps
*handle_ops
[WAPI_HANDLE_COUNT
]={
64 static int daemon_sock
;
66 static pthread_mutexattr_t mutex_shared_attr
;
67 static pthread_condattr_t cond_shared_attr
;
69 struct _WapiHandleShared_list
**_wapi_shared_data
=NULL
;
70 struct _WapiHandleScratch
*_wapi_shared_scratch
=NULL
;
71 struct _WapiHandlePrivate_list
**_wapi_private_data
=NULL
;
72 pthread_mutex_t _wapi_shared_mutex
=PTHREAD_MUTEX_INITIALIZER
;
74 /* This holds the length of the _wapi_shared_data and
75 * _wapi_private_data arrays, so we know if a segment is off the end
76 * of the array, requiring a realloc
78 guint32 _wapi_shm_mapped_segments
;
80 guint32 _wapi_fd_offset_table_size
;
81 gpointer
*_wapi_fd_offset_table
=NULL
;
83 static void shared_init (void)
85 struct sockaddr_un shared_socket_address
;
86 gboolean tried_once
=FALSE
;
90 _wapi_shared_data
=g_new0 (struct _WapiHandleShared_list
*, 1);
91 _wapi_private_data
=g_new0 (struct _WapiHandlePrivate_list
*, 1);
95 #ifndef DISABLE_SHARED_HANDLES
96 if(getenv ("MONO_DISABLE_SHM"))
100 #ifndef DISABLE_SHARED_HANDLES
102 /* Ensure that shared==FALSE while _wapi_shm_attach()
107 shared
=_wapi_shm_attach (&_wapi_shared_data
[0],
108 &_wapi_shared_scratch
);
111 "Failed to attach shared memory! "
112 "Falling back to non-shared handles\n"
113 "See: http://www.go-mono.com/issues.html#wapi for details");
115 #endif /* DISABLE_SHARED_HANDLES */
120 daemon_sock
=socket (PF_UNIX
, SOCK_STREAM
, 0);
121 shared_socket_address
.sun_family
=AF_UNIX
;
122 memcpy (shared_socket_address
.sun_path
,
123 _wapi_shared_data
[0]->daemon
, MONO_SIZEOF_SUNPATH
);
124 ret
=connect (daemon_sock
,
125 (struct sockaddr
*)&shared_socket_address
,
126 sizeof(struct sockaddr_un
));
128 if(tried_once
==TRUE
) {
129 g_warning (G_GNUC_PRETTY_FUNCTION
130 ": connect to daemon failed: %s",
132 /* Fall back to private handles */
135 /* It's possible that the daemon
136 * crashed without destroying the
137 * shared memory segment (thus fooling
138 * subsequent processes into thinking
139 * the daemon is still active).
141 * Destroy the shared memory segment
142 * and try once more. This won't
143 * break running apps, but no new apps
144 * will be able to see the current
145 * shared memory segment.
148 _wapi_shm_destroy ();
153 _wapi_fd_offset_table_size
= _wapi_shared_data
[0]->fd_offset_table_size
;
154 _wapi_fd_offset_table
=g_new0 (gpointer
, _wapi_fd_offset_table_size
);
160 g_message (G_GNUC_PRETTY_FUNCTION
161 ": Using process-private handles");
163 _wapi_shared_data
[0]=g_new0 (struct _WapiHandleShared_list
, 1);
164 _wapi_shared_data
[0]->num_segments
=1;
166 _wapi_shared_scratch
=g_new0 (struct _WapiHandleScratch
, 1);
168 _wapi_fd_offset_table_size
=getdtablesize ();
169 _wapi_fd_offset_table
=g_new0 (gpointer
,
170 _wapi_fd_offset_table_size
);
172 _wapi_private_data
[0]=g_new0 (struct _WapiHandlePrivate_list
, 1);
173 _wapi_shm_mapped_segments
=1;
175 thr_ret
= pthread_mutexattr_init (&mutex_shared_attr
);
176 g_assert (thr_ret
== 0);
178 thr_ret
= pthread_condattr_init (&cond_shared_attr
);
179 g_assert (thr_ret
== 0);
181 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
182 thr_ret
= pthread_mutexattr_setpshared (&mutex_shared_attr
,
183 PTHREAD_PROCESS_SHARED
);
184 g_assert (thr_ret
== 0);
186 thr_ret
= pthread_condattr_setpshared (&cond_shared_attr
,
187 PTHREAD_PROCESS_SHARED
);
188 g_assert (thr_ret
== 0);
190 thr_ret
= pthread_cond_init(&_wapi_private_data
[0]->signal_cond
, NULL
);
191 g_assert (thr_ret
== 0);
193 thr_ret
= mono_mutex_init(&_wapi_private_data
[0]->signal_mutex
, NULL
);
194 g_assert (thr_ret
== 0);
200 print_handle_count (gint mask
)
202 gint
*count
, num_handles
;
204 static const gchar
*names
[] = {"WAPI_HANDLE_UNUSED",
206 "WAPI_HANDLE_CONSOLE",
207 "WAPI_HANDLE_THREAD",
211 "WAPI_HANDLE_SOCKET",
213 "WAPI_HANDLE_PROCESS",
218 num_handles
=_wapi_handle_get_shared_segment (0)->num_segments
* _WAPI_HANDLES_PER_SEGMENT
;
219 count
=g_new0 (gint
, num_handles
);
221 for (i
= 1; i
< num_handles
; i
++) {
222 struct _WapiHandleShared
*shared
;
223 guint32 segment
, idx
;
225 _wapi_handle_segment (GUINT_TO_POINTER (i
), &segment
, &idx
);
226 _wapi_handle_ensure_mapped (segment
);
228 shared
= &_wapi_handle_get_shared_segment (segment
)->handles
[idx
];
229 count
[shared
->type
]++;
232 for (i
= 0; i
< num_handles
; i
++)
233 if ((i
& mask
) == i
) /* Always prints the UNUSED count */
234 g_print ("%s: %d\n", names
[i
], count
[i
]);
238 #endif /* HEAVY_DEBUG */
241 * _wapi_handle_new_internal:
242 * @type: Init handle to this type
244 * Search for a free handle and initialize it. Return the handle on
245 * success and 0 on failure.
247 guint32
_wapi_handle_new_internal (WapiHandleType type
)
249 guint32 segment
, idx
;
251 static guint32 last
=1;
253 guint32 num_segments
= _wapi_handle_get_shared_segment (0)->num_segments
;
255 /* A linear scan should be fast enough. Start from the last
256 * allocation, assuming that handles are allocated more often
257 * than they're freed. Leave 0 (NULL) as a guard
260 print_handle_count (0xFFF);
263 _wapi_handle_segment (GUINT_TO_POINTER (last
), &segment
, &idx
);
264 for(i
=segment
; i
< num_segments
; i
++) {
269 for(j
=idx
; j
<_WAPI_HANDLES_PER_SEGMENT
; j
++) {
270 struct _WapiHandleShared
*shared
;
272 /* Make sure we dont try and assign the
273 * handles that would clash with fds
275 if ((i
* _WAPI_HANDLES_PER_SEGMENT
+ j
) < _wapi_fd_offset_table_size
) {
276 i
= _wapi_fd_offset_table_size
/ _WAPI_HANDLES_PER_SEGMENT
;
277 j
= _wapi_fd_offset_table_size
- (i
* _WAPI_HANDLES_PER_SEGMENT
);
279 if (i
>= num_segments
) {
280 /* Need to get the caller to
281 * add more shared segments
289 shared
=&_wapi_handle_get_shared_segment (i
)->handles
[j
];
291 if(shared
->type
==WAPI_HANDLE_UNUSED
) {
292 last
=(_wapi_handle_index (i
, j
)+1) % (_wapi_handle_get_shared_segment (0)->num_segments
* _WAPI_HANDLES_PER_SEGMENT
);
294 shared
->signalled
=FALSE
;
295 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
296 thr_ret
= mono_mutex_init (&shared
->signal_mutex
, &mutex_shared_attr
);
297 g_assert (thr_ret
== 0);
299 thr_ret
= pthread_cond_init (&shared
->signal_cond
, &cond_shared_attr
);
300 g_assert (thr_ret
== 0);
302 thr_ret
= pthread_cond_init(&shared
->signal_cond
, NULL
);
303 g_assert (thr_ret
== 0);
305 thr_ret
= mono_mutex_init(&shared
->signal_mutex
, NULL
);
306 g_assert (thr_ret
== 0);
309 return(_wapi_handle_index (i
, j
));
315 /* Try again from the beginning */
320 /* Will need a new segment. The caller will sort it out */
325 gpointer
_wapi_handle_new (WapiHandleType type
)
327 static mono_once_t shared_init_once
= MONO_ONCE_INIT
;
328 static pthread_mutex_t scan_mutex
=PTHREAD_MUTEX_INITIALIZER
;
329 guint32 handle_idx
= 0, idx
, segment
;
331 WapiHandleRequest
new={0};
332 WapiHandleResponse new_resp
={0};
334 gboolean tried_collect
=FALSE
;
338 mono_once (&shared_init_once
, shared_init
);
342 new.type
=WapiHandleRequestType_New
;
345 _wapi_daemon_request_response (daemon_sock
, &new, &new_resp
);
347 if (new_resp
.type
==WapiHandleResponseType_New
) {
348 handle_idx
=new_resp
.u
.new.handle
;
350 g_warning (G_GNUC_PRETTY_FUNCTION
351 ": bogus daemon response, type %d",
353 g_assert_not_reached ();
356 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock
,
357 (void *)&scan_mutex
);
358 thr_ret
= pthread_mutex_lock (&scan_mutex
);
359 g_assert (thr_ret
== 0);
361 while ((handle_idx
= _wapi_handle_new_internal (type
)) == 0) {
362 /* Try and get a new segment, and have another go */
363 segment
=_wapi_handle_get_shared_segment (0)->num_segments
;
364 _wapi_handle_ensure_mapped (segment
);
366 if(_wapi_handle_get_shared_segment (segment
)!=NULL
) {
367 /* Got a new segment */
368 _wapi_handle_get_shared_segment (0)->num_segments
++;
370 /* Map failed. Just return 0 meaning
376 _wapi_handle_segment (GUINT_TO_POINTER (handle_idx
), &segment
, &idx
);
377 _wapi_handle_get_shared_segment (segment
)->handles
[idx
].ref
++;
379 thr_ret
= pthread_mutex_unlock (&scan_mutex
);
380 g_assert (thr_ret
== 0);
381 pthread_cleanup_pop (0);
384 /* Make sure we left the space for fd mappings */
385 g_assert (handle_idx
>= _wapi_fd_offset_table_size
);
388 g_warning (G_GNUC_PRETTY_FUNCTION
": Ran out of handles!");
391 /* See if we can reclaim some handles by forcing a GC
394 if(tried_collect
==FALSE
) {
395 g_warning (G_GNUC_PRETTY_FUNCTION
396 ": Seeing if GC collection helps...");
397 GC_gcollect (); /* FIXME: we should wait for finalizers to be called */
401 g_warning (G_GNUC_PRETTY_FUNCTION
402 ": didn't help, returning error");
406 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID
));
409 _wapi_handle_segment (GUINT_TO_POINTER (handle_idx
), &segment
, &idx
);
410 _wapi_handle_ensure_mapped (segment
);
412 if(_wapi_private_data
!=NULL
) {
413 _wapi_handle_get_private_segment (segment
)->handles
[idx
].type
=type
;
416 #if !defined(_POSIX_THREAD_PROCESS_SHARED) || _POSIX_THREAD_PROCESS_SHARED == -1
417 thr_ret
= mono_mutex_init (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_mutex
, &mutex_shared_attr
);
418 g_assert (thr_ret
== 0);
420 thr_ret
= pthread_cond_init (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_cond
, &cond_shared_attr
);
421 g_assert (thr_ret
== 0);
423 handle
=GUINT_TO_POINTER (handle_idx
);
426 g_message (G_GNUC_PRETTY_FUNCTION
": Allocated new handle %p", handle
);
432 gboolean
_wapi_lookup_handle (gpointer handle
, WapiHandleType type
,
433 gpointer
*shared
, gpointer
*private)
435 struct _WapiHandleShared
*shared_handle_data
;
436 struct _WapiHandlePrivate
*private_handle_data
= NULL
;
440 g_assert (GPOINTER_TO_UINT (handle
) >= _wapi_fd_offset_table_size
);
442 _wapi_handle_segment (handle
, &segment
, &idx
);
443 _wapi_handle_ensure_mapped (segment
);
445 shared_handle_data
=&_wapi_handle_get_shared_segment (segment
)->handles
[idx
];
448 *shared
=&shared_handle_data
->u
;
452 private_handle_data
=&_wapi_handle_get_private_segment (segment
)->handles
[idx
];
454 *private=&private_handle_data
->u
;
457 if(shared_handle_data
->type
!=type
) {
458 /* If shared type is UNUSED, see if the private type
459 * matches what we are looking for - this can happen
460 * when the handle is being destroyed and the
461 * close_private function is looking up the private
464 if(shared_handle_data
->type
==WAPI_HANDLE_UNUSED
&&
465 (private!=NULL
&& private_handle_data
->type
==type
)) {
475 gpointer
_wapi_search_handle (WapiHandleType type
,
476 gboolean (*check
)(gpointer test
, gpointer user
),
478 gpointer
*shared
, gpointer
*private)
480 struct _WapiHandleShared
*shared_handle_data
;
481 struct _WapiHandlePrivate
*private_handle_data
;
482 guint32 i
, segment
, idx
;
484 for(i
=1; i
<_wapi_handle_get_shared_segment (0)->num_segments
* _WAPI_HANDLES_PER_SEGMENT
; i
++) {
485 struct _WapiHandleShared
*shared
;
487 _wapi_handle_segment (GUINT_TO_POINTER (i
), &segment
, &idx
);
488 _wapi_handle_ensure_mapped (segment
);
490 shared
=&_wapi_handle_get_shared_segment (segment
)->handles
[idx
];
492 if(shared
->type
==type
) {
493 if(check (GUINT_TO_POINTER (i
), user_data
)==TRUE
) {
499 if(i
==_wapi_handle_get_shared_segment (0)->num_segments
* _WAPI_HANDLES_PER_SEGMENT
) {
500 return(GUINT_TO_POINTER (0));
504 shared_handle_data
=&_wapi_handle_get_shared_segment (segment
)->handles
[idx
];
506 *shared
=&shared_handle_data
->u
;
510 private_handle_data
=&_wapi_handle_get_private_segment (segment
)->handles
[idx
];
512 *private=&private_handle_data
->u
;
515 return(GUINT_TO_POINTER (i
));
518 gpointer
_wapi_search_handle_namespace (WapiHandleType type
,
519 gchar
*utf8_name
, gpointer
*shared
,
522 struct _WapiHandleShared
*shared_handle_data
;
523 struct _WapiHandlePrivate
*private_handle_data
;
524 guint32 i
, segment
, idx
;
527 g_message (G_GNUC_PRETTY_FUNCTION
528 ": Lookup for handle named [%s] type %d", utf8_name
, type
);
531 for(i
=1; i
<_wapi_handle_get_shared_segment (0)->num_segments
* _WAPI_HANDLES_PER_SEGMENT
; i
++) {
532 struct _WapiHandleShared
*shared
;
534 _wapi_handle_segment (GUINT_TO_POINTER (i
), &segment
, &idx
);
535 _wapi_handle_ensure_mapped (segment
);
537 shared
=&_wapi_handle_get_shared_segment (segment
)->handles
[idx
];
539 /* Check mutex, event, semaphore, timer, job and file-mapping
540 * object names. So far only mutex is implemented.
542 if(_WAPI_SHARED_NAMESPACE (shared
->type
)) {
544 WapiSharedNamespace
*sharedns
;
547 g_message (G_GNUC_PRETTY_FUNCTION
": found a shared namespace handle at 0x%x (type %d)", i
, shared
->type
);
550 shared_handle_data
=&_wapi_handle_get_shared_segment (segment
)->handles
[idx
];
551 sharedns
=(WapiSharedNamespace
*)&shared_handle_data
->u
;
555 lookup_name
=_wapi_handle_scratch_lookup (
559 g_message (G_GNUC_PRETTY_FUNCTION
560 ": handle 0x%x is unnamed", i
);
565 if(lookup_name
==NULL
) {
567 g_message (G_GNUC_PRETTY_FUNCTION
568 ": couldn't find handle 0x%x name",
575 g_message (G_GNUC_PRETTY_FUNCTION
": name is [%s]",
579 if(strcmp (lookup_name
, utf8_name
)==0) {
580 if(shared
->type
!=type
) {
581 /* Its the wrong type, so fail now */
583 g_message (G_GNUC_PRETTY_FUNCTION
": handle 0x%x matches name but is wrong type: %d", i
, shared
->type
);
585 return(_WAPI_HANDLE_INVALID
);
587 /* fall through so we can fill
591 g_message (G_GNUC_PRETTY_FUNCTION
": handle 0x%x matches name and type", i
);
599 if(i
==_wapi_handle_get_shared_segment (0)->num_segments
* _WAPI_HANDLES_PER_SEGMENT
) {
600 return(GUINT_TO_POINTER (0));
604 shared_handle_data
=&_wapi_handle_get_shared_segment (segment
)->handles
[idx
];
606 *shared
=&shared_handle_data
->u
;
610 private_handle_data
=&_wapi_handle_get_private_segment (segment
)->handles
[idx
];
612 *private=&private_handle_data
->u
;
615 return(GUINT_TO_POINTER (i
));
618 void _wapi_handle_ref (gpointer handle
)
620 g_assert (GPOINTER_TO_UINT (handle
) >= _wapi_fd_offset_table_size
);
623 WapiHandleRequest req
={0};
624 WapiHandleResponse resp
={0};
626 req
.type
=WapiHandleRequestType_Open
;
627 req
.u
.open
.handle
=GPOINTER_TO_UINT (handle
);
629 _wapi_daemon_request_response (daemon_sock
, &req
, &resp
);
630 if(resp
.type
!=WapiHandleResponseType_Open
) {
631 g_warning (G_GNUC_PRETTY_FUNCTION
632 ": bogus daemon response, type %d",
634 g_assert_not_reached ();
637 guint32 idx
, segment
;
639 _wapi_handle_segment (handle
, &segment
, &idx
);
641 _wapi_handle_get_shared_segment (segment
)->handles
[idx
].ref
++;
644 g_message (G_GNUC_PRETTY_FUNCTION
": handle %p ref now %d",
646 _wapi_handle_get_shared_segment (segment
)->handles
[idx
].ref
);
651 /* The handle must not be locked on entry to this function */
652 void _wapi_handle_unref (gpointer handle
)
654 guint32 idx
, segment
;
655 gboolean destroy
= FALSE
;
658 g_assert (GPOINTER_TO_UINT (handle
) >= _wapi_fd_offset_table_size
);
660 _wapi_handle_segment (handle
, &segment
, &idx
);
663 WapiHandleRequest req
={0};
664 WapiHandleResponse resp
={0};
666 req
.type
=WapiHandleRequestType_Close
;
667 req
.u
.close
.handle
=GPOINTER_TO_UINT (handle
);
669 _wapi_daemon_request_response (daemon_sock
, &req
, &resp
);
670 if(resp
.type
!=WapiHandleResponseType_Close
) {
671 g_warning (G_GNUC_PRETTY_FUNCTION
672 ": bogus daemon response, type %d",
674 g_assert_not_reached ();
676 destroy
=resp
.u
.close
.destroy
;
679 _wapi_handle_get_shared_segment (segment
)->handles
[idx
].ref
--;
682 g_message (G_GNUC_PRETTY_FUNCTION
": handle %p ref now %d", handle
, _wapi_handle_get_shared_segment (segment
)->handles
[idx
].ref
);
685 /* Possible race condition here if another thread refs
686 * the handle between here and setting the type to
687 * UNUSED. I could lock a mutex, but I'm not sure
688 * that allowing a handle reference to reach 0 isn't
689 * an application bug anyway.
691 destroy
=(_wapi_handle_get_shared_segment (segment
)->handles
[idx
].ref
==0);
696 g_message (G_GNUC_PRETTY_FUNCTION
": Destroying handle %p",
701 _wapi_handle_ops_close_shared (handle
);
703 memset (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].u
, '\0', sizeof(_wapi_handle_get_shared_segment (segment
)->handles
[idx
].u
));
706 _wapi_handle_ops_close_private (handle
);
707 _wapi_handle_get_shared_segment (segment
)->handles
[idx
].type
=WAPI_HANDLE_UNUSED
;
708 _wapi_handle_get_private_segment (segment
)->handles
[idx
].type
=WAPI_HANDLE_UNUSED
;
710 /* Destroy the mutex and cond var. We hope nobody
711 * tried to grab them between the handle unlock and
712 * now, but pthreads doesn't have a
713 * "unlock_and_destroy" atomic function.
715 thr_ret
= mono_mutex_destroy (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_mutex
);
716 g_assert (thr_ret
== 0);
718 thr_ret
= pthread_cond_destroy (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_cond
);
719 g_assert (thr_ret
== 0);
723 #define HDRSIZE sizeof(struct _WapiScratchHeader)
725 static pthread_mutex_t _wapi_scratch_mutex
=PTHREAD_MUTEX_INITIALIZER
;
727 /* _wapi_scratch_mutex must be held when this function is called in
728 * the non-shared case
730 static void _wapi_handle_scratch_expand (void)
732 guint32 old_len
, new_len
;
734 old_len
=sizeof(struct _WapiHandleScratch
) +
735 _wapi_shared_scratch
->data_len
;
736 new_len
=old_len
+_WAPI_SHM_SCRATCH_SIZE
;
738 if(_wapi_shared_scratch
->is_shared
==TRUE
) {
739 /* expand via mmap() */
740 _wapi_shared_scratch
=_wapi_shm_file_expand (_wapi_shared_scratch
, WAPI_SHM_SCRATCH
, 0, old_len
, new_len
);
742 _wapi_shared_scratch
=_wapi_g_renew0 (_wapi_shared_scratch
, old_len
, new_len
);
744 _wapi_shared_scratch
->data_len
+=_WAPI_SHM_SCRATCH_SIZE
;
747 /* _wapi_scratch_mutex must be held when this function is called in
748 * the non-shared case
750 static guint32
_wapi_handle_scratch_locate_space (guint32 bytes
)
752 guint32 idx
=0, last_idx
=0;
753 struct _WapiScratchHeader
*hdr
, *last_hdr
= NULL
;
754 gboolean last_was_free
=FALSE
;
755 guchar
*storage
=_wapi_shared_scratch
->scratch_data
;
758 g_message (G_GNUC_PRETTY_FUNCTION
759 ": looking for %d bytes of scratch space (%d bytes total)",
760 bytes
, _wapi_shared_scratch
->data_len
);
763 while(idx
< _wapi_shared_scratch
->data_len
) {
764 hdr
=(struct _WapiScratchHeader
*)&storage
[idx
];
766 /* Do a simple first-fit allocation, coalescing
767 * adjacent free blocks as we progress through the
770 if(hdr
->flags
& WAPI_SHM_SCRATCH_FREE
&&
771 hdr
->length
>= bytes
+ HDRSIZE
) {
773 guint32 old_length
=hdr
->length
;
775 g_message (G_GNUC_PRETTY_FUNCTION
": found suitable free size at %d, length %d", idx
, hdr
->length
);
778 hdr
->flags
&= ~WAPI_SHM_SCRATCH_FREE
;
782 /* Put a new header in at the end of the used
785 hdr
=(struct _WapiScratchHeader
*)&storage
[idx
+bytes
];
786 hdr
->flags
|= WAPI_SHM_SCRATCH_FREE
;
787 hdr
->length
= old_length
-bytes
-HDRSIZE
;
790 g_message (G_GNUC_PRETTY_FUNCTION
": new header at %d, length %d", idx
+bytes
, hdr
->length
);
794 * It was memset(0..) when free/made so no need to do it here
798 } else if(hdr
->flags
& WAPI_SHM_SCRATCH_FREE
&&
799 last_was_free
== FALSE
) {
801 g_message (G_GNUC_PRETTY_FUNCTION
": found too-small free block at %d, length %d (previous used)", idx
, hdr
->length
);
804 /* save this point in case we can coalesce it with
805 * the next block, if that is free.
810 idx
+=(hdr
->length
+HDRSIZE
);
811 } else if (hdr
->flags
& WAPI_SHM_SCRATCH_FREE
&&
812 last_was_free
== TRUE
) {
814 g_message (G_GNUC_PRETTY_FUNCTION
": found too-small free block at %d, length %d (previous free)", idx
, hdr
->length
);
817 /* This block and the previous are both free,
820 last_hdr
->length
+= (hdr
->length
+ HDRSIZE
);
822 /* If the new block is now big enough, use it
823 * (next time round the loop)
825 if(last_hdr
->length
>= bytes
+ HDRSIZE
) {
828 /* leave the last free info as it is,
829 * in case the next block is also free
830 * and can be coalesced too
832 idx
=last_idx
+last_hdr
->length
+HDRSIZE
;
836 g_message (G_GNUC_PRETTY_FUNCTION
837 ": found used block at %d, length %d", idx
,
841 /* must be used, try next chunk */
842 idx
+=(hdr
->length
+HDRSIZE
);
844 /* Don't let the coalescing blow away this block */
847 /* But remember where the last block started */
852 /* Not enough free space. last_idx points to the last block.
853 * If it's free, just tack on more space and update the
854 * length. If it's allocated, it must have fit right into the
855 * available space, so add more space and add a new header
858 _wapi_handle_scratch_expand ();
859 storage
=_wapi_shared_scratch
->scratch_data
;
861 hdr
=(struct _WapiScratchHeader
*)&storage
[last_idx
];
862 if(hdr
->flags
& WAPI_SHM_SCRATCH_FREE
) {
863 hdr
->length
+=_WAPI_SHM_SCRATCH_SIZE
;
865 idx
=(hdr
->length
+HDRSIZE
);
866 hdr
=(struct _WapiScratchHeader
*)&storage
[idx
];
867 hdr
->flags
|= WAPI_SHM_SCRATCH_FREE
;
868 hdr
->length
= _WAPI_SHM_SCRATCH_SIZE
-HDRSIZE
;
871 /* The caller will try again */
876 * _wapi_handle_scratch_store_internal:
877 * @bytes: Allocate no. bytes
879 * Like malloc(3) except its for the shared memory segment's scratch
880 * part. Memory block returned is zeroed out.
882 guint32
_wapi_handle_scratch_store_internal (guint32 bytes
, gboolean
*remap
)
886 struct _WapiScratchHeader
*hdr
;
889 g_message (G_GNUC_PRETTY_FUNCTION
": storing %d bytes", bytes
);
894 if(_wapi_shared_scratch
->data_len
==0) {
895 /* Need to expand the data array for the first use */
897 g_message (G_GNUC_PRETTY_FUNCTION
898 ": setting up scratch space");
901 _wapi_handle_scratch_expand ();
905 storage
=_wapi_shared_scratch
->scratch_data
;
906 hdr
=(struct _WapiScratchHeader
*)&storage
[0];
907 if(hdr
->flags
==0 && hdr
->length
==0) {
908 /* Need to initialise scratch data */
909 hdr
->flags
|= WAPI_SHM_SCRATCH_FREE
;
910 hdr
->length
= _wapi_shared_scratch
->data_len
- HDRSIZE
;
913 idx
=_wapi_handle_scratch_locate_space (bytes
);
915 /* Some more space will have been allocated, so try again */
917 g_message (G_GNUC_PRETTY_FUNCTION
": trying again");
920 idx
=_wapi_handle_scratch_locate_space (bytes
);
927 guint32
_wapi_handle_scratch_store (gconstpointer data
, guint32 bytes
)
929 guint32 idx
= 0, store_bytes
;
935 g_message (G_GNUC_PRETTY_FUNCTION
": storing %d bytes", bytes
);
938 /* No point storing no data */
943 /* Align bytes to 32 bits (needed for sparc at least) */
944 store_bytes
= (((bytes
) + 3) & (~3));
946 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock
,
947 (void *)&_wapi_scratch_mutex
);
948 thr_ret
= pthread_mutex_lock (&_wapi_scratch_mutex
);
949 g_assert (thr_ret
== 0);
952 WapiHandleRequest scratch
={0};
953 WapiHandleResponse scratch_resp
={0};
954 guint32 old_len
=sizeof(struct _WapiHandleScratch
) +
955 _wapi_shared_scratch
->data_len
;
957 scratch
.type
=WapiHandleRequestType_Scratch
;
958 scratch
.u
.scratch
.length
=store_bytes
;
960 _wapi_daemon_request_response (daemon_sock
, &scratch
,
963 if(scratch_resp
.type
==WapiHandleResponseType_Scratch
) {
964 idx
=scratch_resp
.u
.scratch
.idx
;
965 remap
=scratch_resp
.u
.scratch
.remap
;
967 g_warning (G_GNUC_PRETTY_FUNCTION
968 ": bogus daemon response, type %d",
970 g_assert_not_reached ();
974 munmap (_wapi_shared_scratch
, old_len
);
975 _wapi_shared_scratch
=_wapi_shm_file_map (WAPI_SHM_SCRATCH
, 0, NULL
, NULL
);
978 idx
=_wapi_handle_scratch_store_internal (store_bytes
, &remap
);
980 /* Failed to allocate space */
987 g_message (G_GNUC_PRETTY_FUNCTION
988 ": stored [%s] at %d (len %d, aligned len %d)",
989 (char *)data
, idx
, bytes
, store_bytes
);
992 memcpy (&_wapi_shared_scratch
->scratch_data
[idx
], data
, bytes
);
995 thr_ret
= pthread_mutex_unlock (&_wapi_scratch_mutex
);
996 g_assert (thr_ret
== 0);
997 pthread_cleanup_pop (0);
1002 guint32
_wapi_handle_scratch_store_string_array (gchar
**data
)
1004 guint32
*stored_strings
, count
=0, i
, idx
;
1007 /* No point storing no data */
1013 while(*strings
!=NULL
) {
1019 g_message (G_GNUC_PRETTY_FUNCTION
": %d strings to store", count
);
1026 /* stored_strings[0] is the count */
1027 stored_strings
=g_new0 (guint32
, count
+1);
1028 stored_strings
[0]=count
;
1031 for(i
=0; i
<count
; i
++) {
1032 stored_strings
[i
+1]=_wapi_handle_scratch_store (strings
[i
], strlen (strings
[i
]));
1035 idx
=_wapi_handle_scratch_store (stored_strings
,
1036 sizeof(guint32
)*(count
+1));
1041 gpointer
_wapi_handle_scratch_lookup (guint32 idx
)
1043 struct _WapiScratchHeader
*hdr
;
1048 if(idx
< HDRSIZE
|| idx
> _wapi_shared_scratch
->data_len
) {
1052 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock
,
1053 (void *)&_wapi_scratch_mutex
);
1054 thr_ret
= pthread_mutex_lock (&_wapi_scratch_mutex
);
1055 g_assert (thr_ret
== 0);
1057 storage
=_wapi_shared_scratch
->scratch_data
;
1059 hdr
=(struct _WapiScratchHeader
*)&storage
[idx
- HDRSIZE
];
1060 ret
=g_malloc0 (hdr
->length
+1);
1061 memcpy (ret
, &storage
[idx
], hdr
->length
);
1063 thr_ret
= pthread_mutex_unlock (&_wapi_scratch_mutex
);
1064 g_assert (thr_ret
== 0);
1065 pthread_cleanup_pop (0);
1070 gchar
**_wapi_handle_scratch_lookup_string_array (guint32 idx
)
1073 guint32
*stored_strings
;
1076 if(idx
< HDRSIZE
|| idx
> _wapi_shared_scratch
->data_len
) {
1080 stored_strings
=_wapi_handle_scratch_lookup (idx
);
1081 if(stored_strings
==NULL
) {
1085 /* stored_strings[0] is the number of strings, the index of
1086 * each string follows
1088 count
=stored_strings
[0];
1091 g_message (G_GNUC_PRETTY_FUNCTION
1092 ": looking up an array of %d strings", count
);
1095 /* NULL-terminate the array */
1096 strings
=g_new0 (gchar
*, count
+1);
1098 for(i
=0; i
<count
; i
++) {
1099 strings
[i
]=_wapi_handle_scratch_lookup (stored_strings
[i
+1]);
1102 g_message (G_GNUC_PRETTY_FUNCTION
": string %d is [%s]", i
,
1107 g_free (stored_strings
);
1113 * _wapi_handle_scratch_delete_internal:
1114 * @idx: Index to free block
1116 * Like free(3) except its for the shared memory segment's scratch
1119 void _wapi_handle_scratch_delete_internal (guint32 idx
)
1121 struct _WapiScratchHeader
*hdr
;
1125 if(idx
< HDRSIZE
|| idx
> _wapi_shared_scratch
->data_len
) {
1129 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock
,
1130 (void *)&_wapi_scratch_mutex
);
1131 thr_ret
= pthread_mutex_lock (&_wapi_scratch_mutex
);
1132 g_assert (thr_ret
== 0);
1134 storage
=_wapi_shared_scratch
->scratch_data
;
1136 hdr
=(struct _WapiScratchHeader
*)&storage
[idx
- HDRSIZE
];
1137 memset (&storage
[idx
], '\0', hdr
->length
);
1138 hdr
->flags
|= WAPI_SHM_SCRATCH_FREE
;
1140 /* We could coalesce forwards here if the next block is also
1141 * free, but the _store() function will do that anyway.
1144 thr_ret
= pthread_mutex_unlock (&_wapi_scratch_mutex
);
1145 g_assert (thr_ret
== 0);
1146 pthread_cleanup_pop (0);
1149 void _wapi_handle_scratch_delete (guint32 idx
)
1152 WapiHandleRequest scratch_free
={0};
1153 WapiHandleResponse scratch_free_resp
={0};
1155 scratch_free
.type
=WapiHandleRequestType_ScratchFree
;
1156 scratch_free
.u
.scratch_free
.idx
=idx
;
1158 _wapi_daemon_request_response (daemon_sock
, &scratch_free
,
1159 &scratch_free_resp
);
1161 if(scratch_free_resp
.type
!=WapiHandleResponseType_ScratchFree
) {
1162 g_warning (G_GNUC_PRETTY_FUNCTION
1163 ": bogus daemon response, type %d",
1164 scratch_free_resp
.type
);
1165 g_assert_not_reached ();
1168 _wapi_handle_scratch_delete_internal (idx
);
1172 void _wapi_handle_scratch_delete_string_array (guint32 idx
)
1174 guint32
*stored_strings
;
1177 stored_strings
=_wapi_handle_scratch_lookup (idx
);
1178 if(stored_strings
==NULL
) {
1182 /* stored_strings[0] is the number of strings, the index of
1183 * each string follows
1185 count
=stored_strings
[0];
1188 g_message (G_GNUC_PRETTY_FUNCTION
": deleting an array of %d strings",
1192 for(i
=1; i
<count
; i
++) {
1193 _wapi_handle_scratch_delete (stored_strings
[i
]);
1196 _wapi_handle_scratch_delete (idx
);
1198 g_free (stored_strings
);
1201 void _wapi_handle_register_capabilities (WapiHandleType type
,
1202 WapiHandleCapability caps
)
1204 handle_caps
[type
]=caps
;
1207 gboolean
_wapi_handle_test_capabilities (gpointer handle
,
1208 WapiHandleCapability caps
)
1210 guint32 idx
, segment
;
1211 WapiHandleType type
;
1213 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1214 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1217 _wapi_handle_segment (handle
, &segment
, &idx
);
1219 type
=_wapi_handle_get_shared_segment (segment
)->handles
[idx
].type
;
1222 g_message (G_GNUC_PRETTY_FUNCTION
": testing 0x%x against 0x%x (%d)",
1223 handle_caps
[type
], caps
, handle_caps
[type
] & caps
);
1226 return((handle_caps
[type
] & caps
)!=0);
1229 void _wapi_handle_ops_close_shared (gpointer handle
)
1231 guint32 idx
, segment
;
1232 WapiHandleType type
;
1234 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1235 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1238 _wapi_handle_segment (handle
, &segment
, &idx
);
1240 type
=_wapi_handle_get_shared_segment (segment
)->handles
[idx
].type
;
1242 if(handle_ops
[type
]!=NULL
&& handle_ops
[type
]->close_shared
!=NULL
) {
1243 handle_ops
[type
]->close_shared (handle
);
1247 void _wapi_handle_ops_close_private (gpointer handle
)
1249 guint32 idx
, segment
;
1250 WapiHandleType type
;
1252 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1253 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1256 _wapi_handle_segment (handle
, &segment
, &idx
);
1258 type
=_wapi_handle_get_shared_segment (segment
)->handles
[idx
].type
;
1260 /* When a handle in the process of being destroyed the shared
1261 * type has already been set to UNUSED
1263 if(type
==WAPI_HANDLE_UNUSED
&& _wapi_private_data
!=NULL
) {
1264 type
=_wapi_handle_get_private_segment (segment
)->handles
[idx
].type
;
1267 if(handle_ops
[type
]!=NULL
&& handle_ops
[type
]->close_private
!=NULL
) {
1268 handle_ops
[type
]->close_private (handle
);
1272 void _wapi_handle_ops_signal (gpointer handle
)
1274 guint32 idx
, segment
;
1275 WapiHandleType type
;
1277 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1278 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1281 _wapi_handle_segment (handle
, &segment
, &idx
);
1283 type
=_wapi_handle_get_shared_segment (segment
)->handles
[idx
].type
;
1285 if(handle_ops
[type
]!=NULL
&& handle_ops
[type
]->signal
!=NULL
) {
1286 handle_ops
[type
]->signal (handle
);
1290 void _wapi_handle_ops_own (gpointer handle
)
1292 guint32 idx
, segment
;
1293 WapiHandleType type
;
1295 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1296 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1299 _wapi_handle_segment (handle
, &segment
, &idx
);
1301 type
=_wapi_handle_get_shared_segment (segment
)->handles
[idx
].type
;
1303 if(handle_ops
[type
]!=NULL
&& handle_ops
[type
]->own_handle
!=NULL
) {
1304 handle_ops
[type
]->own_handle (handle
);
1308 gboolean
_wapi_handle_ops_isowned (gpointer handle
)
1310 guint32 idx
, segment
;
1311 WapiHandleType type
;
1313 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1314 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1317 _wapi_handle_segment (handle
, &segment
, &idx
);
1319 type
=_wapi_handle_get_shared_segment (segment
)->handles
[idx
].type
;
1321 if(handle_ops
[type
]!=NULL
&& handle_ops
[type
]->is_owned
!=NULL
) {
1322 return(handle_ops
[type
]->is_owned (handle
));
1330 * @handle: The handle to release
1332 * Closes and invalidates @handle, releasing any resources it
1333 * consumes. When the last handle to a temporary or non-persistent
1334 * object is closed, that object can be deleted. Closing the same
1335 * handle twice is an error.
1337 * Return value: %TRUE on success, %FALSE otherwise.
1339 gboolean
CloseHandle(gpointer handle
)
1341 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1342 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1345 if (handle
== NULL
) {
1349 _wapi_handle_unref (handle
);
1354 gboolean
_wapi_handle_count_signalled_handles (guint32 numhandles
,
1360 guint32 count
, i
, iter
=0;
1364 /* Lock all the handles, with backoff */
1366 for(i
=0; i
<numhandles
; i
++) {
1367 guint32 idx
, segment
;
1368 gpointer handle
= handles
[i
];
1370 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1371 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1374 _wapi_handle_segment (handle
, &segment
, &idx
);
1377 g_message (G_GNUC_PRETTY_FUNCTION
": attempting to lock %p",
1381 ret
=mono_mutex_trylock (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_mutex
);
1384 struct timespec sleepytime
;
1387 g_message (G_GNUC_PRETTY_FUNCTION
": attempt failed for %p: %s", handle
, strerror (ret
));
1391 handle
= handles
[i
];
1393 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1394 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1397 _wapi_handle_segment (handle
, &segment
, &idx
);
1398 thr_ret
= mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_mutex
);
1399 g_assert (thr_ret
== 0);
1402 /* If iter ever reaches 100 the nanosleep will
1403 * return EINVAL immediately, but we have a
1404 * design flaw if that happens.
1408 g_warning (G_GNUC_PRETTY_FUNCTION
1409 ": iteration overflow!");
1413 sleepytime
.tv_sec
=0;
1414 sleepytime
.tv_nsec
=10000000 * iter
; /* 10ms*iter */
1417 g_message (G_GNUC_PRETTY_FUNCTION
1418 ": Backing off for %d ms", iter
*10);
1420 nanosleep (&sleepytime
, NULL
);
1427 g_message (G_GNUC_PRETTY_FUNCTION
": Locked all handles");
1433 for(i
=0; i
<numhandles
; i
++) {
1434 guint32 idx
, segment
;
1435 gpointer handle
= handles
[i
];
1437 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1438 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1441 _wapi_handle_ref (handle
);
1443 _wapi_handle_segment (handle
, &segment
, &idx
);
1446 g_message (G_GNUC_PRETTY_FUNCTION
": Checking handle %p",
1450 if(((_wapi_handle_test_capabilities (handle
, WAPI_HANDLE_CAP_OWN
)==TRUE
) &&
1451 (_wapi_handle_ops_isowned (handle
)==TRUE
)) ||
1452 (_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signalled
==TRUE
)) {
1456 g_message (G_GNUC_PRETTY_FUNCTION
1457 ": Handle %p signalled", handle
);
1466 g_message (G_GNUC_PRETTY_FUNCTION
": %d event handles signalled",
1470 if((waitall
==TRUE
&& count
==numhandles
) ||
1471 (waitall
==FALSE
&& count
>0)) {
1478 g_message (G_GNUC_PRETTY_FUNCTION
": Returning %d", ret
);
1486 void _wapi_handle_unlock_handles (guint32 numhandles
, gpointer
*handles
)
1491 for(i
=0; i
<numhandles
; i
++) {
1492 guint32 idx
, segment
;
1493 gpointer handle
= handles
[i
];
1495 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1496 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1499 _wapi_handle_segment (handle
, &segment
, &idx
);
1502 g_message (G_GNUC_PRETTY_FUNCTION
": unlocking handle %p",
1506 thr_ret
= mono_mutex_unlock (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_mutex
);
1507 g_assert (thr_ret
== 0);
1509 _wapi_handle_unref (handle
);
1513 /* Process-shared handles (currently only process and thread handles
1514 * are allowed, and they only work because once signalled they can't
1515 * become unsignalled) are waited for by one process and signalled by
1516 * another. Without process-shared conditions, the waiting process
1517 * will block forever. To get around this, the four handle waiting
1518 * functions use a short timeout when _POSIX_THREAD_PROCESS_SHARED is
1519 * not available. They also return "success" if the fake timeout
1520 * expired, and let the caller check signal status.
1522 int _wapi_handle_wait_signal (void)
1524 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1525 return(mono_cond_wait (&_wapi_handle_get_shared_segment (0)->signal_cond
,
1526 &_wapi_handle_get_shared_segment (0)->signal_mutex
));
1528 struct timespec fake_timeout
;
1531 _wapi_calc_timeout (&fake_timeout
, 100);
1533 ret
=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond
,
1534 &_wapi_handle_get_private_segment (0)->signal_mutex
,
1536 if(ret
==ETIMEDOUT
) {
1541 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1544 int _wapi_handle_timedwait_signal (struct timespec
*timeout
)
1546 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1547 return(mono_cond_timedwait (&_wapi_handle_get_shared_segment (0)->signal_cond
,
1548 &_wapi_handle_get_shared_segment (0)->signal_mutex
,
1551 struct timespec fake_timeout
;
1554 _wapi_calc_timeout (&fake_timeout
, 100);
1556 if((fake_timeout
.tv_sec
>timeout
->tv_sec
) ||
1557 (fake_timeout
.tv_sec
==timeout
->tv_sec
&&
1558 fake_timeout
.tv_nsec
> timeout
->tv_nsec
)) {
1559 /* Real timeout is less than 100ms time */
1560 ret
=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond
,
1561 &_wapi_handle_get_private_segment (0)->signal_mutex
,
1564 ret
=mono_cond_timedwait (&_wapi_handle_get_private_segment (0)->signal_cond
,
1565 &_wapi_handle_get_private_segment (0)->signal_mutex
,
1567 if(ret
==ETIMEDOUT
) {
1573 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1576 int _wapi_handle_wait_signal_handle (gpointer handle
)
1578 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1579 guint32 idx
, segment
;
1581 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1582 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1585 _wapi_handle_segment (handle
, &segment
, &idx
);
1587 return(mono_cond_wait (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_cond
,
1588 &_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_mutex
));
1590 guint32 idx
, segment
;
1591 struct timespec fake_timeout
;
1594 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1595 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1598 _wapi_handle_segment (handle
, &segment
, &idx
);
1599 _wapi_calc_timeout (&fake_timeout
, 100);
1601 ret
=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_cond
,
1602 &_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_mutex
,
1604 if(ret
==ETIMEDOUT
) {
1609 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1612 int _wapi_handle_timedwait_signal_handle (gpointer handle
,
1613 struct timespec
*timeout
)
1615 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
1616 guint32 idx
, segment
;
1618 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1619 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1622 _wapi_handle_segment (handle
, &segment
, &idx
);
1624 return(mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_cond
,
1625 &_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_mutex
,
1628 guint32 idx
, segment
;
1629 struct timespec fake_timeout
;
1632 if (GPOINTER_TO_UINT (handle
) < _wapi_fd_offset_table_size
) {
1633 handle
= _wapi_handle_fd_offset_to_handle (handle
);
1636 _wapi_handle_segment (handle
, &segment
, &idx
);
1637 _wapi_calc_timeout (&fake_timeout
, 100);
1639 if((fake_timeout
.tv_sec
>timeout
->tv_sec
) ||
1640 (fake_timeout
.tv_sec
==timeout
->tv_sec
&&
1641 fake_timeout
.tv_nsec
> timeout
->tv_nsec
)) {
1642 /* Real timeout is less than 100ms time */
1643 ret
=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_cond
,
1644 &_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_mutex
,
1647 ret
=mono_cond_timedwait (&_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_cond
,
1648 &_wapi_handle_get_shared_segment (segment
)->handles
[idx
].signal_mutex
,
1650 if(ret
==ETIMEDOUT
) {
1656 #endif /* _POSIX_THREAD_PROCESS_SHARED */
1659 gboolean
_wapi_handle_process_fork (guint32 cmd
, guint32 env
, guint32 dir
,
1660 gboolean inherit
, guint32 flags
,
1661 gpointer stdin_handle
,
1662 gpointer stdout_handle
,
1663 gpointer stderr_handle
,
1664 gpointer
*process_handle
,
1665 gpointer
*thread_handle
, guint32
*pid
,
1668 WapiHandleRequest fork_proc
={0};
1669 WapiHandleResponse fork_proc_resp
={0};
1670 int in_fd
, out_fd
, err_fd
;
1676 fork_proc
.type
=WapiHandleRequestType_ProcessFork
;
1677 fork_proc
.u
.process_fork
.cmd
=cmd
;
1678 fork_proc
.u
.process_fork
.env
=env
;
1679 fork_proc
.u
.process_fork
.dir
=dir
;
1680 fork_proc
.u
.process_fork
.stdin_handle
=GPOINTER_TO_UINT (stdin_handle
);
1681 fork_proc
.u
.process_fork
.stdout_handle
=GPOINTER_TO_UINT (stdout_handle
);
1682 fork_proc
.u
.process_fork
.stderr_handle
=GPOINTER_TO_UINT (stderr_handle
);
1683 fork_proc
.u
.process_fork
.inherit
=inherit
;
1684 fork_proc
.u
.process_fork
.flags
=flags
;
1686 in_fd
=_wapi_file_handle_to_fd (stdin_handle
);
1687 out_fd
=_wapi_file_handle_to_fd (stdout_handle
);
1688 err_fd
=_wapi_file_handle_to_fd (stderr_handle
);
1690 if(in_fd
==-1 || out_fd
==-1 || err_fd
==-1) {
1691 /* We were given duff handles */
1692 /* FIXME: error code */
1696 _wapi_daemon_request_response_with_fds (daemon_sock
, &fork_proc
,
1697 &fork_proc_resp
, in_fd
,
1699 if(fork_proc_resp
.type
==WapiHandleResponseType_ProcessFork
) {
1700 *process_handle
=GUINT_TO_POINTER (fork_proc_resp
.u
.process_fork
.process_handle
);
1701 *thread_handle
=GUINT_TO_POINTER (fork_proc_resp
.u
.process_fork
.thread_handle
);
1702 *pid
=fork_proc_resp
.u
.process_fork
.pid
;
1703 *tid
=fork_proc_resp
.u
.process_fork
.tid
;
1705 /* If there was an internal error, the handles will be
1706 * 0. If there was an error forking or execing, the
1707 * handles will have values, and process_handle's
1708 * exec_errno will be set, and the handle will be
1709 * signalled immediately.
1711 if(*process_handle
==0 || *thread_handle
==0) {
1714 /* This call returns new handles, so we need to do
1715 * a little bookkeeping
1717 if (_wapi_private_data
!= NULL
) {
1718 guint32 segment
, idx
;
1720 _wapi_handle_segment (*process_handle
,
1722 _wapi_handle_ensure_mapped (segment
);
1723 _wapi_handle_get_private_segment (segment
)->handles
[idx
].type
= WAPI_HANDLE_PROCESS
;
1725 _wapi_handle_segment (*thread_handle
,
1727 _wapi_handle_ensure_mapped (segment
);
1728 _wapi_handle_get_private_segment (segment
)->handles
[idx
].type
= WAPI_HANDLE_THREAD
;
1734 g_warning (G_GNUC_PRETTY_FUNCTION
1735 ": bogus daemon response, type %d",
1736 fork_proc_resp
.type
);
1737 g_assert_not_reached ();
1744 _wapi_handle_process_kill (pid_t process
, guint32 signo
, gint
*errnum
)
1746 WapiHandleRequest killproc
= {0};
1747 WapiHandleResponse killprocresp
= {0};
1750 if (shared
!= TRUE
) {
1751 if (errnum
) *errnum
= EINVAL
;
1755 killproc
.type
= WapiHandleRequestType_ProcessKill
;
1756 killproc
.u
.process_kill
.pid
= process
;
1757 killproc
.u
.process_kill
.signo
= signo
;
1759 _wapi_daemon_request_response (daemon_sock
, &killproc
, &killprocresp
);
1761 if (killprocresp
.type
!= WapiHandleResponseType_ProcessKill
) {
1762 g_warning (G_GNUC_PRETTY_FUNCTION
1763 ": bogus daemon response, type %d",
1765 g_assert_not_reached ();
1768 result
= killprocresp
.u
.process_kill
.err
;
1769 if (result
!= 0 && errnum
!= NULL
)
1770 *errnum
= (result
== FALSE
) ? result
: 0;
1772 return (result
== 0);
1775 gboolean
_wapi_handle_get_or_set_share (dev_t device
, ino_t inode
,
1776 guint32 new_sharemode
,
1778 guint32
*old_sharemode
,
1779 guint32
*old_access
)
1781 WapiHandleRequest req
= {0};
1782 WapiHandleResponse resp
= {0};
1784 if(shared
!= TRUE
) {
1785 /* No daemon means we don't know if a file is sharable.
1786 * We're running in our own little world if this is
1787 * the case, so there's no point in pretending that
1788 * the file isn't sharable.
1793 req
.type
= WapiHandleRequestType_GetOrSetShare
;
1794 req
.u
.get_or_set_share
.device
= device
;
1795 req
.u
.get_or_set_share
.inode
= inode
;
1796 req
.u
.get_or_set_share
.new_sharemode
= new_sharemode
;
1797 req
.u
.get_or_set_share
.new_access
= new_access
;
1799 _wapi_daemon_request_response (daemon_sock
, &req
, &resp
);
1800 if (resp
.type
!= WapiHandleResponseType_GetOrSetShare
) {
1801 g_warning (G_GNUC_PRETTY_FUNCTION
1802 ": bogus daemon response, type %d", resp
.type
);
1803 g_assert_not_reached ();
1806 *old_sharemode
= resp
.u
.get_or_set_share
.sharemode
;
1807 *old_access
= resp
.u
.get_or_set_share
.access
;
1809 return(resp
.u
.get_or_set_share
.exists
);
1812 void _wapi_handle_set_share (dev_t device
, ino_t inode
, guint32 sharemode
,
1815 WapiHandleRequest req
= {0};
1816 WapiHandleResponse resp
= {0};
1818 if(shared
!= TRUE
) {
1819 /* No daemon, so there's no one else to tell about
1825 req
.type
= WapiHandleRequestType_SetShare
;
1826 req
.u
.set_share
.device
= device
;
1827 req
.u
.set_share
.inode
= inode
;
1828 req
.u
.set_share
.sharemode
= sharemode
;
1829 req
.u
.set_share
.access
= access
;
1831 _wapi_daemon_request_response (daemon_sock
, &req
, &resp
);
1832 if (resp
.type
!= WapiHandleResponseType_SetShare
) {
1833 g_warning (G_GNUC_PRETTY_FUNCTION
1834 ": bogus daemon response, type %d", resp
.type
);
1835 g_assert_not_reached ();