diff --git a/src/frontend/misccoms.c b/src/frontend/misccoms.c index ef434ac4e..7328308b4 100644 --- a/src/frontend/misccoms.c +++ b/src/frontend/misccoms.c @@ -32,6 +32,10 @@ extern char history_file[]; extern char history_file[]; #endif +#ifdef SHARED_MODULE +extern void rem_controls(void); +#endif + extern IFsimulator SIMinfo; extern void spice_destroy_devices(void); /* FIXME need a better place */ static void byemesg(void); @@ -76,6 +80,8 @@ com_quit(wordlist *wl) cp_remvar("prompt"); } + rem_controls(); + /* Destroy CKT when quit. */ if (!ft_nutmeg) { while(ft_curckt) diff --git a/src/frontend/runcoms2.c b/src/frontend/runcoms2.c index b04fc06be..1d975c3c2 100644 --- a/src/frontend/runcoms2.c +++ b/src/frontend/runcoms2.c @@ -30,7 +30,9 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group extern void line_free_x(struct card *deck, bool recurse); extern INPmodel *modtab; -extern void com_mc_source(wordlist *wl); +#ifdef SHARED_MODULE +extern void exec_controls(wordlist *newcontrols); +#endif #define line_free(line, flag) \ do { \ @@ -176,6 +178,9 @@ com_rset(wordlist *wl) return; } com_remcirc(NULL); +#ifdef SHARED_MODULE + exec_controls(NULL); +#endif inp_source_recent(); #else struct variable *v, *next; diff --git a/src/sharedspice.c b/src/sharedspice.c index 35aceb27c..1932d7303 100644 --- a/src/sharedspice.c +++ b/src/sharedspice.c @@ -1,4 +1,4 @@ -/* Copyright 2013 Holger Vogt +/* Copyright 2013 - 2018 Holger Vogt * * Modified BSD license */ @@ -22,6 +22,25 @@ via a new thread. Delays may occur. */ #define low_latency +/************* About threads in sharedspice.c ************************* + If the calling (main) thread loads a circuit, the .control section + commands in the input file are executed immediately by the calling + thread after the ciruit has been parsed and loaded. + Command bg_run from the calling thread then immediately starts the + background thread (id. tid) that issues the 'run' command to + start the simulation in this thread. The main thread returns to the + caller. .control commands typically are executed prematurely before + bg_run has returned. + If the flag 'set controlswait' is given in the .control section, + all commands following are assembled in the wordlist 'shcontrols', + a new thread is started (id: tid2) and suspended immediately. Only + when the background thread tid (and thus the simulation) is ready, + the tid2 thread is released and the .control commands are executed. + Before a repeated 'bg_run' is given, or after a 'reset', the command + 'bg_ctrl' has to be sent by the caller to re-start and suspend the + thread tid2, using the still existing shcontrols. +*/ + /**********************************************************************/ /* Header files for C functions */ /**********************************************************************/ @@ -180,7 +199,8 @@ extern int SIMinit(IFfrontEnd *frontEnd, IFsimulator **simulator); extern wordlist *cp_varwl(struct variable *var); extern void create_circbyline(char *line); -void exec_controls(wordlist *controls); +void exec_controls(wordlist *shcontrols); +void rem_controls(void); /*The current run (to get variable names, etc)*/ static runDesc *cur_run; @@ -249,6 +269,7 @@ static SendInitEvtData* sendinitevt; static SendEvtData* sendevt; #endif static void* euserptr; +static wordlist *shcontrols; // thread IDs @@ -312,6 +333,8 @@ _cthread_run(void *controls) { wordlist *wl; #ifdef HAVE_LIBPTHREAD + if (!cont_condition) + printf("Prepared to start controls after bg_run has finished\n"); pthread_mutex_lock(&triggerMutex); while (!cont_condition) pthread_cond_wait(&cond, &triggerMutex); @@ -320,7 +343,7 @@ _cthread_run(void *controls) for (wl = controls; wl; wl = wl->wl_next) cp_evloop(wl->wl_word); - wl_free(controls); + #ifdef HAVE_LIBPTHREAD cont_condition = FALSE; #endif @@ -410,27 +433,43 @@ sighandler_sharedspice(int num) #endif /*THREADS*/ +/* create a suspended thread tid2 that is activated when bg_run has finished. + It executes the .control commands. If the arguemnt is NULL, the thread is + stated with the existing controls (e.g. for command 'reset'. */ void -exec_controls(wordlist *controls) +exec_controls(wordlist *newcontrols) { + if (newcontrols) { + if (shcontrols) + wl_free(shcontrols); + shcontrols = newcontrols; + } #ifdef THREADS #ifdef HAVE_LIBPTHREAD + cont_condition = FALSE; usleep(20000); /* wait a little */ - pthread_create(&tid2, NULL, (void * (*)(void *))_cthread_run, (void *)controls); + pthread_create(&tid2, NULL, (void * (*)(void *))_cthread_run, (void *)shcontrols); + pthread_detach(tid2); /* automatically release the memory after thread has finished */ #elif defined _MSC_VER || defined __MINGW32__ tid2 = (HANDLE)_beginthreadex(NULL, 0, (unsigned int(__stdcall *)(void *))_cthread_run, - (void*)controls, CREATE_SUSPENDED, NULL); + (void*)shcontrols, CREATE_SUSPENDED, NULL); #else - tid2 = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)_cthread_run, (void*)controls, + tid2 = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)_cthread_run, (void*)shcontrols, 0, NULL); #endif #else wordlist *wl; - for (wl = controls; wl; wl = wl->wl_next) + for (wl = shcontrols; wl; wl = wl->wl_next) cp_evloop(wl->wl_word); #endif } +/* free controls after 'quit' */ +void rem_controls(void) +{ + wl_free(shcontrols); +} + /* run a ngspice command */ static int @@ -446,7 +485,8 @@ runc(char* command) bool fl_bg = FALSE; command_id = threadid_self(); /* run task in background if command is preceeded by "bg_" */ - if (!cieq("bg_halt", command) && !cieq("bg_pstop", command) && ciprefix("bg_", command)) { + if (!cieq("bg_halt", command) && !cieq("bg_pstop", command) + && !cieq("bg_ctrl", command) && ciprefix("bg_", command)) { strncpy(buf, command+3, 1024); fl_bg = TRUE; } @@ -503,6 +543,7 @@ runc(char* command) string = copy(buf); /*as buf gets freed fairly quickly*/ #ifdef HAVE_LIBPTHREAD pthread_create(&tid, NULL, (void * (*)(void *))_thread_run, (void *)string); + pthread_detach(tid); #elif defined _MSC_VER || defined __MINGW32__ tid = (HANDLE)_beginthreadex(NULL, 0, (unsigned int (__stdcall *)(void *))_thread_run, (void*)string, 0, NULL); @@ -515,6 +556,13 @@ runc(char* command) if (!strcmp(buf, "bg_halt")) { signal(SIGINT, oldHandler); return _thread_stop(); + /* bg_ctrl prepare running the controls after bg_run */ + } else if (!strcmp(buf, "bg_ctrl")) { + if (shcontrols) + exec_controls(wl_copy(shcontrols)); + else + fprintf(stderr, "Warning: No .control commands available, bg_ctrl skipped\n"); + return 0; } else /* cannot do anything if ngspice is running in the bg*/ if (fl_running) {