/* proc PID identification */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "proc.h" #include /* Transaction handling. */ /* Since the user is responsible for freeing the rendezvous port, it has to * wait for the server to have finished transmitting the pid. * * The server thus waits for the user to give it the pid (unless it was already * there), transmits them and provides the passthrough port. * * The user gives the pid and waits for the passthrough port from the server. * * If the user is early, it has to tell the server it arrived. */ /* A pending user. */ struct pending_user { hurd_ihash_locp_t locp; /* Position in the pending_users ihash table. */ pthread_cond_t wakeup; /* The reader is blocked on this condition. */ /* The user's identity */ struct proc *user; /* The port to pass back to the user. */ mach_port_t passthrough; }; /* A pending server. */ struct pending_server { hurd_ihash_locp_t locp; /* Position in the pending_servers ihash table. */ pthread_cond_t wakeup; /* The server is blocked on this condition. */ }; /* Table of pending transactions keyed on RENDEZVOUS. */ struct hurd_ihash pending_users = HURD_IHASH_INITIALIZER (offsetof (struct pending_user, locp)); struct hurd_ihash pending_servers = HURD_IHASH_INITIALIZER (offsetof (struct pending_server, locp)); pthread_mutex_t pending_lock = PTHREAD_MUTEX_INITIALIZER; /* Implement proc_user_identify as described in . */ kern_return_t S_proc_user_identify (struct proc *userident, mach_port_t rendezvous, mach_port_t *newport, mach_msg_type_name_t *newporttype, pid_t pid) { struct pending_server *s; struct pending_user u; error_t err; if (! userident) return EOPNOTSUPP; if (! MACH_PORT_VALID (rendezvous)) return EINVAL; fprintf(stderr, "S_proc_user_identify: ENTER rendezvous=%d\n", (int)rendezvous); fprintf(stderr, "S_proc_user_identify: *newport = %d, pid=%d\n", (int)*newport, (int)pid); fprintf(stderr, "S_proc_user_identify: userident->p_pid = %d\n", userident->p_pid); fflush(stderr); u.user = userident; pthread_cond_init (&u.wakeup, NULL); pthread_mutex_lock (&pending_lock); err = hurd_ihash_add (&pending_users, rendezvous, &u); if (err) { fprintf(stderr, "S_proc_user_identify: AFTER hurd_ihash_add err = %s\n", strerror(err)); fflush(stderr); pthread_mutex_unlock (&pending_lock); return err; } /* Give the server the ident port. We need to add a ref in case the port dies. */ ports_port_ref (userident); fprintf(stderr, "S_proc_user_identify: BEFORE hurd_ihash_find\n"); fflush(stderr); /* Look for this rendezvous in the server list. */ s = hurd_ihash_find (&pending_servers, rendezvous); if (s) fprintf(stderr, "S_proc_user_identify: s != NULL\n"); else fprintf(stderr, "S_proc_user_identify: s == NULL\n"); if (s) { /* Found it! */ /* Remove it from the pending list. */ hurd_ihash_locp_remove (&pending_servers, s->locp); /* Tell it we eventually arrived. */ pthread_cond_signal (&s->wakeup); } ports_interrupt_self_on_port_death (userident, rendezvous); fprintf(stderr, "S_proc_user_identify: BEFORE pthread_hurd_cond_wait_np&&hurd_ihash_find\n"); fflush(stderr); #if 1 /* Wait for server answer. */ if (pthread_hurd_cond_wait_np (&u.wakeup, &pending_lock) && hurd_ihash_find (&pending_users, rendezvous)) #else if (hurd_ihash_find (&pending_users, rendezvous)) #endif /* We were interrupted; remove our record. */ { hurd_ihash_locp_remove (&pending_users, u.locp); /* Was it a normal interruption or did RENDEZVOUS die? */ mach_port_type_t type; mach_port_type (mach_task_self (), rendezvous, &type); err = type & MACH_PORT_TYPE_DEAD_NAME ? EINVAL : EINTR; fprintf(stderr, "S_proc_user_identify: AFTER pthread_hurd_cond_wait_np&&hurd_ihash_find err=%s\n", strerror(err)); fflush(stderr); } pthread_mutex_unlock (&pending_lock); if (! err) { /* Extract the port. */ *newport = u.passthrough; *newporttype = MACH_MSG_TYPE_MOVE_SEND; mach_port_deallocate (mach_task_self (), rendezvous); } return err; } /* Implement proc_server_identify as described in . */ kern_return_t S_proc_server_identify (struct proc *serverident, mach_port_t rendezvous, mach_port_t newport, mach_msg_type_name_t newport_type, pid_t *pid) { struct pending_user *u; struct proc *user; error_t err = 0; if (! serverident) return EOPNOTSUPP; if (! MACH_PORT_VALID (rendezvous)) return EINVAL; fprintf(stderr, "S_proc_server_identify: ENTER rendezvous = %d\n", (int)rendezvous); fprintf(stderr, "S_proc_server_identify: newport = %d, *pid=%d\n", (int)newport, (int)*pid); fprintf(stderr, "S_proc_server_identify: serverident->p_pid = %d\n", serverident->p_pid); fflush(stderr); pthread_mutex_lock (&pending_lock); fprintf(stderr, "S_proc_server_identify: BEFORE hurd_ihash_find\n"); fflush(stderr); /* Look for this rendezvous in the user list. */ u = hurd_ihash_find (&pending_users, rendezvous); if (u) fprintf(stderr, "S_proc_server_identify: u != NULL\n"); else fprintf(stderr, "S_proc_server_identify: u == NULL\n"); fflush(stderr); if (! u) { /* User not here yet, have to wait for it. */ struct pending_server s; pthread_cond_init (&s.wakeup, NULL); err = hurd_ihash_add (&pending_servers, rendezvous, &s); if (! err) { ports_interrupt_self_on_port_death (serverident, rendezvous); fprintf(stderr, "S_proc_server_identify: BEFORE pthread_hurd_cond_wait_np&&hurd_ihash_find\n"); fflush(stderr); #if 1 if (pthread_hurd_cond_wait_np (&s.wakeup, &pending_lock) && hurd_ihash_find (&pending_servers, rendezvous)) #else if (hurd_ihash_find (&pending_servers, rendezvous)) #endif /* We were interrupted; remove our record. */ { hurd_ihash_locp_remove (&pending_servers, s.locp); /* Was it a normal interruption or did RENDEZVOUS die? */ mach_port_type_t type; mach_port_type (mach_task_self (), rendezvous, &type); err = type & MACH_PORT_TYPE_DEAD_NAME ? EINVAL : EINTR; } else { u = hurd_ihash_find (&pending_users, rendezvous); if (u) fprintf(stderr, "S_proc_server_identify: u != NULL \n"); else fprintf(stderr, "S_proc_server_identify: u == NULL\n"); fflush(stderr); if (! u) /* User still not here, odd! */ err = EINTR; } } } if (u) { /* Remove it from the pending list. */ hurd_ihash_locp_remove (&pending_users, u->locp); /* Found it! */ user = u->user; /* FIXME */ /* Tell third party. */ *pid = user->p_pid; fprintf(stderr, "S_proc_server_identify: *pid=%d\n", (int)*pid); fflush(stderr); /* Give the user the new port and wake the RPC up. */ u->passthrough = newport; pthread_cond_signal (&u->wakeup); } pthread_mutex_unlock (&pending_lock); if (err) { fprintf(stderr, "S_proc_server_identify: EXIT err=%s\n", strerror(err)); fflush(stderr); return err; } ports_port_deref (user); mach_port_deallocate (mach_task_self (), rendezvous); return MIG_NO_REPLY; }