/* * Forking is a relatively cheap way to create a new client. The new * client record shares the IO descriptors. To avoid interference, we * limit children to only produce output by closing the input-side. * * If the father itself is a temporary client, let the new child depend * on the grandfather. */ Client MCforkClient(Client father) { Client son = NULL; str prompt; if (father == NULL) return NULL; if (father->father != NULL) father = father->father; if((prompt = GDKstrdup(father->prompt)) == NULL) return NULL; if ((son = MCinitClient(father->user, father->fdin, father->fdout))) { son->fdin = NULL; son->fdout = father->fdout; son->bak = NULL; son->yycur = 0; son->father = father; son->scenario = father->scenario; if (son->prompt) GDKfree(son->prompt); son->prompt = prompt; son->promptlength = strlen(prompt); /* reuse the scopes wherever possible */ if (son->usermodule == 0) { son->usermodule = userModule(); if(son->usermodule == 0) { MCcloseClient(son); return NULL; } } } else { GDKfree(prompt); } return son; }
/* * 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); }