2 * daemon.c: The handle daemon
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
14 #include <sys/types.h>
15 #include <sys/socket.h>
24 #include <mono/io-layer/io-layer.h>
25 #include <mono/io-layer/handles-private.h>
26 #include <mono/io-layer/wapi-private.h>
27 #include <mono/io-layer/daemon-messages.h>
28 #include <mono/io-layer/timefuncs-private.h>
32 static struct pollfd *pollfds=NULL;
33 static int nfds=0, maxfds=0;
34 /* handle_refs[0] is used by the daemon itself */
35 static gpointer *handle_refs=NULL;
38 /* Set to TRUE by the SIGCHLD signal handler */
39 static volatile gboolean check_processes=FALSE;
41 /* Deletes the shared memory segment. If we're exiting on error,
42 * clients will get EPIPEs.
44 static void cleanup (void)
49 /* If there is only one socket, and no child processes, we can exit.
50 * We test for child processes by counting handle references held by
53 static void maybe_exit (void)
55 guint32 *open_handles=handle_refs[0], i;
58 g_message (G_GNUC_PRETTY_FUNCTION ": Seeing if we should exit");
63 g_message (G_GNUC_PRETTY_FUNCTION ": Still got clients");
68 for(i=0; i<_WAPI_MAX_HANDLES; i++) {
69 if(open_handles[i]>0) {
71 g_message (G_GNUC_PRETTY_FUNCTION
72 ": Still got handle references");
79 g_message (G_GNUC_PRETTY_FUNCTION ": Byebye");
86 static void signal_handler (int unused)
92 static void sigchld_handler (int unused)
94 /* Notice that a child process died */
98 static void startup (void)
104 sa.sa_handler=signal_handler;
105 sigemptyset (&sa.sa_mask);
107 sigaction (SIGINT, &sa, NULL);
108 sigaction (SIGTERM, &sa, NULL);
110 #ifndef HAVE_MSG_NOSIGNAL
111 sa.sa_handler=SIG_IGN;
112 sigaction (SIGPIPE, &sa, NULL);
115 sa.sa_handler=sigchld_handler;
116 sa.sa_flags=SA_NOCLDSTOP;
117 sigaction (SIGCHLD, &sa, NULL);
119 _wapi_shared_data=_wapi_shm_attach (TRUE, &success, &shm_id);
121 g_error ("Failed to attach shared memory! (tried shared memory ID 0x%x)", shm_id);
125 /* Leave the first byte NULL so we create the socket in the
126 * abstrace namespace, not on the filesystem. (Lets see how
127 * portable _that_ is :)
129 * The name is intended to be unique, not cryptographically
132 snprintf (_wapi_shared_data->daemon+1, 106,
133 "mono-handle-daemon-%d-%d-%ld", getuid (), getpid (),
137 static void ref_handle (guint32 idx, guint32 handle)
139 guint32 *open_handles=handle_refs[idx];
145 _wapi_shared_data->handles[handle].ref++;
146 open_handles[handle]++;
149 g_message (G_GNUC_PRETTY_FUNCTION
150 ": handle 0x%x ref now %d (%d this process)", handle,
151 _wapi_shared_data->handles[handle].ref,
152 open_handles[handle]);
156 static gboolean unref_handle (guint32 idx, guint32 handle)
158 guint32 *open_handles=handle_refs[idx];
159 gboolean destroy=FALSE;
165 _wapi_shared_data->handles[handle].ref--;
166 open_handles[handle]--;
169 g_message (G_GNUC_PRETTY_FUNCTION
170 ": handle 0x%x ref now %d (%d this process)", handle,
171 _wapi_shared_data->handles[handle].ref,
172 open_handles[handle]);
175 if(open_handles[handle]==0) {
176 /* This client has released the handle */
180 if(_wapi_shared_data->handles[handle].ref==0) {
181 if (open_handles[handle]!=0) {
182 g_warning (G_GNUC_PRETTY_FUNCTION ": per-process open_handles mismatch, set to %d, should be 0", open_handles[handle]);
186 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle 0x%x",
190 _wapi_handle_ops_close_shared (GUINT_TO_POINTER (handle));
192 _wapi_shared_data->handles[handle].type=WAPI_HANDLE_UNUSED;
193 mono_mutex_destroy (&_wapi_shared_data->handles[handle].signal_mutex);
194 pthread_cond_destroy (&_wapi_shared_data->handles[handle].signal_cond);
195 memset (&_wapi_shared_data->handles[handle].u, '\0', sizeof(_wapi_shared_data->handles[handle].u));
199 /* The daemon released a reference, so see if it's
208 static void add_fd(int fd)
211 /* extend the array */
213 pollfds=g_renew (struct pollfd, pollfds, maxfds);
214 handle_refs=g_renew (gpointer, handle_refs, maxfds);
218 pollfds[nfds].events=POLLIN;
219 pollfds[nfds].revents=0;
221 handle_refs[nfds]=g_new0 (guint32, _WAPI_MAX_HANDLES);
226 static void rem_fd(int idx)
228 guint32 *open_handles=handle_refs[idx], handle_count;
232 /* We shouldn't be deleting the daemon's fd */
233 g_warning (G_GNUC_PRETTY_FUNCTION ": Deleting daemon fd!");
239 g_message (G_GNUC_PRETTY_FUNCTION ": Removing client at %d", idx);
242 close(pollfds[idx].fd);
244 for(i=0; i<_WAPI_MAX_HANDLES; i++) {
245 handle_count=open_handles[i];
247 for(j=0; j<handle_count; j++) {
249 g_message (G_GNUC_PRETTY_FUNCTION ": closing handle 0x%x for client at index %d", i, idx);
251 /* Ignore the hint to the client to destroy
252 * the handle private data
254 unref_handle (idx, i);
260 /* Just the master socket left, so see if we can
266 memset(&pollfds[idx], '\0', sizeof(struct pollfd));
267 g_free (handle_refs[idx]);
270 memmove(&pollfds[idx], &pollfds[idx+1],
271 sizeof(struct pollfd) * (nfds-idx));
272 memmove (&handle_refs[idx], &handle_refs[idx+1],
273 sizeof(guint32) * (nfds-idx));
277 static gboolean process_compare (gpointer handle, gpointer user_data)
279 struct _WapiHandle_process *process_handle;
283 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
284 (gpointer *)&process_handle, NULL);
286 g_warning (G_GNUC_PRETTY_FUNCTION
287 ": error looking up process handle %p", handle);
291 pid=GPOINTER_TO_UINT (user_data);
292 if(process_handle->id==pid) {
299 static gboolean process_thread_compare (gpointer handle, gpointer user_data)
301 struct _WapiHandle_thread *thread_handle;
304 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
305 (gpointer *)&thread_handle, NULL);
307 g_warning (G_GNUC_PRETTY_FUNCTION
308 ": error looking up thread handle %p", handle);
312 if(thread_handle->process_handle==user_data) {
313 /* Signal the handle. Don't use
314 * _wapi_handle_set_signal_state() unless we have
315 * process-shared pthread support.
318 g_message (G_GNUC_PRETTY_FUNCTION ": Set thread handle %p signalled, because its process died", handle);
321 thread_handle->exitstatus=0;
323 #ifdef _POSIX_THREAD_PROCESS_SHARED
324 _wapi_handle_lock_handle (handle);
325 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
326 _wapi_handle_unlock_handle (handle);
328 /* Just tweak the signal state directly. This is not
329 * recommended behaviour, but it works for threads
330 * because they can never become unsignalled. There
331 * are some nasty kludges in the handle waiting code
332 * to cope with missing condition signals for when
333 * process-shared pthread support is missing.
335 _wapi_shared_data->handles[GPOINTER_TO_UINT (handle)].signalled=TRUE;
336 #endif /* _POSIX_THREAD_PROCESS_SHARED */
339 /* Return false to keep searching */
343 /* Find the handle associated with pid, mark it dead and record exit
344 * status. Finds all thread handles associated with this process
345 * handle, and marks those signalled too, with exitstatus '0'. It
346 * also drops the daemon's reference to the handle, and the thread
347 * pointed at by main_thread.
349 static void process_post_mortem (pid_t pid, int status)
351 gpointer process_handle;
352 struct _WapiHandle_process *process_handle_data;
354 process_handle=_wapi_search_handle (WAPI_HANDLE_PROCESS,
356 GUINT_TO_POINTER (pid),
357 (gpointer *)&process_handle_data,
359 if(process_handle==0) {
360 g_warning (G_GNUC_PRETTY_FUNCTION
361 ": Couldn't find handle for process %d!", pid);
363 /* Signal the handle. Don't use
364 * _wapi_handle_set_signal_state() unless we have
365 * process-shared pthread support.
368 g_message (G_GNUC_PRETTY_FUNCTION
369 ": Set process %d exitstatus to %d", pid,
370 WEXITSTATUS (status));
373 /* Technically WEXITSTATUS is only valid if the
374 * process exited normally, but I don't care if the
375 * process caught a signal or not.
377 process_handle_data->exitstatus=WEXITSTATUS (status);
378 _wapi_time_t_to_filetime (time (NULL),
379 &process_handle_data->exit_time);
381 #ifdef _POSIX_THREAD_PROCESS_SHARED
382 _wapi_handle_lock_handle (process_handle);
383 _wapi_handle_set_signal_state (process_handle, TRUE, TRUE);
384 _wapi_handle_unlock_handle (process_handle);
386 /* Just tweak the signal state directly. This is not
387 * recommended behaviour, but it works for processes
388 * because they can never become unsignalled. There
389 * are some nasty kludges in the handle waiting code
390 * to cope with missing condition signals for when
391 * process-shared pthread support is missing.
393 _wapi_shared_data->handles[GPOINTER_TO_UINT (process_handle)].signalled=TRUE;
394 #endif /* _POSIX_THREAD_PROCESS_SHARED */
397 /* Find all threads that have their process
398 * handle==process_handle. Ignore the return value, all the
399 * work will be done in the compare func
401 (void)_wapi_search_handle (WAPI_HANDLE_THREAD, process_thread_compare,
402 process_handle, NULL, NULL);
404 unref_handle (0, GPOINTER_TO_UINT (process_handle_data->main_thread));
405 unref_handle (0, GPOINTER_TO_UINT (process_handle));
408 static void process_died (void)
413 check_processes=FALSE;
416 g_message (G_GNUC_PRETTY_FUNCTION ": Reaping processes");
420 pid=waitpid (-1, &status, WNOHANG);
421 if(pid==0 || pid==-1) {
422 /* Finished waiting. I was checking pid==-1
423 * separately but was getting ECHILD when
424 * there were no more child processes (which
425 * doesnt seem to conform to the man page)
429 /* pid contains the ID of a dead process */
431 g_message (G_GNUC_PRETTY_FUNCTION ": process %d reaped", pid);
433 process_post_mortem (pid, status);
438 static void send_reply (guint32 idx, WapiHandleResponse *resp)
441 _wapi_daemon_response (pollfds[idx].fd, resp);
444 static void process_new (guint32 idx, WapiHandleType type)
447 WapiHandleResponse resp;
449 /* handle might be set to 0. This is handled at the client end */
450 handle=_wapi_handle_new_internal (type);
451 ref_handle (idx, handle);
454 g_message (G_GNUC_PRETTY_FUNCTION ": returning new handle 0x%x",
458 resp.type=WapiHandleResponseType_New;
459 resp.u.new.type=type;
460 resp.u.new.handle=handle;
462 send_reply (idx, &resp);
465 static void process_open (guint32 idx, guint32 handle)
467 WapiHandleResponse resp;
468 struct _WapiHandleShared *shared=&_wapi_shared_data->handles[handle];
470 if(shared->type!=WAPI_HANDLE_UNUSED && handle!=0) {
471 ref_handle (idx, handle);
474 g_message (G_GNUC_PRETTY_FUNCTION
475 ": returning new handle 0x%x", handle);
478 resp.type=WapiHandleResponseType_Open;
479 resp.u.new.type=shared->type;
480 resp.u.new.handle=handle;
482 send_reply (idx, &resp);
487 resp.type=WapiHandleResponseType_Open;
490 send_reply (idx, &resp);
493 static void process_close (guint32 idx, guint32 handle)
495 WapiHandleResponse resp;
497 resp.type=WapiHandleResponseType_Close;
498 resp.u.close.destroy=unref_handle (idx, handle);
501 g_message (G_GNUC_PRETTY_FUNCTION ": unreffing handle 0x%x", handle);
504 send_reply (idx, &resp);
507 static void process_scratch (guint32 idx, guint32 length)
509 WapiHandleResponse resp;
511 resp.type=WapiHandleResponseType_Scratch;
512 resp.u.scratch.idx=_wapi_handle_scratch_store_internal (length);
515 g_message (G_GNUC_PRETTY_FUNCTION ": allocating scratch index 0x%x",
519 send_reply (idx, &resp);
522 static void process_scratch_free (guint32 idx, guint32 scratch_idx)
524 WapiHandleResponse resp;
526 resp.type=WapiHandleResponseType_ScratchFree;
527 _wapi_handle_scratch_delete_internal (scratch_idx);
530 g_message (G_GNUC_PRETTY_FUNCTION ": deleting scratch index 0x%x",
534 send_reply (idx, &resp);
537 static void process_process_fork (guint32 idx,
538 WapiHandleRequest_ProcessFork process_fork)
540 WapiHandleResponse resp;
541 guint32 process_handle, thread_handle;
542 struct _WapiHandle_process *process_handle_data;
543 struct _WapiHandle_thread *thread_handle_data;
546 resp.type=WapiHandleResponseType_ProcessFork;
548 /* Create handles first, so the child process can store exec
549 * errors. Either handle might be set to 0, if this happens
550 * just reply to the client without bothering to fork. The
551 * client must check if either handle is 0 and take
552 * appropriate error handling action.
554 process_handle=_wapi_handle_new_internal (WAPI_HANDLE_PROCESS);
555 ref_handle (0, process_handle);
556 ref_handle (idx, process_handle);
558 thread_handle=_wapi_handle_new_internal (WAPI_HANDLE_THREAD);
559 ref_handle (0, thread_handle);
560 ref_handle (idx, thread_handle);
562 if(process_handle==0 || thread_handle==0) {
563 /* unref_handle() copes with the handle being 0 */
564 unref_handle (0, process_handle);
565 unref_handle (idx, process_handle);
566 unref_handle (0, thread_handle);
567 unref_handle (idx, thread_handle);
571 char *cmd=NULL, *args=NULL;
573 /* Get usable copies of the cmd and args now rather
574 * than in the child process. This is to prevent the
575 * race condition where the parent can return the
576 * reply to the client, which then promptly deletes
577 * the scratch data before the new process gets to see
580 cmd=_wapi_handle_scratch_lookup_as_string (process_fork.cmd);
581 if(process_fork.args!=0) {
582 args=_wapi_handle_scratch_lookup_as_string (process_fork.args);
586 g_message (G_GNUC_PRETTY_FUNCTION ": forking");
589 _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
591 (gpointer *)&process_handle_data, NULL);
593 _wapi_lookup_handle (GUINT_TO_POINTER (thread_handle),
595 (gpointer *)&thread_handle_data, NULL);
597 /* Fork, exec cmd with args and optional env, and
598 * return the handles with pid and blank thread id
602 process_handle_data->exec_errno=errno;
607 /* should we detach from the process group?
608 * We're already running without a controlling
611 if(process_fork.inherit!=TRUE) {
612 /* Close all file descriptors */
615 /* Connect stdin, stdout and stderr */
618 g_message (G_GNUC_PRETTY_FUNCTION
619 ": exec()ing [%s] args [%s]", cmd, args);
623 argv=g_strsplit (args, " \t", 0);
625 argv=g_new0 (char *, 1);
632 process_handle_data->exec_errno=errno;
638 process_handle_data->id=pid;
639 process_handle_data->main_thread=GUINT_TO_POINTER (thread_handle);
640 _wapi_time_t_to_filetime (time (NULL),
641 &process_handle_data->create_time);
643 /* FIXME: if env==0, inherit the env from the current
646 process_handle_data->env=process_fork.env;
648 thread_handle_data->process_handle=GUINT_TO_POINTER (process_handle);
650 resp.u.process_fork.pid=pid;
653 resp.u.process_fork.process_handle=process_handle;
654 resp.u.process_fork.thread_handle=thread_handle;
656 send_reply (idx, &resp);
659 static void read_message (guint32 idx)
661 WapiHandleRequest req;
664 _wapi_daemon_request (pollfds[idx].fd, &req);
666 case WapiHandleRequestType_New:
667 process_new (idx, req.u.new.type);
669 case WapiHandleRequestType_Open:
670 process_open (idx, req.u.open.handle);
672 case WapiHandleRequestType_Close:
673 process_close (idx, req.u.close.handle);
675 case WapiHandleRequestType_Scratch:
676 process_scratch (idx, req.u.scratch.length);
678 case WapiHandleRequestType_ScratchFree:
679 process_scratch_free (idx, req.u.scratch_free.idx);
681 case WapiHandleRequestType_ProcessFork:
682 process_process_fork (idx, req.u.process_fork);
687 int main(int argc, char **argv)
689 struct sockaddr_un main_socket_address;
693 g_message ("Starting up...");
698 main_sock=socket(PF_UNIX, SOCK_STREAM, 0);
700 main_socket_address.sun_family=AF_UNIX;
701 memcpy(main_socket_address.sun_path, _wapi_shared_data->daemon, 108);
703 ret=bind(main_sock, (struct sockaddr *)&main_socket_address,
704 sizeof(struct sockaddr_un));
706 g_warning ("bind failed: %s", strerror (errno));
707 _wapi_shared_data->daemon_running=2;
715 ret=listen(main_sock, 5);
717 g_warning ("listen failed: %s", strerror (errno));
718 _wapi_shared_data->daemon_running=2;
723 g_message("listening");
728 /* We're finished setting up, let everyone else know we're
729 * ready. From now on, it's up to us to delete the shared
730 * memory segment when appropriate.
732 _wapi_shared_data->daemon_running=1;
737 if(check_processes==TRUE) {
742 g_message ("polling");
745 /* Block until something happens */
746 ret=poll(pollfds, nfds, -1);
747 if(ret==-1 && errno!=EINTR) {
748 g_message ("poll error: %s", strerror (errno));
753 for(i=0; i<nfds; i++) {
754 if(((pollfds[i].revents&POLLHUP)==POLLHUP) ||
755 ((pollfds[i].revents&POLLERR)==POLLERR) ||
756 ((pollfds[i].revents&POLLNVAL)==POLLNVAL)) {
758 g_message ("fd[%d] %d error", i,
762 } else if((pollfds[i].revents&POLLIN)==POLLIN) {
763 if(pollfds[i].fd==main_sock) {
765 struct sockaddr addr;
766 socklen_t addrlen=sizeof(struct sockaddr);
767 newsock=accept(main_sock, &addr,
770 g_message("accept error: %s",
776 g_message ("accept returning %d",
782 g_message ("reading data on fd %d",