static int SelWaitFor( lua_State *L ){ unsigned int nsup=0; /* Number of supervised object (used as index in the table) */ int nre; /* Number of received event */ struct pollfd ufds[WAITMAXFD]; int maxarg = lua_gettop(L); for(int j=1; j <= lua_gettop(L); j++){ /* Stacks SelTimer arguments */ if(nsup == WAITMAXFD){ lua_pushnil(L); lua_pushstring(L, "Exhausting number of waiting FD, please increase WAITMAXFD"); return 2; } void *r; if((r = checkUData(L, j, "SelTimer"))){ /* We got a SelTimer */ ufds[nsup].fd = ((struct SelTimer *)r)->fd; ufds[nsup++].events = POLLIN; } else if(( r = checkUData(L, j, "SelEvent"))){ ufds[nsup].fd = ((struct SelEvent *)r)->fd; ufds[nsup++].events = POLLIN; } else if(( r = checkUData(L, j, LUA_FILEHANDLE))){ /* We got a file */ ufds[nsup].fd = fileno(*((FILE **)r)); ufds[nsup++].events = POLLIN; } else { lua_pushnil(L); lua_pushstring(L, "Unsupported type for WaitFor()"); return 2; } } /* at least, we have to supervise SharedStuffs' todo list */ if(nsup == WAITMAXFD){ lua_pushnil(L); lua_pushstring(L, "Exhausting number of waiting FD, please increase WAITMAXFD"); return 2; } ufds[nsup].fd = SharedStuffs.tlfd; /* Push todo list's fd */ ufds[nsup].events = POLLIN; nsup++; /* Waiting */ if((nre = poll(ufds, nsup, -1)) == -1){ /* Waiting for events */ lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2; } for(int i=0; i<nsup; i++){ if( ufds[i].revents ){ /* This one has data */ if( ufds[i].fd == SharedStuffs.tlfd ){ /* Todo list's evenfd */ uint64_t v; if(read( ufds[i].fd, &v, sizeof( uint64_t )) != sizeof( uint64_t )) perror("read(eventfd)"); lua_pushcfunction(L, &handleToDoList); /* Push the function to handle the todo list */ } else for(int j=1; j <= maxarg; j++){ void *r; if((r=checkUData(L, j, "SelTimer"))){ if(ufds[i].fd == ((struct SelTimer *)r)->fd){ uint64_t v; if(read( ufds[i].fd, &v, sizeof( uint64_t )) != sizeof( uint64_t )) perror("read(timerfd)"); if(((struct SelTimer *)r)->ifunc != LUA_REFNIL){ /* Immediate function to be executed */ lua_rawgeti( L, LUA_REGISTRYINDEX, ((struct SelTimer *)r)->ifunc); if(lua_pcall( L, 0, 0, 0 )){ /* Call the trigger without arg */ fprintf(stderr, "*E* (SelTimer ifunc) %s\n", lua_tostring(L, -1)); lua_pop(L, 1); /* pop error message from the stack */ lua_pop(L, 1); /* pop NIL from the stack */ } } if(((struct SelTimer *)r)->task != LUA_REFNIL){ /* Function to be pushed in todo list */ if( pushtask( ((struct SelTimer *)r)->task, ((struct SelTimer *)r)->once ) ){ lua_pushstring(L, "Waiting task list exhausted : enlarge SO_TASKSSTACK_LEN"); lua_error(L); exit(EXIT_FAILURE); /* Code never reached */ } } } } else if((r=checkUData(L, j, "SelEvent"))){ if(ufds[i].fd == ((struct SelEvent *)r)->fd){ if( pushtask( ((struct SelEvent *)r)->func, false) ){ lua_pushstring(L, "Waiting task list exhausted : enlarge SO_TASKSSTACK_LEN"); lua_error(L); exit(EXIT_FAILURE); /* Code never reached */ } } } else if(( r = checkUData(L, j, LUA_FILEHANDLE))){ if(ufds[i].fd == fileno(*((FILE **)r))) lua_pushvalue(L, j); } } } } return lua_gettop(L)-maxarg; /* Number of stuffs to proceed */ }
/* CALLNEWTASK -- Called from CALL instruction to push and setup a new task * structure. If find a known ltask with given name create a new task on * control stack, set up newtask and defaults for the pseudofiles. * Pseudofiles may be effected by other instructions before it gets to exec. * Make sure we have a pfile list; either try to read it if task is * supposed to have a real one or manufacture the beginnings of one if it * isn't and set PF_FAKE. New task runs with a copy of the pfile if it * wasn't fake. Guard against making more than one copy. Also, don't dup * the cl's params to maintain the meaning of "firstask". Things like mode, * logfile and abbreviations should be global and permanent. * Special case for package names essentially runs a cl but with a new curpack, * the only real semantic intent of "running" a package. * This lets a package name given as a command appear to change the current * package and yet remain interactive. Since it really is a new task, state * saving and restoring on error will work right and we also achieve an * ability to have multiple package defn's in a script ltask. * Any parameter references will refer to the cl's also. */ void callnewtask ( char *name ) { /* x1 and x2 are just place holders to call breakout(). */ char *x1, *pk, *t, *x2; struct ltask *ltp; int flags, ltflags; if (cldebug) eprintf ("callnewtask: name=%s, currentask=%x\n", name, currentask); /* Save current dictionary and stack pointers. they get restored when * the new task dies normally and the current task is to continue. * save pc when get to the EXEC instruction so it continues from there. */ currentask->t_topos = topos; /* save these two just in case */ currentask->t_basos = basos; /* something is left on the stk */ currentask->t_topcs = topcs; /* save before adding newtask */ currentask->t_topd = topd; /* save before adding pfile */ currentask->t_curpack = curpack;/* save in case changing to a new one*/ c_envmark (¤task->t_envp);/* save env stack pointer */ currentask->t_pno = 0; /* set only if task defines pkg */ newtask = pushtask(); flags = 0; /* Search for the command to run. A leading '$' signifies that * execution is to be time but is not part of the name. Set ltp * and newtask->t_pfp depending on whether we are running a task or * a package. */ if (*name == '$') { flags |= T_TIMEIT; name++; } breakout (name, &x1, &pk, &t, &x2); ltp = cmdsrch (pk, t); if (ltp->lt_flags & LT_CL) { /* Change curpack if LT_PACCL. (cmdsrch() set lt_pkp). Just * changing packages; use cl's ltask and pfile. Push a new cl() * on the control stack, with the T_PKGCL and T_CL flags set. */ if (ltp->lt_flags & LT_PACCL) { flags |= T_PKGCL; curpack = ltp->lt_pkp; } else if (ltp->lt_flags & LT_CLEOF) flags |= T_CLEOF; ltp = firstask->t_ltp; newtask->t_pfp = firstask->t_pfp; /* Initialize the lexical analyzer (necessary to recognize BOL). */ lexinit(); } else { if (ltp->lt_flags & LT_PFILE) { register struct pfile *pfp; /* This task has a real pfile. read in if not already in * core. Copy if not already one and not just cl. */ newtask->t_pfp = NULL; if ((pfp = pfilefind (ltp)) == NULL) pfp = pfileload (ltp); if (!(pfp->pf_flags & PF_COPY) && ltp != firstask->t_ltp) pfp = pfilecopy (pfp); newtask->t_pfp = pfp; /* Also load any pset files associated with the main pfile. * These are linked into a list with the main pfile at the * head of the list, pointed to by the task descriptor. */ if (pfp->pf_flags & PF_PSETREF) { register struct param *pp; struct operand o; char *pset; for (pp = pfp->pf_pp; pp != NULL; pp = pp->p_np) { if (!(pp->p_type & PT_PSET)) continue; o = pp->p_valo; if (opundef(&o) || *(pset = o.o_val.v_s) == EOS) pset = pp->p_name; pfp = pfp->pf_npset = pfilecopy (pfilesrch (pset)); pfp->pf_psetp = pp; } } } else { /* This task does not have a real pfile so start a fake one. */ newtask->t_pfp = newpfile (ltp); newtask->t_pfp->pf_flags = PF_FAKE; } } newtask->t_pfp->pf_n = 0; /* init number of command line args */ newtask->t_ltp = ltp; newtask->t_pid = -1; /* gets set if do a real exec */ newtask->t_stdin = currentask->t_stdin; /* inherit files */ newtask->t_stdout = currentask->t_stdout; newtask->t_stderr = currentask->t_stderr; newtask->t_stdgraph = currentask->t_stdgraph; newtask->t_stdimage = currentask->t_stdimage; newtask->t_stdplot = currentask->t_stdplot; /* Init i/o redirection for a foreign task. */ newtask->ft_in = newtask->ft_out = newtask->ft_err = NULL; /* Set up flags describing the kind of task we are about to run. the * absence of any of these flags will imply a genuine executable task. * the flags in t_flags are more of a convenience than anything since * later tests could use the same tests used here. */ ltflags = ltp->lt_flags; if (ltflags & LT_PSET) { flags = (T_SCRIPT|T_PSET); } else if (ltflags & LT_SCRIPT) { newtask->t_scriptln = 0; flags = T_SCRIPT; } else if (ltflags & LT_FOREIGN) { flags = T_BUILTIN | T_FOREIGN; /* a type of builtin */ } else if (ltflags & LT_BUILTIN) { flags = T_BUILTIN; } else if (ltflags & LT_CL) { /* Or, not assign: preserve T_PKGCL and T_CLEOF flags if set. */ flags |= T_CL; } if (ltflags & LT_STDINB) flags |= T_STDINB; if (ltflags & LT_STDOUTB) flags |= T_STDOUTB; newtask->t_flags = flags; }
static void sighandler(){ if( sigfunc != LUA_REFNIL ) pushtask( sigfunc, true ); }
/* LOGIN -- Hand-craft the first cl process. Push the first task to become * currentask, set up clpackage at pachead and set cl as its first ltask. * Add the builtin function ltasks. Run the startup file as the stdin of cl. * If any of this fails, we die. */ static void login (char *cmd) { register struct task *tp; register char *ip, *op; struct ltask *ltp; struct operand o; char *loginfile = LOGINFILE; char alt_loginfile[SZ_PATHNAME]; char clstartup[SZ_PATHNAME]; char clprocess[SZ_PATHNAME]; char *arglist; strcpy (clstartup, HOSTLIB); strcat (clstartup, CLSTARTUP); strcpy (clprocess, CLDIR); strcat (clprocess, CLPROCESS); tp = firstask = currentask = pushtask(); tp->t_in = tp->t_stdin = stdin; tp->t_out = tp->t_stdout = stdout; tp->t_stderr = stderr; tp->t_stdgraph = fdopen (STDGRAPH, "w"); tp->t_stdimage = fdopen (STDIMAGE, "w"); tp->t_stdplot = fdopen (STDPLOT, "w"); tp->t_pid = -1; tp->t_flags |= (T_INTERACTIVE|T_CL); /* Make root package. Avoid use of newpac() since pointers are not * yet set right. */ pachead = topd; curpack = (struct package *) memneed (PACKAGESIZ); curpack->pk_name = comdstr (ROOTPACKAGE); curpack->pk_ltp = NULL; curpack->pk_pfp = NULL; curpack->pk_npk = NULL; curpack->pk_flags = 0; /* Make first ltask. */ ltp = newltask (curpack, "cl", clprocess, (struct ltask *) NULL); tp->t_ltp = ltp; ltp->lt_flags |= (LT_PFILE|LT_CL); tp->t_pfp = pfileload (ltp); /* call newpfile(), read cl.par */ tp->t_pfp->pf_npf = NULL; setclmodes (tp); /* uses cl's params */ setbuiltins (curpack); /* add more ltasks off clpackage*/ /* Define the second package, the "clpackage", and make it the * current package (default package at startup). Tasks subsequently * defined by the startup script will get put in clpackage. */ curpack = newpac (CLPACKAGE, "bin$"); /* Compile code that will run the startup script then, if it exists * in the current directory, a login.cl script. We need to do as * much by hand here as the forever loop in main would have if this * code came from calling yyparse(). */ if (c_access (clstartup,0,0) == NO) cl_error (E_FERR, "Cannot find startup file `%s'", clstartup); currentask->t_bascode = 0; pc = 0; o.o_type = OT_STRING; o.o_val.v_s = clstartup; compile (CALL, "cl"); compile (PUSHCONST, &o); compile (REDIRIN); compile (EXEC); compile (FIXLANGUAGE); /* The following is to permit error recovery in the event that an * error occurs while reading the user's LOGIN.CL file. */ validerrenv = 1; if (setjmp (errenv)) { eprintf ("Error while reading login.cl file"); eprintf (" - may need to rebuild with mkiraf\n"); eprintf ("Fatal startup error. CL dies.\n"); clexit(); } ninterrupts = 0; if (setjmp (jumpcom)) onerr(); /* Nondestructively decompose the host command line into the startup * filename and/or the argument string. */ if (strncmp (cmd, "-f", 2) == 0) { for (ip=cmd+2; *ip && isspace(*ip); ip++) ; for (op=alt_loginfile; *ip && ! isspace(*ip); *op++ = *ip++) ; *op = EOS; for ( ; *ip && isspace(*ip); ip++) ; arglist = ip; } else { *alt_loginfile = EOS; arglist = cmd; } /* Copy any user supplied host command line arguments into the * CL parameter $args to use in the startup script (for instance). */ o.o_type = OT_STRING; strcpy (o.o_val.v_s, arglist); compile (PUSHCONST, &o); compile (ASSIGN, "args"); if (alt_loginfile[0]) { if (c_access (alt_loginfile,0,0) == NO) printf ("Warning: script file %s not found\n", alt_loginfile); else { o.o_val.v_s = alt_loginfile; compile (CALL, "cl"); compile (PUSHCONST, &o); compile (REDIRIN); compile (EXEC); } } else if (c_access (loginfile,0,0) == NO) { char *home = envget ("HOME"); char global[SZ_LINE]; memset (global, 0, SZ_LINE); sprintf (global, "%s/.iraf/login.cl", home); if (c_access (global, 0, 0) == YES) { o.o_val.v_s = global; compile (CALL, "cl"); compile (PUSHCONST, &o); compile (REDIRIN); compile (EXEC); } else { printf ("Warning: no login.cl found in login directory\n"); } } else { o.o_val.v_s = loginfile; compile (CALL, "cl"); compile (PUSHCONST, &o); compile (REDIRIN); compile (EXEC); } compile (END); topos = basos = pc - 1; pc = 0; run(); /* returns after doing the first EXEC */ /* Add nothing here that will effect the dictionary or the stacks. */ if (cldebug) printf ("topd, pachead, parhead: %u, %u, %u\n", topd, pachead, parhead); }