diff --git a/src/sbbs3/js_request.c b/src/sbbs3/js_request.c new file mode 100644 index 0000000000000000000000000000000000000000..2c270cb234ee1dc05f7615bdaf0e5ca363d0b999 --- /dev/null +++ b/src/sbbs3/js_request.c @@ -0,0 +1,274 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef __unix__ + #define XP_UNIX +#else + #define XP_PC + #define XP_WIN +#endif + +#include <jsapi.h> +#include "threadwrap.h" +#include "js_request.h" + +#ifdef DEBUG_JS_REQUESTS + +#define DEBUG +#define JS_THREADSAFE +#include <jscntxt.h> + +enum last_request_type { + LAST_REQUEST_TYPE_NONE + ,LAST_REQUEST_TYPE_BEGIN + ,LAST_REQUEST_TYPE_END + ,LAST_REQUEST_TYPE_SUSPEND + ,LAST_REQUEST_TYPE_RESUME +}; +static const char *type_names[5]={"None", "BeginRequest", "EndRequest", "SuspendRequest", "ResumeRequest"}; + +struct request_log { + JSContext* cx; + enum last_request_type type; + const char* file; + unsigned long line; + struct request_log* next; + struct request_log* prev; +}; + +static struct request_log* first_request; +static int initialized=0; +static pthread_mutex_t req_mutex; +static char str[1024]; + +static void logstr(void) +{ + FILE *f; + + if((f=fopen("../data/logs/JS_RequestErrors.log", "a"))!=NULL) { + fputs(str, f); + fclose(f); + } + else { + fputs(str, stderr); + } +} + +static struct request_log *match_request(JSContext *cx) +{ + struct request_log *ent; + + for(ent=first_request; ent != NULL; ent=ent->next) { + if(ent->cx==cx) + return(ent); + } + + ent=malloc(sizeof(struct request_log)); + if(ent != NULL) { + memset(ent, 0, sizeof(struct request_log)); + ent->cx=cx; + ent->type=LAST_REQUEST_TYPE_NONE; + ent->prev=NULL; + ent->next=first_request; + if(first_request != NULL) { + first_request->prev=ent; + } + first_request=ent; + return(ent); + } + return(NULL); +} + +static void initialize_request(void) +{ + pthread_mutex_init(&req_mutex, NULL); + initialized=1; +} + +void js_debug_beginrequest(JSContext *cx, const char *file, unsigned long line) +{ + struct request_log *req; + + if(!initialized) + initialize_request(); + pthread_mutex_lock(&req_mutex); + req=match_request(cx); + if(req==NULL) { + strcpy(str,"Missing req in Begin\n"); + logstr(); + return; + } + switch(req->type) { + case LAST_REQUEST_TYPE_NONE: + case LAST_REQUEST_TYPE_END: + break; + case LAST_REQUEST_TYPE_BEGIN: + case LAST_REQUEST_TYPE_SUSPEND: + case LAST_REQUEST_TYPE_RESUME: + sprintf(str,"Begin after %s from %s:%u at %s:%u\n",type_names[req->type],req->file,req->line,file,line); + logstr(); + break; + } + switch(cx->requestDepth) { + case 0: + break; + case 1: + default: + sprintf(str,"depth=%u at Begin after %s from %s:%u at %s:%u\n",cx->requestDepth,type_names[req->type],req->file,req->line,file,line); + logstr(); + break; + } + + req->type=LAST_REQUEST_TYPE_BEGIN; + req->file=file; + req->line=line; + JS_BeginRequest(cx); + pthread_mutex_unlock(&req_mutex); +} + +void js_debug_endrequest(JSContext *cx, const char *file, unsigned long line) +{ + struct request_log *req; + + if(!initialized) + initialize_request(); + pthread_mutex_lock(&req_mutex); + req=match_request(cx); + if(req==NULL) { + strcpy(str,"Missing req in End\n"); + logstr(); + return; + } + switch(req->type) { + case LAST_REQUEST_TYPE_BEGIN: + if(req->file) { + if(strcmp(req->file, file) != 0 || line < req->line) { + sprintf(str,"Suspicious End after %s from %s:%u at %s:%u\n",type_names[req->type],req->file,req->line,file,line); + } + break; + } + case LAST_REQUEST_TYPE_RESUME: + break; + case LAST_REQUEST_TYPE_NONE: + case LAST_REQUEST_TYPE_END: + case LAST_REQUEST_TYPE_SUSPEND: + sprintf(str,"End after %s from %s:%u at %s:%u\n",type_names[req->type],req->file,req->line,file,line); + logstr(); + break; + } + switch(cx->requestDepth) { + case 0: + default: + sprintf(str,"depth=%u at End after %s from %s:%u at %s:%u\n",cx->requestDepth,type_names[req->type],req->file,req->line,file,line); + logstr(); + break; + case 1: + break; + } + + req->type=LAST_REQUEST_TYPE_END; + req->file=file; + req->line=line; + JS_EndRequest(cx); + if(req->prev != NULL) + req->prev->next=req->next; + if(req->next != NULL) + req->next->prev=req->prev; + if(first_request==req) { + if(req->prev != NULL) + first_request=req->prev; + else + first_request=req->next; + } + free(req); + pthread_mutex_unlock(&req_mutex); +} + +jsrefcount js_debug_suspendrequest(JSContext *cx, const char *file, unsigned long line) +{ + struct request_log *req; + jsrefcount ret; + + if(!initialized) + initialize_request(); + pthread_mutex_lock(&req_mutex); + req=match_request(cx); + if(req==NULL) { + strcpy(str,"Missing req in Suspend\n"); + logstr(); + return; + } + switch(req->type) { + case LAST_REQUEST_TYPE_BEGIN: + case LAST_REQUEST_TYPE_RESUME: + break; + case LAST_REQUEST_TYPE_NONE: + if(req->file==NULL) /* Assumed to be a provided request */ + break; + case LAST_REQUEST_TYPE_END: + case LAST_REQUEST_TYPE_SUSPEND: + sprintf(str,"Suspend after %s from %s:%u at %s:%u\n",type_names[req->type],req->file,req->line,file,line); + logstr(); + break; + } + switch(cx->requestDepth) { + case 0: + default: + sprintf(str,"depth=%u at Suspend after %s from %s:%u at %s:%u\n",cx->requestDepth,type_names[req->type],req->file,req->line,file,line); + logstr(); + break; + case 1: + break; + } + + req->type=LAST_REQUEST_TYPE_SUSPEND; + req->file=file; + req->line=line; + ret=JS_SuspendRequest(cx); + pthread_mutex_unlock(&req_mutex); + return(ret); +} + +void js_debug_resumerequest(JSContext *cx, jsrefcount rc, const char *file, unsigned long line) +{ + struct request_log *req; + + if(!initialized) + initialize_request(); + pthread_mutex_lock(&req_mutex); + req=match_request(cx); + if(req==NULL) { + strcpy(str,"Missing req in Resume\n"); + logstr(); + return; + } + switch(req->type) { + case LAST_REQUEST_TYPE_SUSPEND: + break; + case LAST_REQUEST_TYPE_NONE: + case LAST_REQUEST_TYPE_END: + case LAST_REQUEST_TYPE_BEGIN: + case LAST_REQUEST_TYPE_RESUME: + sprintf(str,"Resume after %s from %s:%u at %s:%u\n",type_names[req->type],req->file,req->line,file,line); + logstr(); + break; + } + switch(cx->requestDepth) { + case 1: + default: + sprintf(str,"depth=%u at Suspend after %s from %s:%u at %s:%u\n",cx->requestDepth,type_names[req->type],req->file,req->line,file,line); + logstr(); + break; + case 0: + break; + } + + req->type=LAST_REQUEST_TYPE_RESUME; + req->file=file; + req->line=line; + JS_ResumeRequest(cx, rc); + pthread_mutex_unlock(&req_mutex); +} + +#endif diff --git a/src/sbbs3/js_request.h b/src/sbbs3/js_request.h new file mode 100644 index 0000000000000000000000000000000000000000..b7b74eafc1d33e623bf5f7b7a766e61f14201f01 --- /dev/null +++ b/src/sbbs3/js_request.h @@ -0,0 +1,29 @@ +#ifndef _JS_REQUEST_H_ +#define _JS_REQUEST_H_ + +//#define DEBUG_JS_REQUESTS + +#ifdef DEBUG_JS_REQUESTS +#ifdef __cplusplus +extern "C" { +#endif +void js_debug_beginrequest(JSContext *cx, const char *file, unsigned long line); +void js_debug_endrequest(JSContext *cx, const char *file, unsigned long line); +jsrefcount js_debug_suspendrequest(JSContext *cx, const char *file, unsigned long line); +void js_debug_resumerequest(JSContext *cx, jsrefcount rc, const char *file, unsigned long line); +#ifdef __cplusplus +} +#endif + +#define JS_BEGINREQUEST(cx) js_debug_beginrequest(cx, __FILE__, __LINE__) +#define JS_ENDREQUEST(cx) js_debug_endrequest(cx, __FILE__, __LINE__) +#define JS_SUSPENDREQUEST(cx) js_debug_suspendrequest(cx, __FILE__, __LINE__) +#define JS_RESUMEREQUEST(cx, rf) js_debug_resumerequest(cx, rf, __FILE__, __LINE__) +#else +#define JS_BEGINREQUEST(cx) JS_BeginRequest(cx); +#define JS_ENDREQUEST(cx) JS_EndRequest(cx); +#define JS_SUSPENDREQUEST(cx) JS_SuspendRequest(cx); +#define JS_RESUMEREQUEST(cx, rf) JS_ResumeRequest(cx, rf); +#endif + +#endif diff --git a/src/sbbs3/objects.mk b/src/sbbs3/objects.mk index ece91339802bfe7b386389bdbd36384a3100888d..7fba0c22efa1056ae08590cb44ac7513e39d5ace 100644 --- a/src/sbbs3/objects.mk +++ b/src/sbbs3/objects.mk @@ -50,6 +50,7 @@ OBJS = $(MTOBJODIR)$(DIRSEP)ansiterm$(OFILE) \ $(MTOBJODIR)$(DIRSEP)js_msg_area$(OFILE)\ $(MTOBJODIR)$(DIRSEP)js_msgbase$(OFILE)\ $(MTOBJODIR)$(DIRSEP)js_queue$(OFILE)\ + $(MTOBJODIR)$(DIRSEP)js_request$(OFILE)\ $(MTOBJODIR)$(DIRSEP)js_rtpool$(OFILE)\ $(MTOBJODIR)$(DIRSEP)js_server$(OFILE)\ $(MTOBJODIR)$(DIRSEP)js_socket$(OFILE)\