📄 gdk_utils.mx
字号:
doGDKaddbuf(const char *prefix, const char *message, size_t messagelen, const char *suffix){ char *buf = GDKerrbuf; THRerrorcount[THRgettid()]++; if (buf) { char *dst = buf + strlen(buf); size_t maxlen = GDKMAXERRLEN - (dst - buf) - 1; if (prefix && *prefix && dst < buf + GDKMAXERRLEN) { size_t preflen; strncpy(dst, prefix, maxlen); dst[maxlen] = '\0'; preflen = strlen(dst); maxlen -= preflen; dst += preflen; } if (maxlen > messagelen) maxlen = messagelen; strncpy(dst, message, maxlen); dst += maxlen; if (suffix && *suffix && dst < buf + GDKMAXERRLEN) { size_t sufflen; maxlen = buf + GDKMAXERRLEN - dst - 1; strncpy(dst, suffix, maxlen); dst[maxlen] = '\0'; sufflen = strlen(dst); maxlen -= sufflen; dst += sufflen; } *dst = '\0'; } else if (!GDKsilent) { /* construct format string because the format string must start with ! */ char format[32]; snprintf(format, sizeof(format), "%s%%.*s%s", prefix ? prefix : "", suffix ? suffix : ""); THRprintf(GDKout, format, (int) messagelen, message); }}/* print an error or warning message, making sure the message ends in a newline, and also that every line in the message (if there are multiple), starts with an exclamation point. One of the problems complicating this whole issue is that each line should be printed using a single call to THRprintf, and moreover, the format string should start with a "!". This is because THRprintf adds a "#" to the start of the printed text if the format string doesn't start with "!". Another problem is that we're religious about bounds checking. It would probably also not be quite as bad if we could write in the message buffer. */voidGDKaddbuf(const char *message){ const char *p, *q; char prefix[16]; if (message == NULL || *message == '\0') /* empty message, nothing to do */ return; p = message; strcpy(prefix, "!"); /* default prefix */ while (p && *p) { if (*p == '!') { size_t preflen; /* remember last ! prefix (e.g. "!ERROR: ") for any subsequent lines that start without ! */ message = p; /* A prefix consists of a ! immediately followed by some text, followed by a : and a space. Anything else results in no prefix being remembered */ while (*++p && *p != ':' && *p != '\n' && *p != ' ') ; if (*p == ':' && *++p == ' ') { /* found prefix, now remember it */ preflen = (size_t) (p - message) + 1; if (preflen > sizeof(prefix) - 1) preflen = sizeof(prefix) - 1; strncpy(prefix, message, preflen); prefix[preflen] = 0; } else { /* there is a ! but no proper prefix */ strcpy(prefix, "!"); preflen = 1; } p = message + preflen; } /* find end of line */ q = strchr(p, '\n'); if (q) { /* print line including newline */ q++; doGDKaddbuf(prefix, p, (size_t) (q - p), ""); } else { /* no newline at end of buffer: print all the rest and add a newline */ doGDKaddbuf(prefix, p, strlen(p), "\n"); /* we're done since there were no more newlines */ break; } p = q; }}/*VARARGS*/ intGDKwarning(const char *format, ...){ char message[GDKMAXERRLEN]; size_t len = strlen(GDKWARNING); va_list ap; if (!strncmp(format,GDKWARNING,len)) { len = 0; } else { strcpy(message, GDKWARNING); } va_start(ap, format); vsnprintf(message + len, GDKMAXERRLEN - (len + 2), format, ap); va_end(ap); GDKaddbuf(message); return 0;}/*VARARGS*/ intGDKerror(const char *format, ...){ char message[GDKMAXERRLEN]; size_t len = strlen(GDKERROR); va_list ap; if (!strncmp(format,GDKERROR,len)) { len = 0; } else { strcpy(message, GDKERROR); } va_start(ap, format); vsnprintf(message + len, GDKMAXERRLEN - (len + 2), format, ap); va_end(ap); GDKaddbuf(message); return 0;}/*VARARGS*/ intGDKsyserror(const char *format, ...){ char message[GDKMAXERRLEN]; size_t len = strlen(GDKERROR); int err = errno; va_list ap; if (!strncmp(format,GDKERROR,len)) { len = 0; } else { strcpy(message, GDKERROR); } va_start(ap, format); vsnprintf(message + len, GDKMAXERRLEN - (len + 2), format, ap); va_end(ap); if (err > 0 && err < 1024) { char *osmsg = strerror(err); size_t len1 = strlen(message); size_t len2 = len1 + strlen(GDKMESSAGE); size_t len3 = len2 + strlen(osmsg); if (len3 + 2 < GDKMAXERRLEN) { strcpy(message + len1, GDKMESSAGE); strcpy(message + len2, osmsg); message[len3] = '\n'; message[len3 + 1] = 0; } } GDKaddbuf(message); errno = 0; return err;}/*VARARGS*/ intGDKfatal(const char *format, ...){ char message[GDKMAXERRLEN]; size_t len = strlen(GDKFATAL); va_list ap; FILE *fd = stderr; GDKdebug |= 16;#ifndef NATIVE_WIN32 BATSIGinit();#endif if (!strncmp(format,GDKFATAL,len)) { len = 0; } else { strcpy(message, GDKFATAL); } va_start(ap, format); vsnprintf(message + len, GDKMAXERRLEN - (len + 2), format, ap); va_end(ap); if (GDKsilent == 0) { fputs(message, fd); fputs("\n", fd); fflush(fd); }@-Real errors should be saved in the lock file for post-crash inspection.@c if (GDKstopped) { fflush(stdout); MT_exit_thread(1); /* exit(1); */ } else { GDKlog(message);#ifdef COREDUMP abort();#else GDKexit(1); }#endif return -1;}intGDKerrorCount(void){ return THRerrorcount[THRgettid()];}@- TimersThe following relative timers are available for inspection.Note that they may consume recognizable overhead.@clngGDKusec(void){#ifdef HAVE_GETTIMEOFDAY struct timeval tp; gettimeofday(&tp, NULL); return ((lng) (tp.tv_sec - GDKtime_startsec)) * LL_CONSTANT(1000000) + (lng) tp.tv_usec;#else#ifdef HAVE_FTIME struct timeb tb; ftime(&tb); return ((lng) (tb.time - GDKtime_startsec)) * LL_CONSTANT(1000000) + ((lng) tb.millitm) * LL_CONSTANT(1000);#endif#endif}intGDKms(void){#ifdef HAVE_GETTIMEOFDAY struct timeval tp; gettimeofday(&tp, NULL); return (tp.tv_sec - GDKtime_startsec) * 1000 + tp.tv_usec / 1000;#else#ifdef HAVE_FTIME struct timeb tb; ftime(&tb); return (int) ((tb.time - GDKtime_startsec) * 1000 + tb.millitm);#endif#endif}@}@+ Logical Thread managementAll semaphores used by the application should be mentioned here.They are initialized during system initialization.@-The first action upon thread creation is to add it to the poolof known threads. This should be done by the thread itself.Subsequently, the thread descriptor can be obtained using @%THRget@.Note that the users should have gained exclusive access already.A new entry is initialized automatically when not found.Its file descriptors are the same as for the server and should besubsequently reset.@{@cint GDKnrofthreads;ThreadRec GDKthreads[THREADS];void *THRdata[THREADDATA] = { 0 };ThreadTHRget(int tid){ assert(0 < tid && tid <= THREADS); return (GDKthreads + tid - 1);}static INLINE size_tTHRsp(void){ int l = 0; size_t sp = (size_t) (&l); return sp;}static ThreadGDK_find_thread(MT_Id pid){ Thread t, s; for (t = GDKthreads, s = t + THREADS; t < s; t++) { if (t->pid && t->pid == pid) { return t; } } return NULL;}ThreadTHRnew(MT_Id pid, str name){ int tid = 0; Thread t; Thread s = GDK_find_thread(pid); gdk_set_lock(GDKthreadLock, "THRnew"); if (s == NULL) { for (s = GDKthreads, t = s + THREADS; s < t; s++) { if (s->pid == pid) { gdk_unset_lock(GDKthreadLock, "THRnew"); GDKwarning("THRnew:duplicate %d\n", pid); return s; } } for (s = GDKthreads, t = s + THREADS; s < t; s++) { if (s->pid == 0) { break; } } if (s == t) { gdk_unset_lock(GDKthreadLock, "THRnew"); GDKfatal("THRnew: too many threads\n"); } tid = s->tid; memset((char *) s, 0, sizeof(*s)); s->pid = pid; s->tid = tid; s->data[1] = THRdata[1]; s->data[0] = THRdata[0]; s->cleanup = NULL; s->sp = THRsp(); PARDEBUG THRprintf(GDKout, "#%x " SZFMT " sp = " SZFMT "\n", s->tid, (size_t) pid, s->sp); PARDEBUG THRprintf(GDKout, "#nrofthreads %d\n", GDKnrofthreads); GDKnrofthreads++; MT_alloc_register(&tid, 1, (char) ('0' + ((int) tid) - 1)); } s->name = name; gdk_unset_lock(GDKthreadLock, "THRnew"); return s;}voidTHRdel(Thread t){ if (t < GDKthreads || t > GDKthreads + THREADS) { GDKfatal("THRdel: illegal call\n"); } gdk_set_lock(GDKthreadLock, "THRdel"); if (t->cleanup) { (*t->cleanup) (t); } PARDEBUG THRprintf(GDKout, "#pid = " SZFMT ", disconnected, %d left\n", (size_t) t->pid, GDKnrofthreads); t->pid = 0; GDKnrofthreads--; gdk_unset_lock(GDKthreadLock, "THRdel");}@-The easiest way to terminate a thread is to identify its nameA zero is returned when the thread could not be found@cintTHRexit(str nme){ Thread t; Thread s; for (t = GDKthreads, s = t + THREADS; t < s; t++) { if (t->pid && t->name && strcmp(t->name, nme) == 0) { MT_Id victim = t->pid; THRdel(t); MT_kill_thread(victim); return 1; } } return 0;}intTHRcnt(void){ return GDKnrofthreads;}intTHRhighwater(void){ size_t c = THRsp(); Thread s = GDK_find_thread(MT_getpid()); size_t diff = (c < s->sp) ? s->sp - c : c - s->sp; if (diff > (THREAD_STACK_SIZE - 2048)) { return 1; } return 0;}@-I/O is organized per thread, because users may gain access throughthe network.The code below should be improved to gain speed.@cintTHRinit(void){ int i = 0; THRdata[0] = (void *) file_wastream(stdout, "stdout"); THRdata[1] = (void *) file_rastream(stdin, "stdin"); for (i = 0; i < THREADS; i++) { GDKthreads[i].tid = i + 1; } return 0;}voidTHRsetdata(int n, ptr val){ Thread s = GDK_find_thread(MT_getpid()); if (s) s->data[n] = val;}void *THRgetdata(int n){ Thread s = GDK_find_thread(MT_getpid()); return (s ? s->data[n] : THRdata[n]);}intTHRgettid(void){ Thread s = GDK_find_thread(MT_getpid()); return s ? s->tid : 1;}static char THRprintbuf[BUFSIZ];/*VARARGS*/ intTHRprintf(stream *s, const char *format, ...){ str bf = THRprintbuf, p = 0; size_t bfsz = BUFSIZ; int n = 0; ptrdiff_t m = 0; char c; va_list ap; if (!s) return -1; gdk_set_lock(MT_system_lock, "THRprintf"); if (*format != '!') { c = '#'; } else { c = '!'; format++; }@= THRprintf_va_vsnprintf p = bf; *p++ = c; if (GDKdebug&1) { sprintf(p, "%02d ", THRgettid()); while (*p) p++; } m = p-bf; va_start(ap, format); n = vsnprintf(p, bfsz-m, format, ap); va_end(ap);@c @:THRprintf_va_vsnprintf@ if (n < 0) goto cleanup; if ((size_t) n >= bfsz - m) { bfsz = m + n + 1; /* precisely what is needed */ if (bf != THRprintbuf) free(bf); bf = (str) malloc(bfsz); assert(bf != NULL); @:THRprintf_va_vsnprintf@ } p += n; n = 0; if (stream_write(s, bf, p - bf, 1) != 1) n = -1;cleanup: if (bf != THRprintbuf) free(bf); gdk_unset_lock(MT_system_lock, "THRprintf"); return n;}@h#endif /* _GDK_UTILS_H_ */@}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -