void handle_work_done_event(awe_server_state * ns, tw_bf * b, awe_msg * m, tw_lp * lp) { char *work_id = m->object_id; gchar ** parts = g_strsplit(work_id, "_", 3); char* job_id = parts[0]; int task_id = atoi(parts[1]); Job* job = g_hash_table_lookup(job_map, job_id); job->task_remainwork[task_id] -= 1; fprintf(event_log, "%lf;awe_server;%lu;WD;workid=%s\n", now_sec(lp), lp->gid, work_id); ns->total_work += 1; /*handle task done*/ if (job->task_remainwork[task_id] == 0) { fprintf(event_log, "%lf;awe_server;%lu;TD;taskid=%s_%d\n", now_sec(lp), lp->gid, job_id, task_id); ns->total_task +=1; job->task_states[task_id]=2; for (int j=0; j<job->num_tasks; j++) { job->task_dep[j][task_id] = 0; } parse_ready_tasks(job, lp); job->remain_tasks -= 1; /*handle job done*/ if (job->remain_tasks==0) { fprintf(event_log, "%lf;awe_server;%lu;JD;jobid=%s\n", now_sec(lp), lp->gid, job_id); ns->total_job += 1; } } }
void parse_ready_tasks(Job* job, tw_lp * lp) { for (int i=0; i<job->num_tasks; i++) { bool is_ready = True; for (int j=0; j<job->num_tasks; j++) { if (job->task_dep[i][j] == 1) { is_ready = False; break; } } if (is_ready && job->task_states[i]==0) { fprintf(event_log, "%lf;awe_server;%lu;TQ;taskid=%s_%d splits=%d\n", now_sec(lp), lp->gid, job->id, i, job->task_splits[i]); job->task_states[i]=1; if (job->task_splits[i] == 1) { char work_id[MAX_LENGTH_ID]; sprintf(work_id, "%s_%d_0", job->id, i); plan_work_enqueue_event(work_id, lp); } else if (job->task_splits[i] > 1) { for (int j=1; j<=job->task_splits[i]; j++) { char work_id[MAX_LENGTH_ID]; sprintf(work_id, "%s_%d_%d", job->id, i, j); plan_work_enqueue_event(work_id, lp); } } } } }
/* handle initial event (initialize job submission) */ void handle_kick_off_event( awe_server_state * ns, tw_bf * b, awe_msg * m, tw_lp * lp) { printf("%lf;awe_server;%lu]Start serving\n", now_sec(lp), lp->gid); GHashTableIter iter; gpointer key, value; g_hash_table_iter_init(&iter, job_map); while (g_hash_table_iter_next(&iter, &key, &value)) { Job* job = (Job*)value; tw_event *e; awe_msg *msg; tw_stime submit_time; submit_time = s_to_ns(etime_to_stime(job->stats.created)) + ns_tw_lookahead; if (fraction < 1.0) { submit_time = submit_time * fraction; } e = codes_event_new(lp->gid, submit_time, lp); msg = tw_event_data(e); msg->event_type = JOB_SUBMIT; strcpy(msg->object_id, job->id); tw_event_send(e); } return; }
void handle_work_enqueue_event( awe_server_state * ns, tw_bf * b, awe_msg * m, tw_lp * lp) { fprintf(event_log, "%lf;awe_server;%lu;WQ;work=%s\n", now_sec(lp), lp->gid, m->object_id); char* workid=NULL; workid = malloc(sizeof(char[MAX_LENGTH_ID])); strcpy(workid, m->object_id); assert(workid); tw_lpid *clientid; int has_match = 0; int len = g_queue_get_length(client_req_queue); if (len > 0) { int n = -1; for (int i=0; i<len; i++) { clientid = g_queue_peek_nth(client_req_queue, i); if (client_match_work(*clientid, workid)) { n = i; break; } } if (n >=0) { clientid = g_queue_pop_nth(client_req_queue, n); has_match = 1; } } if (has_match) { tw_event *e; awe_msg *msg; e = codes_event_new(*clientid, ns_tw_lookahead, lp); msg = tw_event_data(e); msg->event_type = WORK_CHECKOUT; strcpy(msg->object_id, workid); tw_event_send(e); fprintf(event_log, "%lf;awe_server;%lu;WC;work=%s client=%lu\n", now_sec(lp), lp->gid, workid, *clientid); free(workid); free(clientid); } else { g_queue_push_tail(work_queue, workid); } return; }
void handle_work_checkout_event( awe_server_state * ns, tw_bf * b, awe_msg * m, tw_lp * lp) { tw_event *e; awe_msg *msg; e = codes_event_new(m->src, ns_tw_lookahead, lp); msg = tw_event_data(e); msg->event_type = WORK_CHECKOUT; memset(msg->object_id, 0, sizeof(msg->object_id)); tw_lpid client_id = m->src; // char group_name[MAX_LENGTH_GROUP]; //char lp_type_name[MAX_LENGTH_GROUP]; //int lp_type_id, grp_id, grp_rep_id, offset; // codes_mapping_get_lp_info(client_id, group_name, &grp_id, &lp_type_id, // lp_type_name, &grp_rep_id, &offset); int group_id = 0; group_id = get_group_id(client_id); /*if queue is empty, msg->object_id is "", otherwise msg->object-id is the dequeued workid*/ int got_work = 0; char workid[MAX_LENGTH_ID]; if (!g_queue_is_empty(work_queue)) { if (group_id == 1 && sched_policy>0) { //client from remote site char* work = NULL; if (sched_policy==1) { work = get_first_work_by_stage(5); //checkout task 5 (blat) only for remote site } else if (sched_policy==2) { work = get_first_work_by_greedy(WorkOrder); } if (work) { strcpy(workid, work); got_work = 1; } } else { strcpy(workid, g_queue_pop_head(work_queue)); got_work = 1; } } if (got_work) { //eligible work found, send back to the requesting client fprintf(event_log, "%lf;awe_server;%lu;WC;work=%s client=%lu\n", now_sec(lp), lp->gid, workid, m->src); assert (strlen(workid) > 10); strcpy(msg->object_id, workid); tw_event_send(e); } else { //no eligible work found, put client request to the waiting queue tw_lpid *clientid = NULL; clientid = malloc(sizeof(tw_lpid)); *clientid = m->src; g_queue_push_tail(client_req_queue, clientid); } return; }
/* handle initial event (initialize job submission) */ void handle_kick_off_event( shock_router_state * qs, tw_bf * b, awe_msg * m, tw_lp * lp) { printf("[%lf][shock_router][%lu]Start serving...\n", now_sec(lp), lp->gid); return; }
static void _callstack_signal_handler(int signr, siginfo_t *info, void *secret) { std::stringstream ss; double now = now_sec(); ss << "WATCHDOG: task '" << global_monitor->get_name() << "' has not responded for more than " << global_monitor->get_interval(now) << " seconds - timeout is " << global_monitor->get_timeout_sec() << " seconds"; std::string backtrace = Backtrace(); ss << "\n\n*** traceback follows ***\n\n" << backtrace << "\n"; throw std::runtime_error(ss.str()); }
/* check this every 1msec */ void CNatRxManager::handle_aging() { int i; dsec_t now=now_sec(); for (i=0; i<m_max_threads; i++) { CNatPerThreadInfo * thread_info=get_thread_info( i ); if ( thread_info->m_cur_nat_msg ) { if ( now - thread_info->m_last_time > MAX_TIME_MSG_IN_QUEUE_SEC ) { flush_node(thread_info); } } } }
static int login_finish(T_Connect *conn,T_NetHead *NetHead) { char *cp; T_SRV_Var *up=(T_SRV_Var *)conn->Var; GDA *gp=(GDA *)up->var; T_CLI_Var *clip; char tmp[30],tmp1[256]; unset_callback(up->TCB_no); // up->poolno=get_scpool_no(NetHead->D_NODE); /* 怎么认证还得想办法 cp=get_LABEL(up->poolno); if(!cp || strcmp(cp,logrec.label)) { sprintf(tmp1,"错误的DBLABEL %s",logrec.label); goto errret; } */ if(!gp->server) { sprintf(tmp1,"%s:connect to server fault,TCB:%d", __FUNCTION__,up->TCB_no); ShowLog(1,"%s:Error:%s",__FUNCTION__,tmp1); NetHead->ERRNO1=-1; NetHead->ERRNO2=-1; NetHead->PKG_REC_NUM=0; NetHead->data=tmp1; NetHead->PKG_LEN=strlen(NetHead->data); SendPack(conn,NetHead); return 0; // fail } clip=(T_CLI_Var *)gp->server->Var; if(clip) { // stptok(clip->UID,up->SQL_Connect.UID,sizeof(up->SQL_Connect.UID),0); // stptok(clip->DBOWN,up->SQL_Connect.DBOWN,sizeof(up->SQL_Connect.DBOWN),0); } ShowLog(5,"%s:TCB:%d,poolno=%d,Errno=%d",__FUNCTION__,up->TCB_no,up->poolno,clip->Errno); release_SC_connect(&gp->server,up->TCB_no,up->poolno); cp=tmp1; if(clip) cp+=sprintf(cp,"%s|%s|%s|%s|", gp->devid,gp->operid ,clip->UID,clip->DBOWN); else cp+=sprintf(cp,"%s|%s|||", gp->devid,gp->operid); cp+=sprintf(cp,"%s|%d|",rsecstrfmt(tmp,now_sec(),YEAR_TO_SEC),up->TCB_no); ShowLog(2,"%s:%s Login success",__FUNCTION__,tmp1); NetHead->data=tmp1; NetHead->PKG_LEN=strlen(NetHead->data); NetHead->ERRNO1=0; NetHead->ERRNO2=0; NetHead->PKG_REC_NUM=0; SendPack(conn,NetHead); return 1; }
void handle_job_submit_event( awe_server_state * ns, tw_bf * b, awe_msg * m, tw_lp * lp) { char* job_id = m->object_id; Job* job = g_hash_table_lookup(job_map, job_id); assert(job); fprintf(event_log, "%lf;awe_server;%lu;JQ;jobid=%s inputsize=%llu\n", now_sec(lp), lp->gid, job_id, job->inputsize); parse_ready_tasks(job, lp); return; }
/** * main loop * */ void TrexWatchDog::_main() { pthread_setname_np(pthread_self(), "Trex Watchdog"); assert(m_enable == true); /* start main loop */ while (m_active) { dsec_t now = now_sec(); /* to be on the safe side - read the count with a lock */ std::unique_lock<std::mutex> lock(m_lock); int count = m_mon_count; lock.unlock(); for (int i = 0; i < count; i++) { TrexMonitor *monitor = m_monitors[i]; /* skip non active monitors */ if (!monitor->is_active()) { continue; } /* if its own - turn it off and write down the time */ if (monitor->is_tickled()) { monitor->reset(now); continue; } /* if the monitor has expired - crash */ if (monitor->is_expired(now)) { global_monitor = monitor; pthread_kill(monitor->get_tid(), SIGALRM); /* nothing to do more... the other thread will terminate, but if not - we terminate */ sleep(5); fprintf(stderr, "\n\n*** WATCHDOG violation detected on task '%s' which have failed to response to the signal ***\n\n", monitor->get_name().c_str()); abort(); } } /* the internal clock - 250 ms */ delay(250); } }
void CNatRxManager::handle_packet_ipv4(CNatOption * option, IPHeader * ipv4) { CNatPerThreadInfo * thread_info=get_thread_info(option->get_thread_id()); if (!thread_info) { return; } /* Extract info from the packet ! */ uint32_t ext_ip = ipv4->getSourceIp(); uint32_t ext_ip_server = ipv4->getDestIp(); uint8_t proto = ipv4->getProtocol(); /* must be TCP/UDP this is the only supported proto */ if (!( (proto==6) || (proto==17) )) { m_stats.m_err_no_valid_proto++; return; } /* we support only TCP/UDP so take the source port , post IP header */ UDPHeader * udp= (UDPHeader *) (((char *)ipv4)+ ipv4->getHeaderLength()); uint16_t ext_port = udp->getSourcePort(); #ifdef NAT_TRACE_ printf("rx msg ext ip : %08x:%08x ext port : %04x flow_id : %d \n",ext_ip,ext_ip_server,ext_port,option->get_fid()); #endif CGenNodeNatInfo * node=thread_info->m_cur_nat_msg; if ( !node ) { node = (CGenNodeNatInfo * )CGlobalInfo::create_node(); assert(node); node->init(); thread_info->m_cur_nat_msg = node; thread_info->m_last_time = now_sec(); } /* get message */ CNatFlowInfo * msg=node->get_next_msg(); /* fill the message */ msg->m_external_ip = ext_ip; msg->m_external_ip_server = ext_ip_server; msg->m_external_port = ext_port; msg->m_fid = option->get_fid(); msg->m_pad = 0xee; if ( node->is_full() ) { flush_node(thread_info); } }
inline time_t now_boottime_sec(void) { return now_sec(CLOCK_BOOTTIME); }
inline time_t now_monotonic_sec(void) { return now_sec(CLOCK_MONOTONIC); }
inline time_t now_realtime_sec(void) { return now_sec(CLOCK_REALTIME); }
void RxCheckManager::handle_packet(CRx_check_header * rxh){ //rxh->dump(stdout); m_stats.m_total_rx++; if ( rxh->m_magic != RX_CHECK_MAGIC ){ m_stats.m_err_no_magic++; update_template_err(rxh->m_template_id); return; } if ((rxh->m_pkt_id+1) > rxh->m_flow_size ){ m_stats.m_err_wrong_pkt_id++; update_template_err(rxh->m_template_id); return; } m_cur_time=now_sec(); uint64_t d = (os_get_hr_tick_32() - rxh->m_time_stamp ); double dt= ptime_convert_hr_dsec(d); m_hist.Add(dt); // calc jitter per template CPerTemplateInfo *lpt= get_template(rxh->m_template_id); lpt->calc(dt); lpt->inc_rx_counter(); CRxCheckFlow * lf; /* lookup */ lf=m_ft.lookup(rxh->m_flow_id); m_stats.m_lookup++; bool any_err=false; if ( rxh->is_fif_dir() ) { if (lf==0) { /* valid , this is FIF we don't expect flows */ lf=m_ft.add(rxh->m_flow_id); assert(lf); lf->m_aging_timer_handle.m_object1=this; lf->m_flow_id=rxh->m_flow_id; if (rxh->get_both_dir()) { lf->set_both_dir(); } CRxCheckFlowPerDir *lpd=&lf->m_dir[rxh->get_dir()]; lpd->set_fif_seen(rxh->m_flow_size); m_stats.m_fif++; m_stats.m_add++; m_stats.m_active++; }else{ m_stats.m_found++; CRxCheckFlowPerDir *lpd=&lf->m_dir[rxh->get_dir()]; if ( lpd->is_fif_seen() ){ lf->m_oo_err++; any_err=true; m_stats.m_err_fif_seen_twice++; if ( lpd->m_flow_size != rxh->m_flow_size ){ m_stats.m_err_flow_length_changed++; lf->m_oo_err++; } lpd->m_pkts++; }else{ /* first in direction , we are OK */ lpd->set_fif_seen(rxh->m_flow_size); } } }else{ /* NON FIF */ if (lf==0) { /* no flow at it is not the first packet */ /* the first packet was dropped ?? */ lf=m_ft.add(rxh->m_flow_id); assert(lf); lf->m_aging_timer_handle.m_object1=this; if (rxh->get_both_dir()) { lf->set_both_dir(); } lf->m_flow_id=rxh->m_flow_id; CRxCheckFlowPerDir * lpd=&lf->m_dir[rxh->get_dir()]; lpd->set_fif_seen(rxh->m_flow_size); m_stats.m_add++; m_stats.m_active++; m_stats.m_err_open_with_no_fif_pkt++; any_err=true; lf->m_oo_err++; }else{ m_stats.m_found++; CRxCheckFlowPerDir *lpd=&lf->m_dir[rxh->get_dir()]; if ( !lpd->is_fif_seen() ){ // init this dir lpd->set_fif_seen(rxh->m_flow_size); }else{ if ( lpd->m_flow_size != rxh->m_flow_size ){ m_stats.m_err_flow_length_changed++; lf->m_oo_err++; any_err=true; } /* check seq number */ uint16_t c_seq=lpd->m_seq; if ((c_seq) != rxh->m_pkt_id) { /* out of order issue */ lf->m_oo_err++; any_err=true; if (c_seq-1 == rxh->m_pkt_id) { m_stats.m_err_oo_dup++; }else{ if ((c_seq ) < rxh->m_pkt_id ) { m_stats.m_err_oo_late++; }else{ m_stats.m_err_oo_early++; } } } /* reset the seq */ lpd->m_seq=rxh->m_pkt_id+1; lpd->m_pkts++; } } } if (any_err) { update_template_err(rxh->m_template_id); } m_tw.restart_timer(&lf->m_aging_timer_handle,m_cur_time+std::max(rxh->m_aging_sec,(uint16_t)5)); /* teminate flow if needed */ if ( lf->is_all_pkts_seen() ){ /* handel from termination */ m_tw.stop_timer(&lf->m_aging_timer_handle); lf->set_aged_correctly(); on_flow_end(lf); } if ((m_stats.m_lookup & 0xff)==0) { /* handle aging from time to time */ tw_handle() ; } }
int login(T_Connect *conn,T_NetHead *NetHead) { int ret,crc; char tmp[200]; char *cp,*key; char tmp1[1024],cliaddr[20]; DWS dw; struct login_s logrec; ENIGMA egm; FILE *fd; T_SRV_Var *up; GDA *gp; //u_int e[RSALEN],m[RSALEN]; up=(T_SRV_Var *)conn->Var; gp=(GDA *)up->var; StrAddr(NetHead->O_NODE,cliaddr); ShowLog(5,"%s:TCB:%d Client IP Addr=%s,Net_login %s",__FUNCTION__,up->TCB_no,cliaddr,NetHead->data); net_dispack(&logrec,NetHead->data,login_type); strcpy(gp->devid,logrec.devid); sprintf(gp->ShowID,"%s:%s:%d",logrec.devid,cliaddr,up->TCB_no); mthr_showid_add(up->tid,gp->ShowID); conn->MTU=NetHead->ERRNO1; cp=getenv("KEYFILE"); if(!cp||!*cp) { strcpy(tmp1,"缺少环境变量 KEYFILE"); errret: ShowLog(1,"%s:Error %s",__FUNCTION__,tmp1); NetHead->ERRNO1=-1; NetHead->ERRNO2=-1; NetHead->PKG_REC_NUM=0; NetHead->data=tmp1; NetHead->PKG_LEN=strlen(NetHead->data); SendPack(conn,NetHead); return 0; // fail } /* read key */ crc=0; reopen: ret=initdw(cp,&dw); if(ret) { if((errno==24)&& (++crc<5)) { sleep(15); goto reopen; } sprintf(tmp1,"Init dw error %d",ret); goto errret; } crc=ssh_crc32((unsigned char *)logrec.devid,strlen(logrec.devid)); key=getdw(crc,&dw); if(!key) { freedw(&dw); sprintf(tmp1,"无效的 DEVID"); goto errret; } //ShowLog(5,"getdw key=%s",key); enigma1_init(egm,key); /* check CA */ memset(gp->operid,0,sizeof(gp->operid)); cp=getenv("CADIR"); if(!cp||!*cp) cp="."; if(strcmp(gp->devid,"REGISTER")) { strncpy(gp->operid,logrec.uid,sizeof(gp->operid)-1); sprintf(tmp,"%s/%s.CA",cp,logrec.devid); //ShowLog(5,"CAfile=%s,key=%s",tmp,key); fd=fopen(tmp,"r"); if(!fd) { if(errno==2) { crc=strlen(logrec.CA); frenz_encode(egm,logrec.CA,crc); byte_a64(tmp1,logrec.CA,crc); //ShowLog(5,"CA=%s",tmp1); fd=fopen(tmp,"w"); if(!fd) { sprintf(tmp1,"write %s err=%d",tmp,errno); err1: freedw(&dw); goto errret; } fprintf(fd,"%s\n",tmp1); fclose(fd); } else { sprintf(tmp1,"open CAfile %s err=%d",tmp,errno); goto err1; } } else { fgets(tmp1,sizeof(logrec.CA),fd); fclose(fd); TRIM(tmp1); ret=a64_byte(tmp,tmp1); frenz_decode(egm,tmp,ret); tmp[ret]=0; if(strcmp(tmp,logrec.CA)) { sprintf(tmp1,"CA 错误"); ShowLog(1,"%s:%s CA=%s log=%s len=%d",__FUNCTION__,tmp1,tmp,logrec.CA,ret); goto err1; } } } else { //未注册客户端注册 char *p; char *keyD; /* REGISTER label|CA|devfile|CHK_Code| */ ShowLog(2,"REGISTER %s",logrec.uid); if(!*logrec.uid) { sprintf(tmp1,"REGSTER is empty!"); goto err1; } //uid=devfile crc=0xFFFF&gencrc((unsigned char *)logrec.uid,strlen(logrec.uid)); //pwd=CHK_Code sscanf(logrec.pwd,"%04X",&ret); ret &= 0xFFFF; if(ret != crc) { sprintf(tmp1,"REGISTER:devfile CHK Code error! ");//, crc,ret); goto err1; } p=stptok(logrec.uid,logrec.devid,sizeof(logrec.devid),".");//logrec.devid=准备注册的DEVID crc=ssh_crc32((unsigned char *)logrec.devid,strlen(logrec.devid)); keyD=getdw(crc,&dw); if(!keyD) { sprintf(tmp1,"注册失败,%s:没有这个设备!", logrec.devid); goto err1; } enigma1_init(egm,keyD); sprintf(tmp,"%s/%s.CA",cp,logrec.devid); ShowLog(5,"REGISTER:%s",tmp); if(0!=(fd=fopen(tmp,"r"))) { fgets(tmp1,81,fd); fclose(fd); TRIM(tmp1); ret=a64_byte(tmp,tmp1); frenz_decode(egm,tmp,ret); tmp[ret]=0; if(strcmp(tmp,logrec.CA)) { sprintf(tmp1,"注册失败,%s 已被注册,使用中。", logrec.devid); goto err1; } } else if(errno != 2) { sprintf(tmp1,"CA 错误"); goto err1; } /*把设备特征码写入文件*/ fd=fopen(tmp,"w"); if(fd) { int len=strlen(logrec.CA); frenz_encode(egm,logrec.CA,len); byte_a64(tmp1,logrec.CA,len); fprintf(fd,"%s\n",tmp1); fclose(fd); } else ShowLog(1,"net_login:REGISTER open %s for write,err=%d,%s", tmp,errno,strerror(errno)); freedw(&dw); sprintf(tmp,"%s/%s",cp,logrec.uid); fd=fopen(tmp,"r"); if(!fd) { sprintf(tmp1,"REGISTER 打不开文件 %s err=%d,%s", logrec.CA,errno,strerror(errno)); goto errret; } fgets(logrec.uid,sizeof(logrec.uid),fd); TRIM(logrec.uid); ShowLog(2,"REGISTER open %s",tmp); fclose(fd); cp=tmp1; cp+=sprintf(cp,"%s|%s|", logrec.devid,logrec.uid); cp+=sprintf(cp,"%s|",rsecstrfmt(tmp,now_sec(),YEAR_TO_SEC)); NetHead->data=tmp1; NetHead->PKG_LEN=strlen(NetHead->data); NetHead->ERRNO1=0; NetHead->ERRNO2=0; NetHead->PKG_REC_NUM=0; SendPack(conn,NetHead); return -1; } //未注册客户端注册完成 freedw(&dw); up->poolno=get_scpool_no(NetHead->D_NODE); if(up->poolno<0) { sprintf(tmp1,"非法的D_NODE %d",NetHead->D_NODE); goto errret; } ret=get_s_connect(up->TCB_no,up->poolno,&gp->server,login_finish); if(ret==0) return login_finish(conn,NetHead); else if(ret==1) return -5; sprintf(tmp1,"错误的参数"); goto errret; }
/** * Retrieves a thread from the pool of active threads in a * round-robin fashion. */ struct task* rec_sched_get_active_thread(struct task* t, int* by_waitpid) { int max_events = rr_flags()->max_events; struct tasklist_entry* entry = current_entry; struct task* next_t = NULL; debug("Scheduling next task"); *by_waitpid = 0; if (!entry) { entry = current_entry = CIRCLEQ_FIRST(&head); } if (t && !t->switchable) { debug(" (%d is un-switchable)", t->tid); if (task_may_be_blocked(t)) { debug(" and not runnable; waiting for state change"); /* |t| is un-switchable, but not runnable in * this state. Wait for it to change state * before "scheduling it", so avoid * busy-waiting with our client. */ #ifdef MONITOR_UNSWITCHABLE_WAITS double start = now_sec(), wait_duration; #endif sys_waitpid(t->tid, &t->status); #ifdef MONITOR_UNSWITCHABLE_WAITS wait_duration = now_sec() - start; if (wait_duration >= 0.010) { warn("Waiting for unswitchable %s took %g ms", strevent(t->event), 1000.0 * wait_duration); } #endif *by_waitpid = 1; debug(" new status is 0x%x", t->status); } return t; } /* Prefer switching to the next task if the current one * exceeded its event limit. */ if (t && t->succ_event_counter > max_events) { debug(" previous task exceeded event limit, preferring next"); entry = current_entry = next_entry(entry); t->succ_event_counter = 0; } /* Go around the task list exactly one time looking for a * runnable thread. */ do { pid_t tid; next_t = &entry->t; tid = next_t->tid; if (next_t->unstable) { debug(" %d is unstable, going to waitpid(-1)", tid); next_t = NULL; break; } if (!task_may_be_blocked(next_t)) { debug(" %d isn't blocked, done", tid); break; } debug(" %d is blocked on %s, checking status ...", tid, strevent(next_t->event)); if (0 != sys_waitpid_nonblock(tid, &next_t->status)) { *by_waitpid = 1; debug(" ready with status 0x%x", next_t->status); break; } debug(" still blocked"); } while (next_t = NULL, current_entry != (entry = next_entry(entry))); if (!next_t) { /* All the tasks are blocked. Wait for the next one to * change state. */ int status; pid_t tid; debug(" all tasks blocked or some unstable, waiting for runnable (%d total)", num_active_threads); while (-1 == (tid = waitpid(-1, &status, __WALL | WSTOPPED | WUNTRACED))) { if (EINTR == errno) { debug(" waitpid() interrupted by EINTR"); continue; } fatal("Failed to waitpid()"); } debug(" %d changed state", tid); entry = get_entry(tid); next_t = &entry->t; assert(next_t->unstable || task_may_be_blocked(next_t)); next_t->status = status; *by_waitpid = 1; } current_entry = entry; note_switch(t, next_t, max_events); return next_t; }