/* * When a client needs to be terminated then the file descriptors for * its input/output are simply closed. This leads to a graceful * degradation, but may take some time when the client is busy. A more * forcefull method is to kill the client thread, but this may leave * locks and semaphores in an undesirable state. * * The routine freeClient ends a single client session, but through side * effects of sharing IO descriptors, also its children. Conversely, a * child can not close a parent. */ void MCfreeClient(Client c) { c->mode = FINISHCLIENT; #ifdef MAL_CLIENT_DEBUG fprintf(stderr,"# Free client %d\n", c->idx); #endif MCexitClient(c); /* scope list and curprg can not be removed, because the client may * reside in a quit() command. Therefore the scopelist is re-used. */ c->scenario = NULL; if (c->prompt) GDKfree(c->prompt); c->prompt = NULL; c->promptlength = -1; if (c->errbuf) { /* no client threads in embedded mode */ #ifndef HAVE_EMBEDDED GDKsetbuf(0); #endif if (c->father == NULL) GDKfree(c->errbuf); c->errbuf = 0; } if (c->usermodule) freeModule(c->usermodule); c->usermodule = c->curmodule = 0; c->father = 0; c->login = c->lastcmd = 0; //c->active = 0; c->qtimeout = 0; c->stimeout = 0; c->user = oid_nil; if( c->username){ GDKfree(c->username); c->username = 0; } c->mythread = 0; if (c->glb) { freeStack(c->glb); c->glb = NULL; } if( c->error_row){ BBPrelease(c->error_row->batCacheid); BBPrelease(c->error_fld->batCacheid); BBPrelease(c->error_msg->batCacheid); BBPrelease(c->error_input->batCacheid); c->error_row = c->error_fld = c->error_msg = c->error_input = NULL; } if( c->wlc) freeMalBlk(c->wlc); c->wlc_kind = 0; c->wlc = NULL; MT_sema_destroy(&c->s); c->mode = MCshutdowninprogress()? BLOCKCLIENT: FREECLIENT; }
/* * Every client has a 'main' function to collect the statements. Once * the END instruction has been found, it is added to the symbol table * and a fresh container is being constructed. Note, this scheme makes * testing for recursive function calls a little more difficult. * Therefore, type checking should be performed afterwards. * * In interactive mode, the closing statement is never reached. The * 'main' procedure is typically cleaned between successive external * messages except for its variables, which are considerd global. This * storage container is re-used when during the previous call nothing * was added. At the end of the session we have to garbage collect the * BATs introduced. */ static void MSresetClientPrg(Client cntxt) { MalBlkPtr mb; InstrPtr p; cntxt->itrace = 0; /* turn off any debugging */ mb = cntxt->curprg->def; mb->typefixed = 0; mb->flowfixed = 0; mb->stop = 1; mb->errors = 0; p = mb->stmt[0]; p->gc = 0; p->retc = 1; p->argc = 1; /* remove any MAL history */ if (mb->history) { freeMalBlk(mb->history); mb->history = 0; } }
/* * This is a phtread started function. Here we start the client. We * need to initialize and allocate space for the global variables. * Thereafter it is up to the scenario interpreter to process input. */ void MSserveClient(void *dummy) { MalBlkPtr mb; Client c = (Client) dummy; str msg = 0; if (!isAdministrator(c) && MCinitClientThread(c) < 0) { MCcloseClient(c); return; } /* * A stack frame is initialized to keep track of global variables. * The scenarios are run until we finally close the last one. */ mb = c->curprg->def; if (c->glb == NULL) c->glb = newGlobalStack(MAXGLOBALS + mb->vsize); if (c->glb == NULL) { showException(c->fdout, MAL, "serveClient", MAL_MALLOC_FAIL); c->mode = FINISHCLIENT + 1; /* == RUNCLIENT */ } else { c->glb->stktop = mb->vtop; c->glb->blk = mb; } if (c->scenario == 0) msg = defaultScenario(c); if (msg) { showException(c->fdout, MAL, "serveClient", "could not initialize default scenario"); c->mode = FINISHCLIENT + 1; /* == RUNCLIENT */ GDKfree(msg); } else { do { do { runScenario(c); if (c->mode == FINISHCLIENT) break; resetScenario(c); } while (c->scenario && !GDKexiting()); } while (c->scenario && c->mode != FINISHCLIENT && !GDKexiting()); } /* pre announce our exiting: cleaning up may take a while and we * don't want to get killed during that time for fear of * deadlocks */ MT_exiting_thread(); /* * At this stage we should clean out the MAL block */ freeMalBlk(c->curprg->def); c->curprg->def = 0; if (c->mode > FINISHCLIENT) { if (isAdministrator(c) /* && moreClients(0)==0 */) { if (c->scenario) { exitScenario(c); } } } if (!isAdministrator(c)) MCcloseClient(c); }