/****************************************************************************** * NtTerminateThread (NTDLL.@) * ZwTerminateThread (NTDLL.@) */ NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code ) { NTSTATUS ret; BOOL self; SERVER_START_REQ( terminate_thread ) { req->handle = wine_server_obj_handle( handle ); req->exit_code = exit_code; ret = wine_server_call( req ); self = !ret && reply->self; } SERVER_END_REQ; #ifdef CONFIG_UNIFIED_KERNEL if (self) { server_kill_thread( exit_code ); abort_thread( exit_code ); } #else if (self) abort_thread( exit_code ); #endif return ret; }
/*********************************************************************** * send_request * * Send a request to the server. */ static unsigned int send_request( const struct __server_request_info *req ) { unsigned int i; int ret; if (!req->u.req.request_header.request_size) { if ((ret = write( ntdll_get_thread_data()->request_fd, &req->u.req, sizeof(req->u.req) )) == sizeof(req->u.req)) return STATUS_SUCCESS; } else { struct iovec vec[__SERVER_MAX_DATA+1]; vec[0].iov_base = (void *)&req->u.req; vec[0].iov_len = sizeof(req->u.req); for (i = 0; i < req->data_count; i++) { vec[i+1].iov_base = (void *)req->data[i].ptr; vec[i+1].iov_len = req->data[i].size; } if ((ret = writev( ntdll_get_thread_data()->request_fd, vec, i+1 )) == req->u.req.request_header.request_size + sizeof(req->u.req)) return STATUS_SUCCESS; } if (ret >= 0) server_protocol_error( "partial write %d\n", ret ); if (errno == EPIPE) abort_thread(0); if (errno == EFAULT) return STATUS_ACCESS_VIOLATION; server_protocol_perror( "write" ); }
/*********************************************************************** * server_protocol_error */ void server_protocol_error( const char *err, ... ) { va_list args; va_start( args, err ); fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() ); vfprintf( stderr, err, args ); va_end( args ); abort_thread(1); }
/*********************************************************************** * receive_fd * * Receive a file descriptor passed from the server. */ static int receive_fd( obj_handle_t *handle ) { struct iovec vec; struct msghdr msghdr; int ret, fd = -1; #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS msghdr.msg_accrights = (void *)&fd; msghdr.msg_accrightslen = sizeof(fd); #else /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ char cmsg_buffer[256]; msghdr.msg_control = cmsg_buffer; msghdr.msg_controllen = sizeof(cmsg_buffer); msghdr.msg_flags = 0; #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ msghdr.msg_name = NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = &vec; msghdr.msg_iovlen = 1; vec.iov_base = (void *)handle; vec.iov_len = sizeof(*handle); for (;;) { if ((ret = recvmsg( fd_socket, &msghdr, MSG_CMSG_CLOEXEC )) > 0) { #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR( &msghdr ); cmsg; cmsg = CMSG_NXTHDR( &msghdr, cmsg )) { if (cmsg->cmsg_level != SOL_SOCKET) continue; if (cmsg->cmsg_type == SCM_RIGHTS) fd = *(int *)CMSG_DATA(cmsg); #ifdef SCM_CREDENTIALS else if (cmsg->cmsg_type == SCM_CREDENTIALS) { struct ucred *ucred = (struct ucred *)CMSG_DATA(cmsg); server_pid = ucred->pid; } #endif } #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ if (fd != -1) fcntl( fd, F_SETFD, FD_CLOEXEC ); /* in case MSG_CMSG_CLOEXEC is not supported */ return fd; } if (!ret) break; if (errno == EINTR) continue; if (errno == EPIPE) break; server_protocol_perror("recvmsg"); } /* the server closed the connection; time to die... */ abort_thread(0); }
/****************************************************************************** * NtTerminateThread (NTDLL.@) * ZwTerminateThread (NTDLL.@) */ NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code ) { NTSTATUS ret; BOOL self; SERVER_START_REQ( terminate_thread ) { req->handle = wine_server_obj_handle( handle ); req->exit_code = exit_code; ret = wine_server_call( req ); self = !ret && reply->self; } SERVER_END_REQ; if (self) abort_thread( exit_code ); return ret; }
thread_buffer_t::~thread_buffer_t() { bool stopped=false; try { stopped=stop_thread(); }catch( ... ) { } if( !stopped ) { try { stopped=abort_thread(); }catch( ... ) { } } if( !stopped ) { std::terminate(); } }
/*********************************************************************** * wine_server_send_fd (NTDLL.@) * * Send a file descriptor to the server. * * PARAMS * fd [I] file descriptor to send * * RETURNS * nothing */ void CDECL wine_server_send_fd( int fd ) { struct send_fd data; struct msghdr msghdr; struct iovec vec; int ret; #ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS msghdr.msg_accrights = (void *)&fd; msghdr.msg_accrightslen = sizeof(fd); #else /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ char cmsg_buffer[256]; struct cmsghdr *cmsg; msghdr.msg_control = cmsg_buffer; msghdr.msg_controllen = sizeof(cmsg_buffer); msghdr.msg_flags = 0; cmsg = CMSG_FIRSTHDR( &msghdr ); cmsg->cmsg_len = CMSG_LEN( sizeof(fd) ); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsg) = fd; msghdr.msg_controllen = cmsg->cmsg_len; #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ msghdr.msg_name = NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = &vec; msghdr.msg_iovlen = 1; vec.iov_base = (void *)&data; vec.iov_len = sizeof(data); data.tid = GetCurrentThreadId(); data.fd = fd; for (;;) { if ((ret = sendmsg( fd_socket, &msghdr, 0 )) == sizeof(data)) return; if (ret >= 0) server_protocol_error( "partial write %d\n", ret ); if (errno == EINTR) continue; if (errno == EPIPE) abort_thread(0); server_protocol_perror( "sendmsg" ); } }
/*********************************************************************** * read_reply_data * * Read data from the reply buffer; helper for wait_reply. */ static void read_reply_data( void *buffer, size_t size ) { int ret; for (;;) { if ((ret = read( ntdll_get_thread_data()->reply_fd, buffer, size )) > 0) { if (!(size -= ret)) return; buffer = (char *)buffer + ret; continue; } if (!ret) break; if (errno == EINTR) continue; if (errno == EPIPE) break; server_protocol_perror("read"); } /* the server closed the connection; time to die... */ abort_thread(0); }
thread_buffer_t::~thread_buffer_t() { bool stopped=false; try { stopped=stop_thread(); }catch(...){ } if( !stopped ) { // one more time, with attitude try { stopped=abort_thread(); }catch(...){ } if( !stopped ) { DWORD code=GetLastError(); // otherwize, the thread will be left running loose stomping on freed memory. std::terminate(); } } }
/*********************************************************************** * server_protocol_perror */ void server_protocol_perror( const char *err ) { fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() ); perror( err ); abort_thread(1); }
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; }