/* Sleep USECONDS microseconds, or until a previously set timer goes off. */ int usleep (useconds_t useconds) { mach_port_t recv; struct timeval before, after; recv = __mach_reply_port (); if (__gettimeofday (&before, NULL) < 0) return -1; (void) __mach_msg (NULL, MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_INTERRUPT, 0, 0, recv, (useconds + 999) / 1000, MACH_PORT_NULL); __mach_port_destroy (mach_task_self (), recv); if (__gettimeofday (&after, NULL) < 0) return -1; return 0; }
int __libc_nanosleep (const struct timespec *requested_time, struct timespec *remaining) { mach_port_t recv; struct timeval before, after; if (requested_time->tv_sec < 0 || requested_time->tv_nsec < 0 || requested_time->tv_nsec >= 1000000000) { errno = EINVAL; return -1; } const mach_msg_timeout_t ms = requested_time->tv_sec * 1000 + (requested_time->tv_nsec + 999999) / 1000000; recv = __mach_reply_port (); if (remaining && __gettimeofday (&before, NULL) < 0) return -1; error_t err = __mach_msg (NULL, MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_INTERRUPT, 0, 0, recv, ms, MACH_PORT_NULL); __mach_port_destroy (mach_task_self (), recv); if (err == EMACH_RCV_INTERRUPTED) { if (remaining && __gettimeofday (&after, NULL) >= 0) { struct timeval req_time, elapsed, rem; TIMESPEC_TO_TIMEVAL (&req_time, requested_time); timersub (&after, &before, &elapsed); timersub (&req_time, &elapsed, &rem); TIMEVAL_TO_TIMESPEC (&rem, remaining); } errno = EINTR; return -1; } return 0; }
error_t __hurd_file_name_lookup_retry (error_t (*use_init_port) (int which, error_t (*operate) (file_t)), file_t (*get_dtable_port) (int fd), error_t (*lookup) (file_t dir, char *name, int flags, mode_t mode, retry_type *do_retry, string_t retry_name, mach_port_t *result), enum retry_type doretry, char retryname[1024], int flags, mode_t mode, file_t *result) { error_t err; char *file_name; int nloops; error_t lookup_op (file_t startdir) { while (file_name[0] == '/') file_name++; return lookup_error ((*lookup) (startdir, file_name, flags, mode, &doretry, retryname, result)); } error_t reauthenticate (file_t unauth) { error_t err; mach_port_t ref = __mach_reply_port (); error_t reauth (auth_t auth) { return __auth_user_authenticate (auth, ref, MACH_MSG_TYPE_MAKE_SEND, result); } err = __io_reauthenticate (unauth, ref, MACH_MSG_TYPE_MAKE_SEND); if (! err) err = (*use_init_port) (INIT_PORT_AUTH, &reauth); __mach_port_destroy (__mach_task_self (), ref); __mach_port_deallocate (__mach_task_self (), unauth); return err; }
void _hurdsig_longjmp_from_handler (void *data, jmp_buf env, int val) { struct sigcontext *scp = data; struct hurd_sigstate *ss = _hurd_self_sigstate (); int onstack; inline void cleanup (void) { /* Destroy the MiG reply port used by the signal handler, and restore the reply port in use by the thread when interrupted. */ mach_port_t *reply_port = (mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY); if (*reply_port) { mach_port_t port = *reply_port; /* Assigning MACH_PORT_DEAD here tells libc's mig_get_reply_port not to get another reply port, but avoids mig_dealloc_reply_port trying to deallocate it after the receive fails (which it will, because the reply port will be bogus, regardless). */ *reply_port = MACH_PORT_DEAD; __mach_port_destroy (__mach_task_self (), port); } *reply_port = scp->sc_reply_port; }
mach_port_t _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread, struct machine_thread_all_state *state, int *state_change, void (*reply) (void)) { extern const void _hurd_intr_rpc_msg_in_trap; mach_port_t rcv_port = MACH_PORT_NULL; mach_port_t intr_port; *state_change = 0; intr_port = ss->intr_port; if (intr_port == MACH_PORT_NULL) /* No interruption needs done. */ return MACH_PORT_NULL; /* Abort the thread's kernel context, so any pending message send or receive completes immediately or aborts. */ abort_thread (ss, state, reply); if (state->basic.PC < (natural_t) &_hurd_intr_rpc_msg_in_trap) { /* The thread is about to do the RPC, but hasn't yet entered mach_msg. Mutate the thread's state so it knows not to try the RPC. */ INTR_MSG_BACK_OUT (&state->basic); MACHINE_THREAD_STATE_SET_PC (&state->basic, &_hurd_intr_rpc_msg_in_trap); state->basic.SYSRETURN = MACH_SEND_INTERRUPTED; *state_change = 1; } else if (state->basic.PC == (natural_t) &_hurd_intr_rpc_msg_in_trap && /* The thread was blocked in the system call. After thread_abort, the return value register indicates what state the RPC was in when interrupted. */ state->basic.SYSRETURN == MACH_RCV_INTERRUPTED) { /* The RPC request message was sent and the thread was waiting for the reply message; now the message receive has been aborted, so the mach_msg call will return MACH_RCV_INTERRUPTED. We must tell the server to interrupt the pending operation. The thread must wait for the reply message before running the signal handler (to guarantee that the operation has finished being interrupted), so our nonzero return tells the trampoline code to finish the message receive operation before running the handler. */ mach_port_t *reply = interrupted_reply_port_location (ss->thread, state, sigthread); error_t err = __interrupt_operation (intr_port, _hurdsig_interrupt_timeout); if (err) { if (reply) { /* The interrupt didn't work. Destroy the receive right the thread is blocked on. */ __mach_port_destroy (__mach_task_self (), *reply); *reply = MACH_PORT_NULL; } /* The system call return value register now contains MACH_RCV_INTERRUPTED; when mach_msg resumes, it will retry the call. Since we have just destroyed the receive right, the retry will fail with MACH_RCV_INVALID_NAME. Instead, just change the return value here to EINTR so mach_msg will not retry and the EINTR error code will propagate up. */ state->basic.SYSRETURN = EINTR; *state_change = 1; } else if (reply) rcv_port = *reply; /* All threads whose RPCs were interrupted by the interrupt_operation call above will retry their RPCs unless we clear SS->intr_port. So we clear it for the thread taking a signal when SA_RESTART is clear, so that its call returns EINTR. */ if (! signo || !(_hurd_sigstate_actions (ss) [signo].sa_flags & SA_RESTART)) ss->intr_port = MACH_PORT_NULL; } return rcv_port; }