void *double_killer(void *cookie) { unsigned long long start; struct cond_mutex *cm = cookie; start = rt_timer_tsc(); check("mutex_lock", mutex_lock(cm->mutex), 0); check_sleep("mutex_lock", start); check("thread_kill 1", thread_kill(cm->tid, SIGRTMIN), 0); thread_msleep(10); check("thread_kill 2", thread_kill(cm->tid, SIGRTMIN), 0); check("mutex_unlock", mutex_unlock(cm->mutex), 0); return NULL; }
/* user interface */ void* server_mgr(void* args) { char buf[128]; while (1) { printf(">>"); fgets(buf, 128, stdin); trim(buf); if (strncmp(buf, "add ", 4) == 0) mgr_add(buf+4); else if (strcmp(buf, "count current") == 0) { printf("There are %d user(s) now.\n", mgr_cntcur()); } else if (strcmp(buf, "count all") == 0) { printf("There are %d visitor(s) in history.\n", mgr_cntall()); } else if (strncmp(buf, "kill ", 5) == 0) thread_kill(buf+5); else if (strcmp(buf, "stat all") == 0) mgr_statall(); else if (strncmp(buf, "stat ", 5) == 0) mgr_stat(buf+5); else printf("Error Command\n"); } }
/* Close up shop. */ void network_pcap_close(void) { pcap_t *pc; if (pcap != NULL) { pclog("Closing WinPcap\n"); /* Tell the polling thread to shut down. */ pc = pcap; pcap = NULL; #if 1 /* Terminate the polling thread. */ if (poll_tid != NULL) { thread_kill(poll_tid); poll_tid = NULL; } #else /* Wait for the polling thread to shut down. */ while (poll_tid != NULL) ; #endif /* OK, now shut down WinPcap itself. */ f_pcap_close(pc); /* Unload the DLL if possible. */ if (pcap_handle != NULL) { dynld_close(pcap_handle); pcap_handle = NULL; } } poll_rx = NULL; poll_arg = NULL; }
void thread_free(THREAD *self) { assert(self); if (self->status == THREAD_STATUS_RUNNING) { thread_cancel(self); int count; while (self->status == THREAD_STATUS_RUNNING && count++ < 100) { usleep(1000); } if (self->status == THREAD_STATUS_RUNNING) { thread_kill(self); } } pthread_join(*(self->thread), NULL); if (self->thread) { free(self->thread); self->thread = NULL; } free(self); self = NULL; }
main() { long tid1, tid2; tid1 = thread_create(thread1, 0); tid2 = thread_create(thread2, 0); if (thread_kill(tid1) != 1) fprintf(stderr, "** Incorrect return value for successful kill\n"); if (thread_kill(tid1+456) != 0) fprintf(stderr, "** Incorrect return value for unsuccessful kill\n"); // thread_kill(tid2); if (thread_kill(thread_self()) == 1) fprintf(stderr, "** incorrect return value for attempt to kill main\n"); status(0,2); thread_kill(tid2); status(1,2); thread_yield(); status(2,2); }
main() { long tid1, tid2; tid1 = thread_create(thread1, 0); tid2 = thread_create(thread2, 0); status(0,5); thread_yield(); status(3,5); thread_kill(tid2); thread_yield(); status(5,5); }
void kernel_done() { uint8_t i; for (i = 0; i < THREAD_TID_INVALID; i++) { if (get_thread(i)) { thread_kill(i); } } kprintf("system shutdown is complete.\n"); while (1) { }; }
/* * core_shutdown * ----------------- * */ DWORD remote_request_core_shutdown(Remote *remote, Packet *packet) { Channel *channel = NULL; Packet *response = packet_create_response(packet); DWORD result = ERROR_SUCCESS; // Acknowledge the shutdown request packet_add_tlv_bool(response, TLV_TYPE_BOOL, TRUE); // Transmit the response packet_transmit_response(result, remote, response); #ifdef _WIN32 // see note about posix above - egypt dprintf("[SHUTDOWN] Shutting down the Meterpreter thread 1 (killing the main thread)..."); thread_kill( serverThread ); #endif return result; }
void sigANY(int sig){ ThreadSig *ts; vfuncp func; int tid = TID; int tix; int ti; signal(sig,sigANY); /* for non-BSD */ tix = 1+getthreadix(); nsig++; /* putfLog("####SIG(%d) tix[%d] *%d",sig,tix,nsig); VStrSIG(); */ if( lTHREADSIG() ) fprintf(stderr,"-- %X[%d] %d#gotsig %d\n",tid,tix,nsig,sig); if( sig < 0 || 32 <= sig ){ fprintf(stderr,"-- %X[%d] %d#gotsig %d BAD\n",tid,tix,nsig,sig); return; } ts = &sigs[tix][sig]; if( ts->ts_stat == 0 || ts->ts_func == sigIGNORE ){ for( ti = 0; ti < MAX_THREADS; ti++ ){ ts = &sigs[1+ti][sig]; if( ts->ts_stat && ts->ts_func != sigIGNORE ){ if( ti != tix ){ fprintf(stderr,"-- %X[%d] gotsig %d FORW >>> %X[%d] %s:%d\n", tid,tix,sig,ts->ts_tid,1+ti, ts->ts_F,ts->ts_L); if( isWindows() ){ /* thread_kill not implemented yet */ }else{ thread_kill(ts->ts_tid,sig); return; } } break; } ts = 0; } if( ts == 0 ){ ts = &sigs[0][sig]; } } if( ts->ts_stat == 0 ){ fprintf(stderr,"-- %X[%d] %d#gotsig %d UNDEF ????\n", tid,tix,nsig,sig); return; } func = ts->ts_func; if( func == SIG_DFL ){ fprintf(stderr,"-- %X[%d] %d#gotsig %d DEFAULT <= %s:%d\n", tid,tix,nsig,sig,TS_FL); }else if( func == SIG_IGN ){ fprintf(stderr,"-- %X[%d] %d#gotsig %d IGNORED <= %s:%d\n", tid,tix,nsig,sig,TS_FL); }else{ if( lTHREADSIG() ) fprintf(stderr,"-- %X[%d] %d#gotsig %d HANDLED <= %s:%d %X\n", tid,tix,nsig,sig,TS_FL,xp2i(func)); (*func)(sig); if( lTHREADSIG() ) fprintf(stderr,"-- %X[%d] %d#gotsig %d HANDLED <= %s:%d %X\n", tid,tix,nsig,sig,TS_FL,xp2i(func)); } if( sig == SIGSEGV ){ void msleep(int); msleep(250); } }
/* * Setup and run the server. This is called from Init via the loader. */ DWORD server_setup( SOCKET fd ) { Remote * remote = NULL; char cStationName[256] = {0}; char cDesktopName[256] = {0}; DWORD res = 0; dprintf("[SERVER] Initializing..."); #ifdef _UNIX int local_error = 0; #endif // if hAppInstance is still == NULL it means that we havent been // reflectivly loaded so we must patch in the hAppInstance value // for use with loading server extensions later. InitAppInstance(); srand( (unsigned int)time(NULL) ); __try { do { dprintf( "[SERVER] module loaded at 0x%08X", hAppInstance ); // Open a THREAD item for the servers main thread, we use this to manage migration later. serverThread = thread_open(); dprintf( "[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread->handle, serverThread->id, serverThread->sigterm ); if( !(remote = remote_allocate(fd)) ) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); break; } remote->url = global_meterpreter_url; if (strcmp(global_meterpreter_transport+12, "TRANSPORT_SSL") == 0) { remote->transport = METERPRETER_TRANSPORT_SSL; dprintf("[SERVER] Using SSL transport..."); } else if (strcmp(global_meterpreter_transport+12, "TRANSPORT_HTTPS") == 0) { remote->transport = METERPRETER_TRANSPORT_HTTPS; dprintf("[SERVER] Using HTTPS transport..."); } else if (strcmp(global_meterpreter_transport+12, "TRANSPORT_HTTP") == 0) { remote->transport = METERPRETER_TRANSPORT_HTTP; dprintf("[SERVER] Using HTTP transport..."); } // Do not allow the file descriptor to be inherited by child processes SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0); dprintf("[SERVER] Initializing tokens..."); // Store our thread handle remote->hServerThread = serverThread->handle; #ifdef _WIN32 // Store our process token if (!OpenThreadToken(remote->hServerThread, TOKEN_ALL_ACCESS, TRUE, &remote->hServerToken)) OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &remote->hServerToken); // Copy it to the thread token remote->hThreadToken = remote->hServerToken; // Save the initial session/station/desktop names... remote->dwOrigSessionId = server_sessionid(); remote->dwCurrentSessionId = remote->dwOrigSessionId; GetUserObjectInformation( GetProcessWindowStation(), UOI_NAME, &cStationName, 256, NULL ); remote->cpOrigStationName = _strdup( cStationName ); remote->cpCurrentStationName = _strdup( cStationName ); GetUserObjectInformation( GetThreadDesktop( GetCurrentThreadId() ), UOI_NAME, &cDesktopName, 256, NULL ); remote->cpOrigDesktopName = _strdup( cDesktopName ); remote->cpCurrentDesktopName = _strdup( cDesktopName ); #endif // Process our default SSL-over-TCP transport if (remote->transport == METERPRETER_TRANSPORT_SSL) { dprintf("[SERVER] Flushing the socket handle..."); server_socket_flush( remote ); dprintf("[SERVER] Initializing SSL..."); if( !server_initialize_ssl( remote ) ) break; dprintf("[SERVER] Negotiating SSL..."); if( !server_negotiate_ssl( remote ) ) break; dprintf("[SERVER] Registering dispatch routines..."); register_dispatch_routines(); dprintf("[SERVER] Entering the main server dispatch loop for transport %d...", remote->transport); server_dispatch( remote ); dprintf("[SERVER] Deregistering dispatch routines..."); deregister_dispatch_routines( remote ); } if (remote->transport == METERPRETER_TRANSPORT_HTTP || remote->transport == METERPRETER_TRANSPORT_HTTPS) { dprintf("[SERVER] Registering dispatch routines..."); register_dispatch_routines(); dprintf("[SERVER] Entering the main server dispatch loop for transport %d...", remote->transport); #ifdef _WIN32 server_dispatch_http_wininet( remote ); #else // XXX: Handle non-windows HTTP transport #endif dprintf("[SERVER] Deregistering dispatch routines..."); deregister_dispatch_routines( remote ); } } while (0); if (remote->transport == METERPRETER_TRANSPORT_SSL) { dprintf("[SERVER] Closing down SSL..."); server_destroy_ssl( remote ); } if( remote ) remote_deallocate( remote ); } __except( exceptionfilter(GetExceptionCode(), GetExceptionInformation()) ) { dprintf("[SERVER] *** exception triggered!"); thread_kill( serverThread ); } dprintf("[SERVER] Finished."); return res; }
/*! * @brief Setup and run the server. This is called from Init via the loader. * @param fd The original socket descriptor passed in from the stager, or a pointer to stageless extensions. * @return Meterpreter exit code (ignored by the caller). */ DWORD server_setup(MetsrvConfig* config) { THREAD* serverThread = NULL; Remote* remote = NULL; char stationName[256] = { 0 }; char desktopName[256] = { 0 }; DWORD res = 0; dprintf("[SERVER] Initializing from configuration: 0x%p", config); dprintf("[SESSION] Comms Fd: %u", config->session.comms_fd); dprintf("[SESSION] Expiry: %u", config->session.expiry); dprintf("[SERVER] UUID: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", config->session.uuid[0], config->session.uuid[1], config->session.uuid[2], config->session.uuid[3], config->session.uuid[4], config->session.uuid[5], config->session.uuid[6], config->session.uuid[7], config->session.uuid[8], config->session.uuid[9], config->session.uuid[10], config->session.uuid[11], config->session.uuid[12], config->session.uuid[13], config->session.uuid[14], config->session.uuid[15]); // if hAppInstance is still == NULL it means that we havent been // reflectivly loaded so we must patch in the hAppInstance value // for use with loading server extensions later. InitAppInstance(); srand((unsigned int)time(NULL)); __try { do { dprintf("[SERVER] module loaded at 0x%08X", hAppInstance); // Open a THREAD item for the servers main thread, we use this to manage migration later. serverThread = thread_open(); dprintf("[SERVER] main server thread: handle=0x%08X id=0x%08X sigterm=0x%08X", serverThread->handle, serverThread->id, serverThread->sigterm); if (!(remote = remote_allocate())) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); break; } setup_ssl_lib(&remote->ssl); remote->orig_config = config; remote->sess_expiry_time = config->session.expiry; remote->sess_start_time = current_unix_timestamp(); remote->sess_expiry_end = remote->sess_start_time + config->session.expiry; dprintf("[DISPATCH] Session going for %u seconds from %u to %u", remote->sess_expiry_time, remote->sess_start_time, remote->sess_expiry_end); DWORD transportSize = 0; if (!create_transports(remote, config->transports, &transportSize)) { // not good, bail out! SetLastError(ERROR_BAD_ARGUMENTS); break; } // the first transport should match the transport that we initially connected on. // If it's TCP comms, we need to wire that up. if (remote->transport->type == METERPRETER_TRANSPORT_SSL && config->session.comms_fd) { ((TcpTransportContext*)remote->transport->ctx)->fd = (SOCKET)config->session.comms_fd; } // Set up the transport creation function pointer remote->trans_create = create_transport; // Set up the transport removal function pointer remote->trans_remove = remove_transport; // and the config creation pointer remote->config_create = config_create; // Store our thread handle remote->server_thread = serverThread->handle; dprintf("[SERVER] Registering dispatch routines..."); register_dispatch_routines(); // this has to be done after dispatch routine are registered load_stageless_extensions(remote, (MetsrvExtension*)((LPBYTE)config->transports + transportSize)); // Store our process token if (!OpenThreadToken(remote->server_thread, TOKEN_ALL_ACCESS, TRUE, &remote->server_token)) { OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &remote->server_token); } if (scheduler_initialize(remote) != ERROR_SUCCESS) { SetLastError(ERROR_BAD_ENVIRONMENT); break; } // Copy it to the thread token remote->thread_token = remote->server_token; // Save the initial session/station/desktop names... remote->orig_sess_id = server_sessionid(); remote->curr_sess_id = remote->orig_sess_id; GetUserObjectInformation(GetProcessWindowStation(), UOI_NAME, &stationName, 256, NULL); remote->orig_station_name = _strdup(stationName); remote->curr_station_name = _strdup(stationName); GetUserObjectInformation(GetThreadDesktop(GetCurrentThreadId()), UOI_NAME, &desktopName, 256, NULL); remote->orig_desktop_name = _strdup(desktopName); remote->curr_desktop_name = _strdup(desktopName); remote->sess_start_time = current_unix_timestamp(); // loop through the transports, reconnecting each time. while (remote->transport) { if (remote->transport->transport_init) { dprintf("[SERVER] attempting to initialise transport 0x%p", remote->transport); // Each transport has its own set of retry settings and each should honour // them individually. if (!remote->transport->transport_init(remote->transport)) { dprintf("[SERVER] transport initialisation failed, moving to the next transport"); remote->transport = remote->transport->next_transport; // when we have a list of transports, we'll iterate to the next one. continue; } } dprintf("[SERVER] Entering the main server dispatch loop for transport %x, context %x", remote->transport, remote->transport->ctx); DWORD dispatchResult = remote->transport->server_dispatch(remote, serverThread); dprintf("[DISPATCH] dispatch exited with result: %u", dispatchResult); if (remote->transport->transport_deinit) { dprintf("[DISPATCH] deinitialising transport"); remote->transport->transport_deinit(remote->transport); } dprintf("[TRANS] resetting transport"); if (remote->transport->transport_reset) { remote->transport->transport_reset(remote->transport, dispatchResult == ERROR_SUCCESS && remote->next_transport == NULL); } // If the transport mechanism failed, then we should loop until we're able to connect back again. if (dispatchResult == ERROR_SUCCESS) { dprintf("[DISPATCH] Server requested shutdown of dispatch"); // But if it was successful, and this is a valid exit, then we should clean up and leave. if (remote->next_transport == NULL) { dprintf("[DISPATCH] No next transport specified, leaving"); // we weren't asked to switch transports, so we exit. break; } // we need to change transports to the one we've been given. We will assume, for now, // that the transport has been created using the appropriate functions and that it is // part of the transport list. dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->next_transport); remote->transport = remote->next_transport; remote->next_transport = NULL; } else { // move to the next one in the list dprintf("[TRANS] Moving transport from 0x%p to 0x%p", remote->transport, remote->transport->next_transport); remote->transport = remote->transport->next_transport; } // transport switching and failover both need to support the waiting functionality. if (remote->next_transport_wait > 0) { dprintf("[TRANS] Sleeping for %u seconds ...", remote->next_transport_wait); sleep(remote->next_transport_wait); // the wait is a once-off thing, needs to be reset each time remote->next_transport_wait = 0; } } // clean up the transports while (remote->transport) { remove_transport(remote, remote->transport); } dprintf("[SERVER] Deregistering dispatch routines..."); deregister_dispatch_routines(remote); } while (0); dprintf("[DISPATCH] calling scheduler_destroy..."); scheduler_destroy(); dprintf("[DISPATCH] calling command_join_threads..."); command_join_threads(); remote_deallocate(remote); } __except (exceptionfilter(GetExceptionCode(), GetExceptionInformation())) { dprintf("[SERVER] *** exception triggered!"); thread_kill(serverThread); } dprintf("[SERVER] Finished."); return res; }
void kcall(struct thread *image) { if (image->flags & TF_USER) { // perform syscall // save user state image->usr_eip = image->eip; image->usr_esp = image->useresp; // switch to system mode image->ss = 0x21; image->ds = 0x21; image->cs = 0x19; image->flags &= ~TF_USER; // restore system state image->eip = image->sys_eip; image->useresp = image->sys_esp; return; } switch (image->eax) { case KCALL_SPAWN: { int id = thread_new(); if (id == -1) { // failure to create new thread image->eax = -1; break; } struct thread *thread = thread_get(id); struct t_info *state = (void*) image->ebx; // initialize thread state thread->useresp = state->regs.esp; thread->esp = (uintptr_t) &thread->num; thread->ss = 0x21; thread->ds = 0x21; thread->cs = 0x19; thread->eflags = image->eflags; thread->eip = state->regs.eip; thread->ebp = state->regs.ebp; thread->esi = state->regs.esi; thread->edi = state->regs.edi; thread->edx = state->regs.edx; thread->ecx = state->regs.ecx; thread->ebx = state->regs.ebx; thread->eax = state->regs.eax; // add to scheduler queue thread->state = TS_QUEUED; schedule_push(thread); image->eax = id; break; } case KCALL_REAP: { struct thread *target = thread_get(image->ebx); if (target->state != TS_PAUSED) { image->eax = TE_STATE; } else { if (image->ecx) { save_info((void*) image->ecx, target); } image->eax = 0; thread_kill(target); } break; } case KCALL_GETTID: { image->eax = image->id; break; } case KCALL_YIELD: { thread_save(image); schedule_push(image); image->state = TS_QUEUED; break; } case KCALL_PAUSE: { struct thread *target = thread_get(image->ebx); if (image->ebx == (uint32_t) -1) target = image; if (!target) { image->eax = TE_EXIST; } else switch (target->state) { case TS_RUNNING: // pause (normal, from running) thread_save(target); target->state = TS_PAUSED; image->eax = 0; break; case TS_QUEUED: // pause (normal, from queued) schedule_remv(target); target->state = TS_PAUSED; image->eax = 0; break; case TS_WAITING: // pause (waiting) event_remv(target->id, target->event); target->state = TS_PAUSEDW; image->eax = 0; break; default: // invalid state transition image->eax = TE_STATE; break; } break; } case KCALL_RESUME: { struct thread *target = thread_get(image->ebx); if (!target) { image->eax = TE_EXIST; } else switch (target->state) { case TS_PAUSED: // resume thread by scheduling schedule_push(target); target->state = TS_QUEUED; image->eax = 0; break; case TS_PAUSEDW: // resume thread by entering wait queue event_wait(target->id, target->event); target->state = TS_WAITING; image->eax = 0; break; default: image->eax = TE_STATE; break; } break; } case KCALL_GETSTATE: { struct thread *target = thread_get(image->ebx); if (image->ebx == (uint32_t) -1) target = image; if (!target) { image->eax = TE_EXIST; } else if (target->state != TS_PAUSED && target->state != TS_PAUSEDW && target != image) { image->eax = TE_STATE; } else { save_info((void*) image->ecx, target); image->eax = 0; } break; } case KCALL_SETSTATE: { struct thread *target = thread_get(image->ebx); if (image->ebx == (uint32_t) -1) target = image; if (!target) { image->eax = TE_EXIST; } else switch (target->state) { case TS_PAUSED: case TS_PAUSEDW: case TS_RUNNING: { struct t_info *src = (void*) image->ecx; if (src->flags & TF_DEAD) { // kill thread if (target->state == TS_RUNNING) { thread_save(target); target->state = TS_PAUSED; } // notify reaper dead_push(target); } if (target->pctx != src->pctx) { // change paging contexts pctx_load(src->pctx); } // save thread state target->pctx = src->pctx; target->flags = src->flags; target->fault = src->fault; if (target->state != TS_RUNNING) { // save register state target->edi = src->regs.edi; target->esi = src->regs.esi; target->ebp = src->regs.ebp; target->useresp = src->regs.esp; target->ebx = src->regs.ebx; target->edx = src->regs.edx; target->ecx = src->regs.ecx; target->eax = src->regs.eax; target->eip = src->regs.eip; target->eflags = src->regs.eflags; // save MMX/SSE state if (!target->fxdata) target->fxdata = heap_alloc(512); memcpy(target->fxdata, &src->regs.fxdata[0], 512); } target->usr_eip = src->usr_ip; target->usr_esp = src->usr_sp; image->eax = 0; break; } default: image->eax = TE_STATE; break; } break; } case KCALL_GETDEAD: { if (dead_peek()) { struct thread *dead = dead_pull(); image->eax = dead->id; } else { thread_save(image); image->state = TS_PAUSED; dead_wait(image); } break; } case KCALL_GETFAULT: { if (fault_peek()) { struct thread *fault = fault_pull(); image->eax = fault->id; } else { thread_save(image); image->state = TS_PAUSED; fault_wait(image); } break; } case KCALL_WAIT: { image->eax = event_wait(image->id, image->ebx); break; } case KCALL_RESET: { if (image->ebx < 240) { extern int irqstate[EV_COUNT]; irqstate[image->ebx] = 0; irq_unmask(image->ebx); } image->eax = 0; break; } case KCALL_SYSRET: { // save system state image->sys_eip = image->eip; image->sys_esp = image->useresp; // perform return value swap-in image->eax = image->ebp; // switch to usermode image->ss = 0x33; image->ds = 0x33; image->cs = 0x2B; image->flags |= TF_USER; // restore user state image->eip = image->usr_eip; image->useresp = image->usr_esp; break; } case KCALL_NEWPCTX: { image->eax = pctx_new(); break; } case KCALL_FREEPCTX: { image->eax = pctx_free(image->ebx); break; } case KCALL_SETFRAME: { page_set(image->ebx, page_fmt(image->ecx, page_get(image->ebx))); image->eax = 0; break; } case KCALL_SETFLAGS: { page_set(image->ebx, page_fmt(page_ufmt(page_get(image->ebx)), image->ecx)); image->eax = 0; break; } case KCALL_GETFRAME: { uint32_t off = image->ebx & 0xFFF; uint32_t page = image->ebx & ~0xFFF; image->eax = page_ufmt(page_get(page)) | off; break; } case KCALL_GETFLAGS: { image->eax = page_get(image->ebx) & PF_MASK; break; } case KCALL_NEWFRAME: { uint64_t frame = frame_new(); image->eax = frame & 0xFFFFFFFF; image->ebx = frame >> 32ULL; break; } case KCALL_FREEFRAME: { frame_free(image->ebx); image->eax = 0; break; } case KCALL_TAKEFRAME: { image->eax = 1; break; } default: { debug_printf("warning: unimplemented kcall %d\n", image->eax); image->eax = -1; break; } } }
void sig_norestart_condwait(void) { unsigned long long start; mutex_t mutex; cond_t cond; struct cond_mutex cm = { .mutex = &mutex, .cond = &cond, .tid = thread_self(), }; thread_t cond_killer_tid; struct sigaction sa = { .sa_handler = sighandler, .sa_flags = 0, }; sigemptyset(&sa.sa_mask); fprintf(stderr, "%s\n", __FUNCTION__); check_unix("sigaction", sigaction(SIGRTMIN, &sa, NULL), 0); check("mutex_init", mutex_init(&mutex, PTHREAD_MUTEX_DEFAULT, 0), 0); check("cond_init", cond_init(&cond, 0), 0); check("mutex_lock", mutex_lock(&mutex), 0); check("thread_spawn", thread_spawn(&cond_killer_tid, 2, cond_killer, &cm), 0); thread_msleep(11); start = rt_timer_tsc(); sig_seen = 0; #ifdef XENO_POSIX check("cond_wait", cond_wait(&cond, &mutex, XN_INFINITE), 0); #else /* native */ { int err = cond_wait(&cond, &mutex, XN_INFINITE); if (err == 0) err = -EINTR; check("cond_wait", err, -EINTR); } #endif /* native */ check_sleep("cond_wait", start); check("sig_seen", sig_seen, 1); check("mutex_unlock", mutex_unlock(&mutex), 0); check("thread_join", thread_join(cond_killer_tid), 0); check("mutex_destroy", mutex_destroy(&mutex), 0); check("cond_destroy", cond_destroy(&cond), 0); } void sig_restart_condwait(void) { unsigned long long start; mutex_t mutex; cond_t cond; struct cond_mutex cm = { .mutex = &mutex, .cond = &cond, .tid = thread_self(), }; thread_t cond_killer_tid; struct sigaction sa = { .sa_handler = sighandler, .sa_flags = 0, }; sigemptyset(&sa.sa_mask); fprintf(stderr, "%s\n", __FUNCTION__); check_unix("sigaction", sigaction(SIGRTMIN, &sa, NULL), 0); check("mutex_init", mutex_init(&mutex, PTHREAD_MUTEX_DEFAULT, 0), 0); check("cond_init", cond_init(&cond, 0), 0); check("mutex_lock", mutex_lock(&mutex), 0); check("thread_spawn", thread_spawn(&cond_killer_tid, 2, cond_killer, &cm), 0); thread_msleep(11); start = rt_timer_tsc(); sig_seen = 0; #ifdef XENO_POSIX check("cond_wait", cond_wait(&cond, &mutex, XN_INFINITE), 0); #else /* native */ { int err = cond_wait(&cond, &mutex, XN_INFINITE); if (err == 0) err = -EINTR; check("cond_wait", err, -EINTR); } #endif /* native */ check_sleep("cond_wait", start); check("sig_seen", sig_seen, 1); check("mutex_unlock", mutex_unlock(&mutex), 0); check("thread_join", thread_join(cond_killer_tid), 0); check("mutex_destroy", mutex_destroy(&mutex), 0); check("cond_destroy", cond_destroy(&cond), 0); } void *mutex_killer(void *cookie) { unsigned long long start; struct cond_mutex *cm = cookie; start = rt_timer_tsc(); check("mutex_lock", mutex_lock(cm->mutex), 0); check_sleep("mutex_lock", start); check("cond_signal", cond_signal(cm->cond), 0); thread_msleep(10); check("thread_kill", thread_kill(cm->tid, SIGRTMIN), 0); check("mutex_unlock", mutex_unlock(cm->mutex), 0); return NULL; }
void thread1(void* info) { status(1,5); thread_kill(thread_self()); fprintf(stderr, "** error: killed thread is executing\n"); }
/* * I/O timeout in seconds */ int IO_TIMEOUT = (10*60); #include "proc.h" typedef struct { int t_x; int t_pid; double t_Time; int t_id; int t_fd; int t_timer; int t_sig; void (*t_pipe)(int sig); int t_sser; int t_cln; sigjmp_buf t_ioenv; } ThreadIO; static int sser[MAX_THREADS]; /* setjmp serial */ static int nsig[MAX_THREADS]; static int threadPID[MAX_THREADS]; static ThreadIO *threadIO[MAX_THREADS]; void clearThreadFilter(); void clearThreadEnv(){ int ti; for( ti = 0; ti < MAX_THREADS; ti++ ){ if( threadIO[ti] ){ sv1log("-- clearThreadEnv[%d] %X %d %d %d\n", ti,p2i(threadIO[ti]),sser[ti],nsig[ti],threadPID[ti]); } threadIO[ti] = 0; sser[ti] = 0; nsig[ti] = 0; threadPID[ti] = 0; } clearThreadFilter(); } void clearThreadSig(){ int ti; for( ti = 0; ti < MAX_THREADS; ti++ ){ if( nsig[ti] ){ sv1log("-- clearThreadSig[%d] %d %d\n",ti, nsig[ti],sser[ti]); } nsig[ti] = 0; } } int getmtpid(); static int okenv(ThreadIO *tio){ int off = (char*)tio - (char*)&tio; if( tio->t_x < 0 || elnumof(threadIO) <= tio->t_x ){ porting_dbg("--stale ThreadIO %X %X x=%X",p2i(tio),off,tio->t_x); return 0; } if( tio->t_sser != sser[tio->t_x] ){ porting_dbg("--stale ThreadIO %X %X ser=%X/%X",p2i(tio),off, tio->t_sser,sser[tio->t_x]); return 0; } if( tio->t_pid != getmtpid() ){ porting_dbg("--stale ThreadIO %X %X pid=%d/%d tid=%X",p2i(tio),off, tio->t_pid,getmtpid(),tio->t_id ); return 0; } return 1; } int gotSIGPIPE(){ return nsig[getthreadix()]; } int iamServer(); int MAX_SIGPIPE = 100; /* max. SIGPIPE caught in an output action */ static void io_timeout(int sig){ ThreadIO *myenv; ThreadIO *ev1; int mx,my_tid,tid,tid1; int tn,tx,ti; int my_pid; Vsignal(SIGPIPE,io_timeout); /*should be before thread_kill()*/ if( sig == SIGPIPE ){ /* should not do longjump() to set ferror()... * and maybe the longjump() on SIGPIPE is not necessaly. * 9.8.2 set explicitly by Setferror() as an workaround */ if( lNOSIGPIPE() ){ return; } } mx = getthreadix(); my_tid = getthreadid(); myenv = threadIO[mx]; sv1log("IO_TIMEOUT[%d] SIGPIPE got by[%X] longjump %X[%X] %d/%d\n", mx,my_tid,p2i(myenv),myenv?myenv->t_id:0, actthreads(),numthreads()); if( numthreads() ){ if( isatty(fileno(stderr)) ) fprintf(stderr,"-- %X gotSIGPIPE(%d) [%d]%X[%X] %d/%d\n", TID,sig,mx,p2i(myenv),myenv?myenv->t_id:0, actthreads(),numthreads()); } if( myenv && myenv->t_id == my_tid && okenv(myenv) ){ nsig[mx] += 1; if( myenv->t_sig != 0 ){ sv1log("IO_TIMEOUT[%d] SIG*%d (%d %d) in longjump\n", mx,nsig[mx],myenv->t_sig,sig); if( MAX_SIGPIPE < nsig[mx] ) if( !lSINGLEP() && !iamServer() ){ sv1log("####Finish: Too Many SIGPIPE: %d\n", nsig[mx]); Finish(-1); } return; } myenv->t_sig = sig; siglongjmpX(myenv->t_ioenv,sig); return; } tid = 0; my_pid = getmtpid(); for( tn = 0; tn < elnumof(threadIO); tn++ ){ tx = (mx + 1 + tn) % elnumof(threadIO); if( threadPID[tx] != my_pid ){ threadIO[tx] = 0; continue; } if( (ev1 = threadIO[tx]) == 0 /*|| !validenv(tx,ev1) */ ){ continue; } if( !okenv(ev1) ){ threadIO[tx] = 0; continue; } if( (tid1 = ev1->t_id) == 0 ) continue; sv1log("IO_TIMEOUT[%d] candidate %X [%d]\n", tx,tid1,ev1->t_fd); if( tid == 0 ){ tid = tid1; } porting_dbg("candidate handler IO_TIMEOUT[%d] %X [%d]", tx,tid,ev1->t_fd); nsig[tx] += 1; break; } if( tid == my_tid ){ sv1log("IO_TIMEOUT: dangling? SIG%d -> %X\n",sig,my_tid); porting_dbg("IO_TIMEOUT: dangling? SIG%d -> %X ++++", sig,my_tid); }else if( tid ){ porting_dbg("IO_TIMEOUT: forwarded SIG%d %X -> %X", sig,my_tid,tid); sv1log("IO_TIMEOUT: forwarded SIG%d %X -> %X\n", sig,my_tid,tid); thread_kill(tid,sig); }else{ sv1log("IO_TIMEOUT: dangling SIG%d -> %X\n",sig,my_tid); porting_dbg("IO_TIMEOUT: dangling SIG%d -> %X ----", sig,my_tid); } }