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>
29 #include <mono/io-layer/daemon-private.h>
33 /* The shared thread codepath doesn't seem to work yet... */
34 #undef _POSIX_THREAD_PROCESS_SHARED
36 /* Keep track of the number of clients */
38 /* Array to keep track of handles that have been referenced by the
41 static guint32 *daemon_handles=NULL;
42 /* The socket which we listen to new connections on */
45 /* Set to TRUE by the SIGCHLD signal handler */
46 static volatile gboolean check_processes=FALSE;
48 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
52 /* Deletes the shared memory segment. If we're exiting on error,
53 * clients will get EPIPEs.
55 static void cleanup (void)
57 #ifdef NEED_LINK_UNLINK
58 unlink(_wapi_shared_data->daemon);
63 /* If there is only one socket, and no child processes, we can exit.
64 * We test for child processes by counting handle references held by
67 static void maybe_exit (void)
72 g_message (G_GNUC_PRETTY_FUNCTION ": Seeing if we should exit");
77 g_message (G_GNUC_PRETTY_FUNCTION ": Still got clients");
82 for(i=0; i<_WAPI_MAX_HANDLES; i++) {
83 if(daemon_handles[i]>0) {
85 g_message (G_GNUC_PRETTY_FUNCTION
86 ": Still got handle references");
93 g_message (G_GNUC_PRETTY_FUNCTION ": Byebye");
104 * Called if daemon receives a SIGTERM or SIGINT
106 static void signal_handler (int unused)
116 * Called if daemon receives a SIGCHLD, and notes that a process needs
117 * to be wait()ed for.
119 static void sigchld_handler (int unused)
121 /* Notice that a child process died */
122 check_processes=TRUE;
128 * Bind signals and attach to shared memory
130 static void startup (void)
136 sa.sa_handler=signal_handler;
137 sigemptyset (&sa.sa_mask);
139 sigaction (SIGINT, &sa, NULL);
140 sigaction (SIGTERM, &sa, NULL);
142 #ifndef HAVE_MSG_NOSIGNAL
143 sa.sa_handler=SIG_IGN;
144 sigaction (SIGPIPE, &sa, NULL);
147 sa.sa_handler=sigchld_handler;
148 sa.sa_flags=SA_NOCLDSTOP;
149 sigaction (SIGCHLD, &sa, NULL);
151 _wapi_shared_data=_wapi_shm_attach (TRUE, &success, &shm_id);
153 g_error ("Failed to attach shared memory! (tried shared memory ID 0x%x)", shm_id);
157 #ifdef NEED_LINK_UNLINK
158 /* Here's a more portable method... */
159 snprintf (_wapi_shared_data->daemon, MONO_SIZEOF_SUNPATH-1,
160 "/tmp/mono-handle-daemon-%d-%ld-%ld", getuid (), random (),
163 /* Leave the first byte NULL so we create the socket in the
164 * abstrace namespace, not on the filesystem. (Lets see how
165 * portable _that_ is :)
167 * The name is intended to be unique, not cryptographically
170 snprintf (_wapi_shared_data->daemon+1, MONO_SIZEOF_SUNPATH-2,
171 "mono-handle-daemon-%d-%d-%ld", getuid (), getpid (),
179 * @open_handles: An array of handles referenced by the calling client
180 * @handle: handle to inc refcnt
182 * Increase ref count of handle for the calling client. Handle 0 is
185 static void ref_handle (guint32 *open_handles, guint32 handle)
191 _wapi_shared_data->handles[handle].ref++;
192 open_handles[handle]++;
195 g_message (G_GNUC_PRETTY_FUNCTION
196 ": handle 0x%x ref now %d (%d this process)", handle,
197 _wapi_shared_data->handles[handle].ref,
198 open_handles[handle]);
204 * @open_handles: An array of handles referenced by the calling client
205 * @handle: handle to inc refcnt
207 * Decrease ref count of handle for the calling client. If global ref
208 * count reaches 0 it is free'ed. Return TRUE if the local ref count
209 * is 0. Handle 0 is ignored.
211 static gboolean unref_handle (guint32 *open_handles, guint32 handle)
213 gboolean destroy=FALSE;
219 if (open_handles[handle] == 0) {
220 g_warning(G_GNUC_PRETTY_FUNCTION
221 ": unref on %d called when ref was already 0",
226 _wapi_shared_data->handles[handle].ref--;
227 open_handles[handle]--;
230 g_message (G_GNUC_PRETTY_FUNCTION
231 ": handle 0x%x ref now %d (%d this process)", handle,
232 _wapi_shared_data->handles[handle].ref,
233 open_handles[handle]);
236 if(open_handles[handle]==0) {
237 /* This client has released the handle */
241 if(_wapi_shared_data->handles[handle].ref==0) {
242 if (open_handles[handle]!=0) {
243 g_warning (G_GNUC_PRETTY_FUNCTION ": per-process open_handles mismatch, set to %d, should be 0", open_handles[handle]);
247 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle 0x%x",
251 _wapi_handle_ops_close_shared (GUINT_TO_POINTER (handle));
253 mono_mutex_destroy (&_wapi_shared_data->handles[handle].signal_mutex);
254 pthread_cond_destroy (&_wapi_shared_data->handles[handle].signal_cond);
255 memset (&_wapi_shared_data->handles[handle].u, '\0', sizeof(_wapi_shared_data->handles[handle].u));
258 if(open_handles==daemon_handles) {
259 /* The daemon released a reference, so see if it's
270 * @fd: Filehandle to add
272 * Create a new GIOChannel, and add it to the main loop event sources.
274 static void add_fd(int fd)
276 GIOChannel *io_channel;
279 io_channel=g_io_channel_unix_new (fd);
281 /* Turn off all encoding and buffering crap */
282 g_io_channel_set_encoding (io_channel, NULL, NULL);
283 g_io_channel_set_buffered (io_channel, FALSE);
285 refs=g_new0 (guint32, _WAPI_MAX_HANDLES);
286 if(daemon_handles==NULL) {
287 /* We rely on the daemon channel being created first.
288 * That's safe, because every other channel is the
289 * result of an accept() on the daemon channel.
294 g_io_add_watch (io_channel, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
302 * @channel: GIOChannel to close
304 * Closes the IO channel. Closes all handles that it may have open. If
305 * only main_sock is left, the daemon is shut down.
307 static void rem_fd(GIOChannel *channel, guint32 *open_handles)
309 guint32 handle_count;
312 if(g_io_channel_unix_get_fd (channel) == main_sock) {
313 /* We shouldn't be deleting the daemon's fd */
314 g_warning (G_GNUC_PRETTY_FUNCTION ": Deleting daemon fd!");
320 g_message (G_GNUC_PRETTY_FUNCTION ": Removing client fd %d",
321 g_io_channel_unix_get_fd (channel));
324 g_io_channel_shutdown (channel, TRUE, NULL);
326 for(i=0; i<_WAPI_MAX_HANDLES; i++) {
327 handle_count=open_handles[i];
329 for(j=0; j<handle_count; j++) {
331 g_message (G_GNUC_PRETTY_FUNCTION ": closing handle 0x%x for client at index %d", i, g_io_channel_unix_get_fd (channel));
333 /* Ignore the hint to the client to destroy
334 * the handle private data
336 unref_handle (open_handles, i);
340 g_free (open_handles);
344 /* Just the master socket left, so see if we can
351 static gboolean process_compare (gpointer handle, gpointer user_data)
353 struct _WapiHandle_process *process_handle;
357 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
358 (gpointer *)&process_handle, NULL);
360 g_warning (G_GNUC_PRETTY_FUNCTION
361 ": error looking up process handle %p", handle);
365 pid=GPOINTER_TO_UINT (user_data);
366 if(process_handle->id==pid) {
373 static gboolean process_thread_compare (gpointer handle, gpointer user_data)
375 struct _WapiHandle_thread *thread_handle;
378 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
379 (gpointer *)&thread_handle, NULL);
381 g_warning (G_GNUC_PRETTY_FUNCTION
382 ": error looking up thread handle %p", handle);
386 if(thread_handle->process_handle==user_data) {
387 /* Signal the handle. Don't use
388 * _wapi_handle_set_signal_state() unless we have
389 * process-shared pthread support.
392 g_message (G_GNUC_PRETTY_FUNCTION ": Set thread handle %p signalled, because its process died", handle);
395 thread_handle->exitstatus=0;
397 #ifdef _POSIX_THREAD_PROCESS_SHARED
398 _wapi_handle_lock_handle (handle);
399 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
400 _wapi_handle_unlock_handle (handle);
402 /* Just tweak the signal state directly. This is not
403 * recommended behaviour, but it works for threads
404 * because they can never become unsignalled. There
405 * are some nasty kludges in the handle waiting code
406 * to cope with missing condition signals for when
407 * process-shared pthread support is missing.
409 _wapi_shared_data->handles[GPOINTER_TO_UINT (handle)].signalled=TRUE;
410 #endif /* _POSIX_THREAD_PROCESS_SHARED */
413 /* Return false to keep searching */
417 /* Find the handle associated with pid, mark it dead and record exit
418 * status. Finds all thread handles associated with this process
419 * handle, and marks those signalled too, with exitstatus '0'. It
420 * also drops the daemon's reference to the handle, and the thread
421 * pointed at by main_thread.
423 static void process_post_mortem (pid_t pid, int status)
425 gpointer process_handle;
426 struct _WapiHandle_process *process_handle_data;
428 process_handle=_wapi_search_handle (WAPI_HANDLE_PROCESS,
430 GUINT_TO_POINTER (pid),
431 (gpointer *)&process_handle_data,
433 if(process_handle==0) {
434 g_warning (G_GNUC_PRETTY_FUNCTION
435 ": Couldn't find handle for process %d!", pid);
437 /* Signal the handle. Don't use
438 * _wapi_handle_set_signal_state() unless we have
439 * process-shared pthread support.
442 g_message (G_GNUC_PRETTY_FUNCTION
443 ": Set process %d exitstatus to %d", pid,
444 WEXITSTATUS (status));
447 /* Technically WEXITSTATUS is only valid if the
448 * process exited normally, but I don't care if the
449 * process caught a signal or not.
451 process_handle_data->exitstatus=WEXITSTATUS (status);
452 _wapi_time_t_to_filetime (time (NULL),
453 &process_handle_data->exit_time);
455 #ifdef _POSIX_THREAD_PROCESS_SHARED
456 _wapi_handle_lock_handle (process_handle);
457 _wapi_handle_set_signal_state (process_handle, TRUE, TRUE);
458 _wapi_handle_unlock_handle (process_handle);
460 /* Just tweak the signal state directly. This is not
461 * recommended behaviour, but it works for processes
462 * because they can never become unsignalled. There
463 * are some nasty kludges in the handle waiting code
464 * to cope with missing condition signals for when
465 * process-shared pthread support is missing.
467 _wapi_shared_data->handles[GPOINTER_TO_UINT (process_handle)].signalled=TRUE;
468 #endif /* _POSIX_THREAD_PROCESS_SHARED */
471 /* Find all threads that have their process
472 * handle==process_handle. Ignore the return value, all the
473 * work will be done in the compare func
475 (void)_wapi_search_handle (WAPI_HANDLE_THREAD, process_thread_compare,
476 process_handle, NULL, NULL);
478 unref_handle (daemon_handles,
479 GPOINTER_TO_UINT (process_handle_data->main_thread));
480 unref_handle (daemon_handles, GPOINTER_TO_UINT (process_handle));
483 static void process_died (void)
488 check_processes=FALSE;
491 g_message (G_GNUC_PRETTY_FUNCTION ": Reaping processes");
495 pid=waitpid (-1, &status, WNOHANG);
496 if(pid==0 || pid==-1) {
497 /* Finished waiting. I was checking pid==-1
498 * separately but was getting ECHILD when
499 * there were no more child processes (which
500 * doesnt seem to conform to the man page)
504 /* pid contains the ID of a dead process */
506 g_message (G_GNUC_PRETTY_FUNCTION ": process %d reaped", pid);
508 process_post_mortem (pid, status);
516 * @channel: channel to send reply to
517 * @resp: Package to send
519 * Send a package to a client
521 static void send_reply (GIOChannel *channel, WapiHandleResponse *resp)
524 _wapi_daemon_response (g_io_channel_unix_get_fd (channel), resp);
529 * @channel: The client making the request
530 * @open_handles: An array of handles referenced by this client
531 * @type: type to init handle to
533 * Find a free handle and initialize it to 'type', increase refcnt and
534 * send back a reply to the client.
536 static void process_new (GIOChannel *channel, guint32 *open_handles,
540 WapiHandleResponse resp;
542 /* handle might be set to 0. This is handled at the client end */
543 handle=_wapi_handle_new_internal (type);
544 ref_handle (open_handles, handle);
547 g_message (G_GNUC_PRETTY_FUNCTION ": returning new handle 0x%x",
551 resp.type=WapiHandleResponseType_New;
552 resp.u.new.type=type;
553 resp.u.new.handle=handle;
555 send_reply (channel, &resp);
560 * @channel: The client making the request
561 * @open_handles: An array of handles referenced by this client
562 * @handle: handle no.
564 * Increase refcnt on a previously created handle and send back a
565 * response to the client.
567 static void process_open (GIOChannel *channel, guint32 *open_handles,
570 WapiHandleResponse resp;
571 struct _WapiHandleShared *shared=&_wapi_shared_data->handles[handle];
573 if(shared->type!=WAPI_HANDLE_UNUSED && handle!=0) {
574 ref_handle (open_handles, handle);
577 g_message (G_GNUC_PRETTY_FUNCTION
578 ": returning new handle 0x%x", handle);
581 resp.type=WapiHandleResponseType_Open;
582 resp.u.new.type=shared->type;
583 resp.u.new.handle=handle;
585 send_reply (channel, &resp);
590 resp.type=WapiHandleResponseType_Open;
593 send_reply (channel, &resp);
598 * @channel: The client making the request
599 * @open_handles: An array of handles referenced by this client
600 * @handle: handle no.
602 * Decrease refcnt on a previously created handle and send back a
603 * response to the client with notice of it being destroyed.
605 static void process_close (GIOChannel *channel, guint32 *open_handles,
608 WapiHandleResponse resp;
610 resp.type=WapiHandleResponseType_Close;
611 resp.u.close.destroy=unref_handle (open_handles, handle);
614 g_message (G_GNUC_PRETTY_FUNCTION ": unreffing handle 0x%x", handle);
617 send_reply (channel, &resp);
622 * @channel: The client making the request
623 * @length: allocate this much scratch space
625 * Allocate some scratch space and send a reply to the client.
627 static void process_scratch (GIOChannel *channel, guint32 length)
629 WapiHandleResponse resp;
631 resp.type=WapiHandleResponseType_Scratch;
632 resp.u.scratch.idx=_wapi_handle_scratch_store_internal (length);
635 g_message (G_GNUC_PRETTY_FUNCTION ": allocating scratch index 0x%x",
639 send_reply (channel, &resp);
643 * process_scratch_free:
644 * @channel: The client making the request
645 * @scratch_idx: deallocate this scratch space
647 * Deallocate scratch space and send a reply to the client.
649 static void process_scratch_free (GIOChannel *channel, guint32 scratch_idx)
651 WapiHandleResponse resp;
653 resp.type=WapiHandleResponseType_ScratchFree;
654 _wapi_handle_scratch_delete_internal (scratch_idx);
657 g_message (G_GNUC_PRETTY_FUNCTION ": deleting scratch index 0x%x",
661 send_reply (channel, &resp);
665 * process_process_fork:
666 * @channel: The client making the request
667 * @open_handles: An array of handles referenced by this client
668 * @process_fork: Describes the process to fork
669 * @fds: stdin, stdout, and stderr for the new process
671 * Forks a new process, and returns the process and thread data to the
674 static void process_process_fork (GIOChannel *channel, guint32 *open_handles,
675 WapiHandleRequest_ProcessFork process_fork,
678 WapiHandleResponse resp;
679 guint32 process_handle, thread_handle;
680 struct _WapiHandle_process *process_handle_data;
681 struct _WapiHandle_thread *thread_handle_data;
684 resp.type=WapiHandleResponseType_ProcessFork;
686 /* Create handles first, so the child process can store exec
687 * errors. Either handle might be set to 0, if this happens
688 * just reply to the client without bothering to fork. The
689 * client must check if either handle is 0 and take
690 * appropriate error handling action.
692 process_handle=_wapi_handle_new_internal (WAPI_HANDLE_PROCESS);
693 ref_handle (daemon_handles, process_handle);
694 ref_handle (open_handles, process_handle);
696 thread_handle=_wapi_handle_new_internal (WAPI_HANDLE_THREAD);
697 ref_handle (daemon_handles, thread_handle);
698 ref_handle (open_handles, thread_handle);
700 if(process_handle==0 || thread_handle==0) {
701 /* unref_handle() copes with the handle being 0 */
702 unref_handle (daemon_handles, process_handle);
703 unref_handle (open_handles, process_handle);
704 unref_handle (daemon_handles, thread_handle);
705 unref_handle (open_handles, thread_handle);
709 char *cmd=NULL, *args=NULL;
711 /* Get usable copies of the cmd and args now rather
712 * than in the child process. This is to prevent the
713 * race condition where the parent can return the
714 * reply to the client, which then promptly deletes
715 * the scratch data before the new process gets to see
718 cmd=_wapi_handle_scratch_lookup_as_string (process_fork.cmd);
719 if(process_fork.args!=0) {
720 args=_wapi_handle_scratch_lookup_as_string (process_fork.args);
724 g_message (G_GNUC_PRETTY_FUNCTION ": forking");
727 _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
729 (gpointer *)&process_handle_data, NULL);
731 _wapi_lookup_handle (GUINT_TO_POINTER (thread_handle),
733 (gpointer *)&thread_handle_data, NULL);
735 /* Fork, exec cmd with args and optional env, and
736 * return the handles with pid and blank thread id
740 process_handle_data->exec_errno=errno;
743 char **argv, *full_args;
748 /* should we detach from the process group?
749 * We're already running without a controlling
753 /* Connect stdin, stdout and stderr */
758 if(process_fork.inherit!=TRUE) {
759 /* FIXME: do something here */
762 /* Close all file descriptors */
763 for(i=3; i<getdtablesize (); i++) {
768 g_message (G_GNUC_PRETTY_FUNCTION
769 ": exec()ing [%s] args [%s]", cmd, args);
773 full_args=g_strconcat (cmd, " ", args, NULL);
775 full_args=g_strdup (cmd);
777 ret=g_shell_parse_argv (full_args, NULL, &argv, &gerr);
782 /* FIXME: Could do something with the
785 process_handle_data->exec_errno=gerr->code;
793 while(argv[i]!=NULL) {
794 g_message ("arg %d: [%s]", i, argv[i]);
805 process_handle_data->exec_errno=errno;
811 process_handle_data->id=pid;
812 process_handle_data->main_thread=GUINT_TO_POINTER (thread_handle);
813 _wapi_time_t_to_filetime (time (NULL),
814 &process_handle_data->create_time);
816 /* FIXME: if env==0, inherit the env from the current
819 process_handle_data->env=process_fork.env;
821 thread_handle_data->process_handle=GUINT_TO_POINTER (process_handle);
823 resp.u.process_fork.pid=pid;
826 resp.u.process_fork.process_handle=process_handle;
827 resp.u.process_fork.thread_handle=thread_handle;
829 send_reply (channel, &resp);
834 * @channel: The client to read the request from
835 * @open_handles: An array of handles referenced by this client
837 * Read a message (A WapiHandleRequest) from a client and dispatch
838 * whatever it wants to the process_* calls.
840 static void read_message (GIOChannel *channel, guint32 *open_handles)
842 WapiHandleRequest req;
843 int fds[3]={0, 1, 2};
845 gboolean has_fds=FALSE;
848 ret=_wapi_daemon_request (g_io_channel_unix_get_fd (channel), &req,
851 /* Other end went away */
853 g_message ("Read 0 bytes on fd %d, closing it",
854 g_io_channel_unix_get_fd (channel));
857 rem_fd (channel, open_handles);
862 case WapiHandleRequestType_New:
863 process_new (channel, open_handles, req.u.new.type);
865 case WapiHandleRequestType_Open:
867 g_assert(req.u.open.handle < _WAPI_MAX_HANDLES);
869 process_open (channel, open_handles, req.u.open.handle);
871 case WapiHandleRequestType_Close:
873 g_assert(req.u.close.handle < _WAPI_MAX_HANDLES);
875 process_close (channel, open_handles, req.u.close.handle);
877 case WapiHandleRequestType_Scratch:
878 process_scratch (channel, req.u.scratch.length);
880 case WapiHandleRequestType_ScratchFree:
881 process_scratch_free (channel, req.u.scratch_free.idx);
883 case WapiHandleRequestType_ProcessFork:
884 process_process_fork (channel, open_handles,
885 req.u.process_fork, fds);
887 case WapiHandleRequestType_Error:
890 /* Catch bogus requests */
891 /* FIXME: call rem_fd? */
897 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[0]);
898 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[1]);
899 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[2]);
910 * @channel: The IO channel that is active
911 * @condition: The condition that has been satisfied
912 * @data: A pointer to an array of handles referenced by this client
914 * The callback called by the main loop when there is activity on an
917 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
920 if(condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
922 g_message ("fd %d error", g_io_channel_unix_get_fd (channel));
925 rem_fd (channel, data);
929 if(condition & (G_IO_IN | G_IO_PRI)) {
930 if(g_io_channel_unix_get_fd (channel)==main_sock) {
932 struct sockaddr addr;
933 socklen_t addrlen=sizeof(struct sockaddr);
935 newsock=accept (main_sock, &addr, &addrlen);
937 g_critical ("accept error: %s", strerror (errno));
943 g_message ("accept returning %d", newsock);
949 g_message ("reading data on fd %d",
950 g_io_channel_unix_get_fd (channel));
953 read_message (channel, data);
958 return(FALSE); /* remove source */
964 * Open socket, create shared mem segment and begin listening for
967 void _wapi_daemon_main(void)
969 struct sockaddr_un main_socket_address;
973 g_message ("Starting up...");
978 main_sock=socket(PF_UNIX, SOCK_STREAM, 0);
980 main_socket_address.sun_family=AF_UNIX;
981 memcpy(main_socket_address.sun_path, _wapi_shared_data->daemon,
982 MONO_SIZEOF_SUNPATH);
984 ret=bind(main_sock, (struct sockaddr *)&main_socket_address,
985 sizeof(struct sockaddr_un));
987 g_critical ("bind failed: %s", strerror (errno));
988 _wapi_shared_data->daemon_running=DAEMON_DIED_AT_STARTUP;
996 ret=listen(main_sock, 5);
998 g_critical ("listen failed: %s", strerror (errno));
999 _wapi_shared_data->daemon_running=DAEMON_DIED_AT_STARTUP;
1004 g_message("listening");
1009 /* We're finished setting up, let everyone else know we're
1010 * ready. From now on, it's up to us to delete the shared
1011 * memory segment when appropriate.
1013 _wapi_shared_data->daemon_running=DAEMON_RUNNING;
1016 if(check_processes==TRUE) {
1021 g_message ("polling");
1024 /* Block until something happens. We don't use
1025 * g_main_loop_run() because we rely on the SIGCHLD
1026 * signal interrupting poll() so we can reap child
1027 * processes as soon as they die, without burning cpu
1028 * time by polling the flag.
1030 g_main_context_iteration (g_main_context_default (), TRUE);