static void debug_getthreadinfo(struct gdbcontext *ctx, const char *threadid) { unsigned cpunum; char buf[128], xbuf[256]; size_t i; cpunum = getthreadid(threadid); if (cpunum >= cpu_numcpus()) { debug_send(ctx, "E00"); return; } /* * Send back string of whatever info we want. Since gdb * already fetches and prints the frame info, and fetches this * but doesn't seem to print it, I dunno what to send. */ snprintf(buf, sizeof(buf), "CPU %u", cpunum); /* Code as hex for transmission */ xbuf[0] = 0; for (i=0; buf[i]; i++) { printbyte(xbuf, sizeof(xbuf), (unsigned char)buf[i]); } debug_send(ctx, xbuf); }
bool openprocess(DWORD pid, DWORD process_access, DWORD thread_access, PROCESS_INFORMATION& pi) { closeprocess(pi); static bool ok = setdebugprivilege(); if (!ok) { return false; } pi.dwProcessId = pid; pi.hProcess = OpenProcess(process_access, FALSE, pi.dwProcessId); if (!pi.hProcess) { closeprocess(pi); return false; } pi.dwThreadId = getthreadid(pi.dwProcessId); if (!pi.dwThreadId) { closeprocess(pi); return false; } pi.hThread = OpenThread(thread_access, FALSE, pi.dwThreadId); if (!pi.hThread) { closeprocess(pi); return false; } return true; }
static int xfread(char *buf,int siz,int nel,FILE *fp){ int rel; fPollIn(fp,0); errno = 0; rel = fread(buf,siz,nel,fp); if( rel == 0 ){ while( !feof(fp) ){ fPollIn(fp,0); rel = fread(buf,siz,nel,fp); fprintf(stderr,"----[%d] dgzlib:fread(%d)=%d RETRY\n", getpid(),fileno(fp),rel); if( 0 < rel ){ break; } } } if( rel <= 0 ){ syslog_ERROR("[%X] xfread rcc=%d/%d +%d errno=%d\n", getthreadid(),rel,nel,inlen,errno); } if( 0 < rel ){ inlen += rel; if( errno == EAGAIN ){ //fprintf(stderr,">>>>>>> dgzlib:fread(%d)=%d, errno=%d\n",fileno(fp),rel,errno); clearerr(fp); errno = 0; } } return rel; }
int ismainthread(){ int tid; tid = getthreadid(); if( main_thread == 0 || main_thread == tid ){ return tid; } return 0; }
int thread_kill(int tid,int sig){ if( ThreadKill ){ if( tid == MAINTHREADID ){ tid = main_thread; syslog_ERROR("Killing main-thread %X <- %X\n", tid,getthreadid()); } return (*ThreadKill)(tid,sig); } return -1; }
vfuncp Vsignal_FL(FL_PAR,int sig,vfuncp func){ ThreadSig *ts; vfuncp ofunc; int tix; if( isWindowsCE() ){ return 0; } if( sig < 0 || 32 <= sig ){ return signal(sig,func); } if( lMULTIST() ){ tix = 1+getthreadix(); setupCSC("Vsignal",sigCSC,sizeof(sigCSC)); enterCSC(sigCSC); ts = &sigs[0][sig]; if( ts->ts_stat == 0 ){ ts->ts_stat = 1; ts->ts_tid = getthreadid(); ts->ts_func = signal(sig,sigANY); ts->ts_F = FL_F; ts->ts_L = FL_L; } ts = &sigs[tix][sig]; ofunc = ts->ts_func; ts->ts_stat = 1; ts->ts_tid = getthreadid(); ts->ts_func = func; ts->ts_F = FL_F; ts->ts_L = FL_L; leaveCSC(sigCSC); if( lTHREADSIG() ){ fprintf(stderr,"-- %X %d/%d Vsignal(%d,%X) <= %s:%d\n", TID,actthreads(),numthreads(), sig,xp2i(func),FL_BAR); } return ofunc; } ofunc = signal(sig,func); return ofunc; }
static int getix(int tid){ int ix; if( tid == 0 ){ tid = getthreadid(); } for( ix = 0; ix < elnumof(threadsSerno); ix++ ){ if( threads[ix].t_id == tid ){ return ix; } } return -1; }
static int toFlash(XFlash *Xf,PCStr(fmt),...){ VARGS(16,fmt); fprintf(stderr,"####[%4X] XFlash ",PRTID(getthreadid())); fprintf(stderr,fmt,VA16); fprintf(stderr,"\n"); if( Xf->xf_xfsockfp != NULL ){ fprintf(Xf->xf_xfsockfp,fmt,VA16); fprintf(Xf->xf_xfsockfp,"\r\n"); fflush(Xf->xf_xfsockfp); } return 0; }
void servlog(PCStr(fmt),...){ FILE *lfp; VARGS(8,fmt); lfp = fopen("c:/tmp/svlog","a"); if( lfp == NULL ){ return; } fprintf(stderr,"[%d] ",getpid()); fprintf(stderr,fmt,VA8); fprintf(lfp,"[%d][%d] ",getpid(),getthreadid()); fprintf(lfp,fmt,VA8); fflush(lfp); fclose(lfp); }
int destroythreads(){ int ix; int tid; int fin = 0; int mytid = getthreadid(); for( ix = 0; ix < elnumof(threads); ix++ ){ if( tid = threads[ix].t_id ){ if( tid != mytid ){ if( thread_destroy(tid) == 0 ){ fin++; } } } } return fin; }
static void debug_checkthread(struct gdbcontext *ctx, const char *threadid) { unsigned cpunum; cpunum = getthreadid(threadid); if (cpunum >= cpu_numcpus()) { debug_send(ctx, "E00"); return; } if (!cpu_enabled(cpunum)) { debug_send(ctx, "E01"); return; } debug_send(ctx, "OK"); }
static int getthreadixX(int atid){ int tid,ix; int nix = -1; int mytid = getthreadid(); if( atid ) tid = atid; else tid = mytid; /* else tid = getthreadid(); */ for( ix = 0; ix < elnumof(threads); ix++ ){ if( threads[ix].t_id == 0 ){ if( nix < 0 ){ nix = ix; } } if( tideq(threads[ix].t_id,tid) ){ return ix; } } if( tid != mytid ){ porting_dbg("ERROR: getthreadix(%X) non-existing %X %X", atid,tid,mytid); /* it might exit already (or not yet active) */ return 0; } if( 0 <= nix ){ ix = nix; thtabAdd++; threadsSerno[ix].t_serno = thtabAdd; threadsSerno[ix].t_reqno = 0; threads[ix].t_id = tid; threads[ix].t_tgid = 0; threads[ix].t_F = "new"; threads[ix].t_L = 0; return ix; } porting_dbg("ERROR: getthreadix() no more threads (%d)",ix); return 0; }
void execCloseOnFork(PCStr(wh)) { int fd,rcode; int nulfd; for( fd = 0; fd < elnumof(cof_fds); fd++ ) { if( cof_fds[fd] != 0 ) { if( 0 <= (nulfd = openNull(0)) ) { rcode = close(fd); dup2(nulfd,fd); close(nulfd); } else rcode = close(fd); if( LOG_VERBOSE || lTHREAD() ) fprintf(stderr,"[%d.%X]execCloseOnFork(%s,%d)=%d\n", getpid(),getthreadid(),wh,fd,rcode); syslog_ERROR("{t} execCloseOnFork(%s,%d)=%d\n",wh,fd,rcode); cof_fds[fd] = 0; } } }
static FILE *setStopService(PCStr(addr)) { /* daemonlog("F","####! EMERGENCY STOP !####\n"); */ if( newthreads() || numthreads() || pnumthreads() ){ extern const char *SSLstage; int getXf_list(PVStr(Xf)); IStr(Xf,128); setgotsigTERM(999); getXf_list(AVStr(Xf)); putfLog("####! thread-EMERGENCY-STOP !#### %X in (%s)(%s)(%s)", ismainthread(),Xf,SSLstage?SSLstage:"",PRTHstage); dumpThreads("thread-EMERGENCY-STOP"); } daemonlog("F","####! EMERGENCY STOP !#### [%d.%X]%X %d/%d\n", getpid(),getthreadid(),ismainthread(), actthreads(),numthreads()); return stopServ("setStopService","a",addr); }
int dumpThreads(PCStr(wh)){ int nt = 0; int ix; int me; int tid; Thread *tp; me = getthreadid(); for( ix = 0; ix < elnumof(threads); ix++ ){ tp = &threads[ix]; if( tid = tp->t_id ){ putfLog("--TH[%d] %s %04X %04Xg (%s) %s:%d %s %s", ix,wh, PRTID(tp->t_id),PRTID(tp->t_tgid), tp->t_what?tp->t_what:"", tp->t_F?tp->t_F:"",tp->t_L, tp->t_stat?tp->t_stat:"", tid==me?"*":"" ); nt++; } } return nt; }
/* pkt is null-terminated */ void debug_exec(struct gdbcontext *ctx, const char *pkt) { char *cs; /* start of the checksum */ int i; int check = 0, scheck; #ifdef SHOW_PACKETS msg("Got packet %s", pkt); #endif if (pkt[0] != '$') { return; } cs = strchr(pkt, '#'); if (cs == NULL) { return; } *cs = 0; cs++; for (i=1; pkt[i]; i++) { check += pkt[i]; } scheck = strtoul(cs, NULL, 16); if (scheck != check % 256) { write(ctx->myfd, "-", 1); return; } else { write(ctx->myfd, "+", 1); } switch (pkt[1]) { case '!': /* * Enable extended mode -- extended mode is apparently * where gdb can ask to rerun the program. We can't do * that... although it could probably be arranged. * * Reply with "OK" if extended mode is enabled. */ debug_notsupp(ctx); break; case '?': /* Report why the target stopped. */ debug_send_stopinfo(ctx); break; case 'A': /* * Set argv[]. We can't do this, although it might make * sense if we grow support for reloading the kernel. */ debug_notsupp(ctx); break; case 'b': if (pkt[2] == 0) { /* Set serial bit rate; deprecated. */ debug_notsupp(ctx); break; } else if (pkt[2] == 'c') { /* Backward continue - resume executing, backwards */ } else if (pkt[2] == 's') { /* Backward single step - execute one insn backwards */ } else { /* ? */ } debug_notsupp(ctx); break; case 'B': /* Set or clear breakpoint; old, deprecated. */ debug_notsupp(ctx); break; case 'c': /* * Continue. If an address follows the 'c', continue * from that address. debug_restart() does that. */ debug_restart(ctx, pkt + 2); unset_breakcond(); break; case 'C': /* * Continue with signal. A signal number in hex * follows the C; that may be followed with a * semicolon and an address to continue at. We don't * have signals per se; in theory we could fake up * some mapping of signals to hardware traps, but that * would be difficult to arrange and not serve much * purpose. */ debug_notsupp(ctx); break; case 'd': /* Toggle debug flag (whatever that means); deprecated. */ debug_notsupp(ctx); break; case 'D': /* * Detach. With a process-id, detach only one process, * if the multiprocess extension is in use. */ debug_send(ctx, "OK"); unset_breakcond(); break; case 'F': /* * File I/O extension reply; for now at least we have * no use for this. */ debug_notsupp(ctx); break; case 'g': /* Read general-purpose registers */ debug_register_print(ctx); break; case 'G': /* * Write general-purpose registers. The G is followed * by a register dump in the same format as the 'g' * reply. */ // XXX gcc docs say this is required debug_notsupp(ctx); break; case 'H': /* * Hc followed by a thread ID sets the thread that * step and continue operations should affect; Hg * followed by a thread ID sets the thread that * other operations should affect. */ if (pkt[2] == 'c') { debug_notsupp(ctx); } else if (pkt[2] == 'g') { unsigned cpunum; cpunum = getthreadid(pkt+3); if (cpunum >= cpu_numcpus()) { debug_send(ctx, "E00"); break; } debug_cpu = cpunum; debug_send(ctx, "OK"); } else { debug_send(ctx, "OK"); } break; case 'i': /* Step by cycle count */ debug_notsupp(ctx); break; case 'I': /* Step by cycle count with signal (apparently) */ debug_notsupp(ctx); break; case 'k': /* Kill the target */ // don't do this - debugger hangs up and we get SIGPIPE //debug_send(ctx, "OK"); msg("Debugger requested kill"); reqdie(); // To continue running instead of dying, do this instead //unset_breakcond(); break; case 'm': /* Read target memory */ debug_read_mem(ctx, pkt + 2); break; case 'M': /* Write target memory */ debug_write_mem(ctx, pkt + 2); break; case 'p': /* read one register */ debug_notsupp(ctx); break; case 'P': /* write one register */ debug_notsupp(ctx); break; case 'q': /* General query */ if (strcmp(pkt + 2, "C") == 0) { /* Return current thread id */ debug_sendf(ctx,"QC%x", mkthreadid(debug_cpu)); } else if (!strcmp(pkt+2, "fThreadInfo")) { char buf[128]; unsigned i; strcpy(buf, "m"); for (i=0; i<cpu_numcpus(); i++) { if (!cpu_enabled(i)) { continue; } if (i > 0) { strcat(buf, ","); } printbyte(buf, sizeof(buf), mkthreadid(i)); } debug_send(ctx, buf); } else if (!strcmp(pkt+2, "sThreadInfo")) { debug_send(ctx, "l"); } else if (strcmp(pkt+2, "Offsets") == 0) { /* Return info about load-time relocations */ debug_notsupp(ctx); } else if (strcmp(pkt+2, "Supported") == 0) { /* Features handshake */ debug_notsupp(ctx); } else if (!strncmp(pkt+2, "ThreadExtraInfo,", 16)) { debug_getthreadinfo(ctx, pkt+2+16); } else { debug_notsupp(ctx); } break; case 'Q': /* General set mode (I think) */ debug_notsupp(ctx); break; case 'r': /* Reset target - deprecated */ debug_notsupp(ctx); break; case 'R': /* * Restart target (only with extended mode enabled). * Do not reply. */ break; case 's': /* Single step */ debug_restart(ctx, pkt + 2); onecycle(); debug_send_stopinfo(ctx); break; case 'S': /* Single step with signal */ debug_notsupp(ctx); break; case 't': /* search memory for a pattern (underdocumented) */ debug_notsupp(ctx); break; case 'T': /* check if a thread is alive (OK - yes; E.. - no) */ debug_checkthread(ctx, pkt + 2); break; case 'v': /* various longer commands */ debug_notsupp(ctx); break; case 'X': /* Write target memory with a more efficient encoding */ debug_notsupp(ctx); break; case 'z': case 'Z': /* insert (Z) or remove (z) one of the following: */ switch (pkt[2]) { case '0': /* set or clear memory breakpoint */ debug_notsupp(ctx); break; case '1': /* set or clear hardware breakpoint */ debug_notsupp(ctx); break; case '2': /* set or clear write watchpoint */ debug_notsupp(ctx); break; case '3': /* set or clear read watchpoint */ debug_notsupp(ctx); break; case '4': /* set or clear access watchpoint */ debug_notsupp(ctx); break; default: /* ? */ debug_notsupp(ctx); break; } break; default: debug_notsupp(ctx); break; } }
int thread_done(void *xcode){ int tid; tid = getthreadid(); return thread_doneX(tid,xcode); }
int thread_fork(int size,int gtid,PCStr(what),IFUNCP func,...) { int tid; int ix; int smask,nmask; VARGS(8,func); if( main_thread == 0 ){ main_thread = getthreadid(); main_thread_pid = getpid(); if( THREAD_WAIT_TIMEOUT ){ IGNRETZ pipe(ThreadsDone); ThreadsWaitTO = 1; } } if( ThreadFork ) { /* MyPID = 0; */ NewThreads++; setupCSC("thread_fork",thforkCSC,sizeof(thforkCSC)); enterCSC(thforkCSC); Nthreads++; nmask = sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGPIPE); smask = sigblock(nmask); tid = (*ThreadFork)(size,what,func,VA8); if( tid != 0 ){ ActiveThreads++; if( ActiveThreadsMax < ActiveThreads ){ ActiveThreadsMax = ActiveThreads; } SpawnedThreads++; if( lTHFORKSYNC() ){ /* should wait the thread to be Started to make * the parallel behavior consistent, but it might * affect signal handling ? */ void msleep(int ms); msleep(0); } /* 9.8.5 the thread might exit already, don't add ghost if( 0 <= (ix = getthreadixY(tid)) ){ threads[ix].t_what = what; } */ putpplog("actthreads()++=%d [%X]\n",ActiveThreads,tid); } sigsetmask(smask); leaveCSC(thforkCSC); NewThreads--; if( lTHREADLOG() ){ const void *toThd(int tid,int del,int *ser); FileSize thd; thd = p2llu(toThd(tid,0,0)); syslog_ERROR("thread_fork(%s %X %X)A%d = %X/%llX\n", what,size,gtid,actTid(),tid,thd); } return tid; /* return (*ThreadFork)(size,func,VA8); */ } porting_dbg("NO thread_fork() available."); exit(-1); return -1; }
static boolean threadcallscriptverb (bigstring bsscriptname, tyvaluerecord vparams, hdlhashtable hcontext, tyvaluerecord *v) { /* 8.0.4 dmb: handle running code values 9.1b3 AR: copy bsscriptname to processrecord so the thread can be more easily identified in the system.compiler.threads table */ hdlprocessrecord hp; hdlprocessthread hthread; bigstring bsverb; boolean fl = false; boolean flchained = false; tyvaluerecord val; hdltreenode hfunctioncall; hdltreenode hparamlist; hdltreenode hcode; hdlhashtable htable; tyvaluerecord vhandler; hdlhashnode handlernode; /*build code tree, see langrunscript*/ pushhashtable (roottable); fl = langexpandtodotparams (bsscriptname, &htable, bsverb); if (fl && htable == nil) langsearchpathlookup (bsverb, &htable); pophashtable(); if (!fl) goto exit; if (!hashtablelookupnode (htable, bsverb, &handlernode)) { langparamerror (unknownfunctionerror, bsverb); goto exit; } vhandler = (**handlernode).val; /*build a code tree and call the handler, with our error hook in place*/ hcode = nil; if (vhandler.valuetype == codevaluetype) { hcode = vhandler.data.codevalue; } else if ((**htable).valueroutine == nil) { /*not a kernel table*/ if (!langexternalvaltocode (vhandler, &hcode)) { langparamerror (notfunctionerror, bsverb); goto exit; } if (hcode == nil) { /*needs compilation*/ if (!langcompilescript (handlernode, &hcode)) goto exit; } } if (!setaddressvalue (htable, bsverb, &val)) goto exit; if (!pushfunctionreference (val, &hfunctioncall)) goto exit; if (hcontext != nil) { flchained = (**hcontext).flchained; if (flchained) pushhashtable (hcontext); else chainhashtable (hcontext); /*establishes outer local context*/ } fl = langbuildparamlist (&vparams, &hparamlist); if (hcontext != nil) { if (flchained) pophashtable (); else unchainhashtable (); } if (!fl) { langdisposetree (hfunctioncall); goto exit; } if (!pushfunctioncall (hfunctioncall, hparamlist, &hcode)) /*consumes input parameters*/ goto exit; if (!pushbinaryoperation (moduleop, hcode, nil, &hcode)) /*needs this level???*/ goto exit; /*launch separate process, see processruntext*/ newlyaddedprocess = nil; //process manager global if (!addnewprocess (hcode, true, nil, (long) 0)) { langdisposetree (hcode); goto exit; } /*return thread id*/ hp = newlyaddedprocess; //process.c global; will be nil if a process wasn't just added if ((hp == nil) || !scheduleprocess (hp, &hthread)) return (setlongvalue (0, v)); (**hp).processstartedroutine = &threadverbprocessstarted; //don't dim the menu bar copystring (bsscriptname, (**hp).bsname); /* 9.1b3 AR */ if (hcontext != nil) { Handle hpacked; boolean fldummy; /*make a copy of the context table*/ if (!tablepacktable (hcontext, true, &hpacked, &fldummy)) goto exit; if (!tableunpacktable (hpacked, true, &hcontext)) goto exit; /*set the child thread's context to the copy of the context table*/ (**hp).hcontext = hcontext; /*make sure the copy of the context table will be disposed*/ (**hp).processkilledroutine = &threaddisposecontext; } return (setlongvalue (getthreadid (hthread), v)); exit: return (false); }/*threadcallscriptverb*/
int clearthreadsix(){ int tid,ix; tid = getthreadid(); return clearthreadsixX(tid); }
static boolean threadfunctionvalue (short token, hdltreenode hparam1, tyvaluerecord *vreturned, bigstring bserror) { /* 4.1b3 dmb: new verbs 4.1b5 dmb: added thread.sleep 4.1b6 dmb: make thread.sleepFor take seconds, not ticks 5.0d13 dmb: added v == nil check */ register tyvaluerecord *v = vreturned; typrocessid processid; unsigned long ticks; if (v == nil) { /*need Frontier process?*/ switch (token) { case evaluatefunc: case callscriptfunc: case sleepfunc: case sleepforfunc: case sleepticksfunc: case issleepingfunc: case wakefunc: case killfunc: /* case begincriticalfunc: case endcriticalfunc: */ case statsfunc: return (true); case existsfunc: case getcurrentfunc: case getcountfunc: case getnththreadfunc: case gettimeslicefunc: case getdefaulttimeslicefunc: case settimeslicefunc: case setdefaulttimeslicefunc: default: return (false); } } setbooleanvalue (false, v); // assume the worst processid = getcurrentprocessid (); if (!iscurrentapplication (processid)) { getstringlist (langerrorlist, cantbackgroundclipboard, bserror); // *** return (false); } switch (token) { case existsfunc: { long id; flnextparamislast = true; if (!getlongvalue (hparam1, 1, &id)) return (false); return (setbooleanvalue (getprocessthread (id) != nil, v)); } case evaluatefunc: { Handle htext; hdlprocessrecord hp; hdlprocessthread hthread; flnextparamislast = true; if (!getexempttextvalue (hparam1, 1, &htext)) return (false); newlyaddedprocess = nil; //process manager global if (!processruntext (htext)) return (false); hp = newlyaddedprocess; //process.c global; will be nil if a process wasn't just added if ((hp == nil) || !scheduleprocess (hp, &hthread)) return (setlongvalue (0, v)); (**hp).processstartedroutine = &threadverbprocessstarted; return (setlongvalue (getthreadid (hthread), v)); } case callscriptfunc: { bigstring bsscriptname; tyvaluerecord vparams; hdlhashtable hcontext = nil; boolean fl; if (!getstringvalue (hparam1, 1, bsscriptname)) return (false); if (!getparamvalue (hparam1, 2, &vparams)) return (false); if (vparams.valuetype != recordvaluetype) if (!coercetolist (&vparams, listvaluetype)) return (false); if (langgetparamcount (hparam1) > 2) { flnextparamislast = true; if (!gettablevalue (hparam1, 3, &hcontext)) return (false); } (**(getcurrentthreadglobals ())).debugthreadingcookie = token; fl = threadcallscriptverb (bsscriptname, vparams, hcontext, v); (**(getcurrentthreadglobals ())).debugthreadingcookie = 0; return (fl); } case getcurrentfunc: if (!langcheckparamcount (hparam1, 0)) return (false); return (setlongvalue (getthreadid (getcurrentthread ()), v)); case getcountfunc: if (!langcheckparamcount (hparam1, 0)) return (false); return (setlongvalue (processthreadcount (), v)); case getnththreadfunc: { short n; flnextparamislast = true; if (!getintvalue (hparam1, 1, &n)) return (false); return (setlongvalue (getthreadid (nthprocessthread (n)), v)); } case sleepfunc: { hdlprocessthread hthread; flnextparamislast = true; if (!getthreadvalue (hparam1, 1, &hthread)) return (false); return (setbooleanvalue (processsleep (hthread, -1), v)); } case sleepforfunc: { long n; boolean fl; flnextparamislast = true; if (!getlongvalue (hparam1, 1, &n)) return (false); (**(getcurrentthreadglobals ())).debugthreadingcookie = token; fl = processsleep (getcurrentthread (), n * 60); (**(getcurrentthreadglobals ())).debugthreadingcookie = 0; return (setbooleanvalue (fl, v)); } case sleepticksfunc: { long n; boolean fl; flnextparamislast = true; if (!getlongvalue (hparam1, 1, &n)) return (false); (**(getcurrentthreadglobals ())).debugthreadingcookie = token; fl = processsleep (getcurrentthread (), n); (**(getcurrentthreadglobals ())).debugthreadingcookie = 0; return (setbooleanvalue (fl, v)); } case issleepingfunc: { hdlprocessthread hthread; flnextparamislast = true; if (!getthreadvalue (hparam1, 1, &hthread)) return (false); return (setbooleanvalue (processissleeping (hthread), v)); } case wakefunc: { hdlprocessthread hthread; flnextparamislast = true; if (!getthreadvalue (hparam1, 1, &hthread)) return (false); return (setbooleanvalue (wakeprocessthread (hthread), v)); } case killfunc: { hdlprocessthread hthread; flnextparamislast = true; if (!getthreadvalue (hparam1, 1, &hthread)) return (false); return (setbooleanvalue (killprocessthread (hthread), v)); } case gettimeslicefunc: if (!langcheckparamcount (hparam1, 0)) return (false); getprocesstimeslice (&ticks); return (setlongvalue (ticks, v)); case settimeslicefunc: flnextparamislast = true; if (!getlongvalue (hparam1, 1, (long *) (&ticks))) return (false); return (setbooleanvalue (setprocesstimeslice (ticks), v)); case getdefaulttimeslicefunc: if (!langcheckparamcount (hparam1, 0)) return (false); getdefaulttimeslice (&ticks); return (setlongvalue (ticks, v)); case setdefaulttimeslicefunc: flnextparamislast = true; if (!getlongvalue (hparam1, 1, (long *) (&ticks))) return (false); return (setbooleanvalue (setdefaulttimeslice (ticks), v)); /* case begincriticalfunc: if (!langcheckparamcount (hparam1, 0)) return (false); ++fldisableyield; return (setbooleanvalue (true, v)); case endcriticalfunc: if (!langcheckparamcount (hparam1, 0)) return (false); if (fldisableyield > 0) { --fldisableyield; (*v).data.flvalue = true; } return (true); */ case statsfunc: return (threadstatsverb (hparam1, v)); default: return (false); } } /*threadfunctionvalue*/
/* * 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); } }
static void gotSIG(PCStr(F),int L,ThreadIO *myenv,int timeout){ sv1log("IO_TIMOEUT[%d]%X %X longreturn SIG%s timeout=%d [%d] %s:%d/%d\n", getthreadix(),getthreadid(),myenv->t_id, sigsym(myenv->t_sig),timeout, myenv->t_fd,F,L,myenv->t_cln); }
int gzipFilterX(FILE *in,FILE *out,SyncXF syncf,void *sp,int si){ gzFile gz; int len,rcc; CStr(buf,1024*8); int size; int gsize; int wcc; int bcc = 0; double Start = Time(); double Prevf = 0; int ibz = sizeof(buf); int gi; int fd = -1; int ofd = fileno(out); int xfd; int zerr = 0; /* int rready = -1; */ errno = 0; fd = dup(fileno(out)); if( fd < 0 ){ syslog_ERROR("--gzipFilter[%d]<-[%d] errno=%d\n",fd,ofd,errno); return -1; } /* if( 0 <= GZIPready ) rready = dup(GZIPready); */ len = 0; /* if( gz = GZdopen(dup(fileno(out)),"w") ){ */ if( file_isSOCKET(ofd) || file_ISSOCK(ofd) ) if( !IsConnected(ofd,NULL) || !IsAlive(ofd) ){ fprintf(stderr,"[%d.%X] gzip DISCONN\n",getpid(),getthreadid()); fprintf(stderr,"[%d.%X] gzip DISCONN fd[%d] con=%d isSOCK=%d,%d,%d\n", getpid(),getthreadid(),ofd,IsConnected(ofd,NULL), file_isSOCKET(ofd),file_ISSOCK(ofd),file_issock(ofd)); sendsync(rready,1); close(fd); return -1; } gz = GZdopen(fd,"w"); if( file_isSOCKET(ofd) || file_ISSOCK(ofd) ) if( !IsConnected(ofd,NULL) || !IsAlive(ofd) ){ fprintf(stderr,"[%d.%X] gzip DISCONN gx=%d\n",getpid(),getthreadid(),p2i(gz)); fprintf(stderr,"[%d.%X] gzip DISCONN fd[%d] con=%d isSOCK=%d,%d,%d\n", getpid(),getthreadid(),ofd,IsConnected(ofd,NULL), file_isSOCKET(ofd),file_ISSOCK(ofd),file_issock(ofd)); close(fd); sendsync(rready,2); close(fd); return -1; } if( gz ){ LOGX_gzip++; if( Gzip_NoFlush ){ GZDBG(stderr,"-- %X gzip flush disabled(%d)\n", TID,Gzip_NoFlush); } Prevf = Time(); sendsync(rready,0); setCloseOnFork("GZIPstart",fd); /* while( rcc = fread(buf,1,sizeof(buf),in) ){ */ for( gi = 0;; gi++ ){ if( gotsigTERM("gzip gi=%d",gi) ){ if( numthreads() && !ismainthread() ){ thread_exit(0); } break; } if( !Gzip_NoFlush ) if( bcc ) if( 0 < len && finputReady(in,NULL) == 0 ){ zerr = gzflush(gz,Z_SYNC_FLUSH); if( zerr ){ porting_dbg("+++EPIPE[%d] gzflush() zerr=%d %d SIG*%d",fd,zerr,len,gotSIGPIPE()); } bcc = 0; } if( lSINGLEP() ) /* could be generic */ { if( 0 < len ) if( !Gzip_NoFlush || 4 < gi && 5 < Time()-Prevf ){ GZDBG(stderr,"-- %X gzip flush %d(%f) %d/%d\n", TID,Gzip_NoFlush,Time()-Start,len,gi); Prevf = Time(); zerr = gzflush(gz,Z_SYNC_FLUSH); bcc = 0; if( zerr ){ GZDBG(stderr,"-- %X gzip gzflush()%d err=%d\n", TID,len,zerr); break; } } } /* rcc = fread(buf,1,sizeof(buf),in); */ rcc = xread(in,AVStr(buf),QVSSize(buf,ibz)); if( rcc <= 0 ){ break; } wcc = gzwrite(gz,buf,rcc); //fprintf(stderr,"[%d] Gzwrite %d/%d / %d\n",getpid(),wcc,rcc,len); if( wcc <= 0 ){ porting_dbg("+++EPIPE[%d] gzwrite() %d/%d %d SIG*%d",fd,wcc,rcc,len,gotSIGPIPE()); fprintf(stderr,"[%d] Gzwrite %d/%d / %d\n",getpid(),wcc,rcc,len); break; } if( wcc != rcc ){ syslog_ERROR("gzwrite %d/%d\n",wcc,rcc); } if( 0 < wcc ){ bcc += wcc; } if( sizeof(buf) <= len ){ ibz = sizeof(buf); } if( !Gzip_NoFlush ) if( bcc ) if( sizeof(buf) <= bcc || len < 16*1024 ){ zerr = gzflush(gz,Z_SYNC_FLUSH); bcc = 0; } if( zerr || gotSIGPIPE() ){ porting_dbg("+++EPIPE[%d] gzflush() zerr=%d %d SIG*%d",fd,zerr,len,gotSIGPIPE()); break; } len += rcc; } if( len == 0 ){ const char *em; int en; int ef; em = gzerror(gz,&en); ef = gzeof(gz); if( en == -1 /* see errno */ && errno == 0 ){ /* no error */ }else{ daemonlog("F","FATAL: gzwrite(%d)=%d/%d eof=%d %d %s\n", fd,len,bcc,ef,en,em); porting_dbg("FATAL: gzwrite(%d)=%d/%d eof=%d %d %s", fd,len,bcc,ef,en,em); } } clearCloseOnFork("GZIPend",fd); gzflush(gz,Z_SYNC_FLUSH); xfd = dup(fd); gsize = GZtell(gz); GZclose(gz); if( isWindowsCE() || lMULTIST() ){ /* duplicated close of fd is harmful */ }else if( isWindows() ) close(fd); /* to clear osf-handle mapping */ Lseek(xfd,0,2); size = Lseek(xfd,0,1); Lseek(xfd,0,0); close(xfd); syslog_DEBUG("(%f)gzipFilter %d -> %d / %d\n",Time()-Start, len,gsize,size); return len; } sendsync(rready,3); close(fd); return 0; }
static int getConnSocket(int sock,SAP addr,int leng,int *rcsock,int *pending){ int si; int csi = -1; SockPool *sp; int got_csock = -1; double Now = Time(); double Age = 0; static int getOk; static int getNg; int rcode = -1; setupCSC("getConnSocket",sockCSC,sizeof(sockCSC)); enterCSC(sockCSC); *pending = 0; for( si = 0; si < elnumof(sockPool); si++ ){ sp = &sockPool[si]; if( sp->sp_Time == 0 ) continue; if( PCON_TIMEOUT < Now - sp->sp_Time ){ LOGX_tcpConAbandon2++; abandon(sp,1); continue; } if( sp->sp_leng != leng ){ continue; } if( bcmp(addr,&sp->sp_addr,leng) != 0 && VSA_addrcomp((VSAddr*)addr,&sp->sp_addr) != 0 ){ continue; } rcode = sp->sp_rcode; if( rcode == RCODE_RECYC ){ if( /* HTTP && */ inoutReady(sp->sp_sock,1) || !sock_isconnected(sp->sp_sock) ){ getNg++; /* porting_dbg("--getConnSock(%d/%d) age=%.2f [%d] NO-R %d:%d", si,sockPoolN,Now-sp->sp_Time,sp->sp_sock,getNg,getOk); */ LOGX_tcpConAbandon3++; abandon(sp,2); continue; } LOGX_tcpConRecycleOk++; }else{ if( inoutReady(sp->sp_sock,2) == 0 ){ if( PCON_TIMEOUT < Now - sp->sp_Time ){ porting_dbg("--getConnSock(%d/%d)%s age=%.2f [%d] NO-A", si,sockPoolN,sp->sp_what,Now-sp->sp_Time,sp->sp_sock); LOGX_tcpConAbandon4++; abandon(sp,3); }else{ *pending += 1; } continue; } if( !sock_isconnected(sp->sp_sock) ){ porting_dbg("--getConnSock(%d/%d)%s age=%.2f [%d] NO-B", si,sockPoolN,sp->sp_what,Now-sp->sp_Time,sp->sp_sock); LOGX_tcpConAbandon4++; abandon(sp,3); continue; } } getOk++; if( rcode != RCODE_RECYC ) porting_dbg("--getConnSock(%d/%d)%s age=%.2f [%d] OK (%d)", si,sockPoolN,sp->sp_what,Now-sp->sp_Time,sp->sp_sock,getOk); syslog_ERROR("--getConnSock(%d/%d)%s age=%.2f [%d] OK (%d)\n", si,sockPoolN,sp->sp_what,Now-sp->sp_Time,sp->sp_sock,getOk); Age = Now - sp->sp_Time; sp->sp_Time = 0; sockPoolN--; csi = si; got_csock = sp->sp_sock; break; } leaveCSC(sockCSC); if( got_csock < 0 ){ return -1; } if( rcode != RCODE_RECYC ) porting_dbg("--getConnSocket(%d)[%d]>>>%d[%d]", sockPoolN,sock,csi,got_csock); setfdowner(got_csock,getthreadid(),getthreadgid(0)); *rcsock = got_csock; syslog_ERROR("--getConnSocket([%d]%d)<-[%d]%d %.2f (%d)\n", sock,SocketOf(sock),got_csock,SocketOf(got_csock), Age,*pending); return 0; }