void generic_exit_handler(void) { void (*signal_routine)(); boolean_t is_mupip, is_gtm; static int invoke_cnt = 0; /* how many times generic_exit_handler was invoked in the lifetime of this process */ is_gtm = IS_GTM_IMAGE; is_mupip = IS_MUPIP_IMAGE; exit_handler_active = TRUE; sys$setast(ENABLE); /* safer and doesn't hurt much */ if (is_tracing_on) turn_tracing_off(NULL); /* We expect generic_exit_handler to be invoked at most twice. Once by MUPIP STOP at which time we might have decided * to defer exiting (because of holding crit etc.) but after all those resources which prevented us from exiting have * been released, we should reinvoke generic_exit_handler once more and that invocation SHOULD EXIT. Assert this. */ assert(invoke_cnt < 2); DEBUG_ONLY(invoke_cnt++;) /* We can defer exit-handling if it was a forced-halt and we are in an AST or have crit in any region. * If we are in an AST when a fatal exception occurs we can neither defer exiting nor do normal exit-handling, * so we return immediately with the hope that the privileged exit-handler in GTMSECSHR, * secshr_db_clnup(ABNORMAL_TERMINATION) will do the necessary cleanup. * Note that even if we hold crit in any region when a non-deferrable exception occurs, we can still go ahead with * normal exit-handling chores. secshr_db_clnup(NORMAL_TERMINATION) (invoked below) will cleanup the crits for us. */ if (ERR_FORCEDHALT == exi_condition || 0 == exi_condition)
/* make sure that the journal file is available if appropriate */ uint4 jnl_ensure_open(void) { uint4 jnl_status; jnl_private_control *jpc; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; boolean_t first_open_of_jnl, need_to_open_jnl; int close_res; # if defined(VMS) static const gds_file_id file; uint4 status; # endif error_def(ERR_JNLFILOPN); csa = cs_addrs; csd = csa->hdr; assert(csa->now_crit); jpc = csa->jnl; assert(NULL != jpc); assert(JNL_ENABLED(csa->hdr)); /* The goal is to change the code below to do only one JNL_FILE_SWITCHED(jpc) check instead of the additional * (NOJNL == jpc->channel) check done below. The assert below ensures that the NOJNL check can indeed * be subsumed by the JNL_FILE_SWITCHED check (with the exception of the source-server which has a special case that * needs to be fixed in C9D02-002241). Over time, this has to be changed to one check. */ assert((NOJNL != jpc->channel) || JNL_FILE_SWITCHED(jpc) || is_src_server); need_to_open_jnl = FALSE; jnl_status = 0; if (NOJNL == jpc->channel) { # ifdef VMS if (NOJNL != jpc->old_channel) { if (lib$ast_in_prog()) /* called from wcs_wipchk_ast */ jnl_oper_user_ast(gv_cur_region); else { status = sys$setast(DISABLE); jnl_oper_user_ast(gv_cur_region); if (SS$_WASSET == status) ENABLE_AST; } } # endif need_to_open_jnl = TRUE; } else if (JNL_FILE_SWITCHED(jpc)) { /* The journal file has been changed "on the fly"; close the old one and open the new one */ VMS_ONLY(assert(FALSE);) /* everyone having older jnl open should have closed it at time of switch in VMS */ JNL_FD_CLOSE(jpc->channel, close_res); /* sets jpc->channel to NOJNL */ need_to_open_jnl = TRUE; }
/* **++ ** ROUTINE: sp_close ** ** FUNCTIONAL DESCRIPTION: ** ** Close down a subprocess. ** ** RETURNS: cond_value, longword (unsigned), write only, by value ** ** PROTOTYPE: ** ** sp_close(SPHANDLE *ctxpp) ** ** IMPLICIT INPUTS: None. ** ** IMPLICIT OUTPUTS: None. ** ** COMPLETION CODES: ** SS$_NORMAL: Normal successful completion. ** ** SIDE EFFECTS: None. ** **-- */ unsigned int sp_close (SPHANDLE *ctxpp) { SPHANDLE ctx; struct SPD *spd; unsigned int status; ctx = *ctxpp; /* ** Unlink the context block from our tracking queue */ status = sys$setast(0); queue_remove(ctx, &ctx); while (queue_remove(ctx->sendque.head, &spd)) free_spd(spd); if (status == SS$_WASSET) sys$setast(1); /* ** Delete the subprocess */ sys$forcex(&ctx->pid, 0, SS$_NORMAL); sys$delprc(&ctx->pid, 0); /* ** Wait till it actually dies */ sys$waitfr(ctx->termefn); /* ** Clean up and return */ lib$free_ef(&ctx->termefn); lib$free_ef(&ctx->inefn); lib$free_ef(&ctx->outefn); sys$dassgn(ctx->inchn); sys$dassgn(ctx->outchn); lib$free_vm(&ctx->bufsiz, &ctx->bufptr); lib$free_vm(&spb_size, &ctx); return SS$_NORMAL; } /* sp_close */
/* **++ ** ROUTINE: sp_send ** ** FUNCTIONAL DESCRIPTION: ** ** Queue up some data to be sent to the subprocess. ** ** RETURNS: cond_value, longword (unsigned), write only, by value ** ** PROTOTYPE: ** ** sp_send(SPHANDLE *ctxpp, struct dsc$descriptor *cmdstr); ** ** IMPLICIT INPUTS: None. ** ** IMPLICIT OUTPUTS: None. ** ** COMPLETION CODES: ** SS$_NORMAL: Normal successful completion. ** ** SIDE EFFECTS: None. ** **-- */ unsigned int sp_send (SPHANDLE *ctxpp, void *cmdstr) { SPHANDLE ctx; struct SPD *spd; unsigned int status, efstate; unsigned short cmdlen; char *cmdadr; ctx = *ctxpp; if (sys$readef(ctx->termefn, &efstate) != SS$_WASCLR) return SS$_NONEXPR; status = lib$analyze_sdesc(cmdstr, &cmdlen, &cmdadr); if (!OK(status)) return status; spd = get_spd(cmdlen); if (spd == 0) return SS$_INSFMEM; memcpy(spd->buf, cmdadr, cmdlen); status = sys$setast(0); queue_insert(spd, ctx->sendque.tail); if (status == SS$_WASSET) sys$setast(1); sys$dclast(try_to_send, ctx, 0); return SS$_NORMAL; } /* sp_send */
/* **++ ** ROUTINE: sp_open ** ** FUNCTIONAL DESCRIPTION: ** ** Spawns a subprocess, possibly passing it an initial command. ** ** RETURNS: cond_value, longword (unsigned), write only, by value ** ** PROTOTYPE: ** ** sp_open(SPHANDLE *ctxpp, struct dsc$descriptor *inicmd, ** unsigned int (*rcvast)(void *), void *rcvastprm); ** ** IMPLICIT INPUTS: None. ** ** IMPLICIT OUTPUTS: None. ** ** COMPLETION CODES: ** SS$_NORMAL: Normal successful completion. ** ** SIDE EFFECTS: None. ** **-- */ unsigned int sp_open (SPHANDLE *ctxpp, void *inicmd, unsigned int (*rcvast)(void *), void *rcvastprm) { SPHANDLE ctx; unsigned int dvi_devnam = DVI$_DEVNAM, dvi_devbufsiz = DVI$_DEVBUFSIZ; unsigned int spawn_flags = CLI$M_NOWAIT|CLI$M_NOKEYPAD; unsigned int status; struct dsc$descriptor inbox, outbox; status = lib$get_vm(&spb_size, &ctx); if (!OK(status)) return status; /* ** Assign the SPHANDLE address for the caller immediately to avoid timing issues with ** WRTATTN AST that passes the ctx as rcvastprm (which sp_once does). */ *ctxpp = ctx; ctx->sendque.head = ctx->sendque.tail = &ctx->sendque; ctx->ok_to_send = 0; /* ** Create the mailboxes we'll be using for I/O with the subprocess */ status = sys$crembx(0, &ctx->inchn, 1024, 1024, 0xff00, 0, 0, 0); if (!OK(status)) { lib$free_vm(&spb_size, &ctx); return status; } status = sys$crembx(0, &ctx->outchn, 1024, 1024, 0xff00, 0, 0, 0); if (!OK(status)) { sys$dassgn(ctx->inchn); lib$free_vm(&spb_size, &ctx); return status; } /* ** Now that they're created, let's find out what they're called so we ** can tell LIB$SPAWN */ INIT_DYNDESC(inbox); INIT_DYNDESC(outbox); lib$getdvi(&dvi_devnam, &ctx->inchn, 0, 0, &inbox); lib$getdvi(&dvi_devnam, &ctx->outchn, 0, 0, &outbox); lib$getdvi(&dvi_devbufsiz, &ctx->outchn, 0, &ctx->bufsiz); /* ** Create the output buffer for the subprocess. */ status = lib$get_vm(&ctx->bufsiz, &ctx->bufptr); if (!OK(status)) { sys$dassgn(ctx->outchn); sys$dassgn(ctx->inchn); str$free1_dx(&inbox); str$free1_dx(&outbox); lib$free_vm(&spb_size, &ctx); return status; } /* ** Set the "receive AST" routine to be invoked by SP_WRTATTN_AST */ ctx->rcvast = rcvast; ctx->astprm = rcvastprm; sys$qiow(0, ctx->outchn, IO$_SETMODE|IO$M_WRTATTN, 0, 0, 0, sp_wrtattn_ast, ctx, 0, 0, 0, 0); sys$qiow(0, ctx->inchn, IO$_SETMODE|IO$M_READATTN, 0, 0, 0, sp_readattn_ast, ctx, 0, 0, 0, 0); /* ** Get us a termination event flag */ status = lib$get_ef(&ctx->termefn); if (OK(status)) lib$get_ef(&ctx->inefn); if (OK(status)) lib$get_ef(&ctx->outefn); if (!OK(status)) { sys$dassgn(ctx->outchn); sys$dassgn(ctx->inchn); str$free1_dx(&inbox); str$free1_dx(&outbox); lib$free_vm(&ctx->bufsiz, &ctx->bufptr); lib$free_vm(&spb_size, &ctx); return status; } /* ** Now create the subprocess */ status = lib$spawn(inicmd, &inbox, &outbox, &spawn_flags, 0, &ctx->pid, 0, &ctx->termefn); if (!OK(status)) { lib$free_ef(&ctx->termefn); lib$free_ef(&ctx->outefn); lib$free_ef(&ctx->inefn); sys$dassgn(ctx->outchn); sys$dassgn(ctx->inchn); str$free1_dx(&inbox); str$free1_dx(&outbox); lib$free_vm(&ctx->bufsiz, &ctx->bufptr); lib$free_vm(&spb_size, &ctx); return status; } /* ** Set up the exit handler, if we haven't done so already */ status = sys$setast(0); if (!exh_declared) { sys$dclexh(&exhblk); exh_declared = 1; } if (status == SS$_WASSET) sys$setast(1); /* ** Save the SPB in our private queue */ queue_insert(ctx, spque.tail); /* ** Clean up and return */ str$free1_dx(&inbox); str$free1_dx(&outbox); return SS$_NORMAL; } /* sp_open */
/* ** Name: CScp_resume - Resume (a thread in) a process ** ** Description: ** This routine resumes the indicated thread in the indicated process. ** ** If the indicated process is this process, then this is a simple ** CSresume operation. If the indicated process is another process, then ** that process must be notified that it should CSresume the indicated ** thread. ** ** Inputs: ** cpid pointer to CS_CPID with ** .pid - the indicated process ** .sid - the indicated session ** .iosb - a thread-safe IOSB ** .data - where we'll place a pointer ** to the CPchan written to. ** ** Outputs: ** None ** ** Returns: ** void ** ** History: ** Summer, 1992 (bryanp) ** Working on the new portable logging and locking system. ** 9-oct-1992 (bryanp) ** Use global IOSB, not stack IOSB, so that when QIO completes ** some time from now it will not overwrite arbitrary stack stuff. ** 19-oct-1992 (bryanp) ** CSresume expects to be called at AST level. Oblige it by invoking it ** via sys$dclast(). ** 20-oct-1992 (bryanp) ** Back out the DCLAST change; CSresume can now be called at normal ** level. ** 14-dec-1992 (bryanp) ** ERsend() calls should be ERlog() calls. ** 29-sep-1993 (walt) ** Get an event flag number from lib$get_ef rather than use event flag ** zero in the sys$qio call. ** 18-oct-1993 (rachael) ** Call lib$signal(SS$_DEBUG) only when compiled with xDEBUG flag. ** 16-Nov-1998 (jenjo02) ** Prototype changed to pass CS_CPID * instead of PID, SID. ** 08-Nov-2007 (jonj) ** Write with IO$M_NOW and IO$M_READERCHECK, check for dead reader ** process (NOREADER), mark this PID/channel as dead for subsequent ** resumers to ignore. IO$M_NOW does not wait for the reader to ** read. ** 04-Apr-2008 (jonj) ** Embed IOSB in CS_CPID and reinstate lib$get_ef() to assure ** thread-safeness. ** Disable/reenable ASTs to prevent seen duplicate reads on the ** other end. ** Supply cpres_mbx_write_complete() AST to check IOSB status ** for NOREADER. */ void CScp_resume( CS_CPID *cpid ) { i4 vms_status; CS_CP_WAKEUP_MSG wakeup_msg; i4 mbox_chan; char msg_buf[100]; CL_ERR_DESC local_sys_err; CP_CHANNEL *CPchan; II_VMS_EF_NUMBER efn; i4 ReenableASTs; if (cpid->pid == Cs_srv_block.cs_pid) { CSresume(cpid->sid); } else { /* Disable AST delivery */ ReenableASTs = (sys$setast(0) == SS$_WASSET); /* Initialize to success */ vms_status = SS$_NORMAL; if ( cpres_mbx_assign(cpid->pid, &CPchan) == OK ) { /* If reader is not alive, do nothing */ if ( CPchan->state == CPchanIsAlive ) { /* The SID of the session to resume */ wakeup_msg.wakeup_sid = cpid->sid; /* horda03 - Fill in details to help track Cross-Process ** ACCVIO problem. */ wakeup_msg.wakeup_pid = cpid->pid; wakeup_msg.from_pid = Cs_srv_block.cs_pid; /* If from AST, "from_sid" is meaningless */ if ( (wakeup_msg.sender_in_ast = lib$ast_in_prog()) ) wakeup_msg.from_sid = 0; else wakeup_msg.from_sid = (CS_SID)Cs_srv_block.cs_current; /* ** Plunk message, don't wait for reader to read it. ** ** Use IOSB embedded in CS_CPID, pass CS_CPID* to ** AST completion. */ /* Set CPchan in the CS_CPID for AST's use */ cpid->data = (PTR)CPchan; vms_status = sys$qio(EFN$C_ENF, CPchan->chan, IO$_WRITEVBLK | IO$M_NOW | IO$M_READERCHECK, &cpid->iosb, cpres_mbx_write_complete, cpid, &wakeup_msg, sizeof(wakeup_msg), 0, 0, 0, 0); if ( vms_status != SS$_NORMAL ) { STprintf(msg_buf, "[%x.%x] Error (%x) queueing write to %x on channel %d", wakeup_msg.from_pid, wakeup_msg.from_sid, vms_status, CPchan->pid, CPchan->chan); ERlog(msg_buf, STlength(msg_buf), &local_sys_err); } } } else { STprintf(msg_buf, "Unable to assign channel to %x", cpid->pid); ERlog(msg_buf, STlength(msg_buf), &local_sys_err); STprintf(msg_buf, "Ignoring error in assigning mailbox for PID %x", cpid->pid); ERlog(msg_buf, STlength(msg_buf), &local_sys_err); /* ** The process we were going to send this message to will probably ** "hang", which at least allows some sort of diagnosis. Killing ** ourselves at this point is less useful, since it tends to crash ** the entire installation. */ } if ( vms_status != SS$_NORMAL ) { STprintf(msg_buf, "CScp_resume QIO to %x failed with status %x", cpid->pid, vms_status); ERlog(msg_buf, STlength(msg_buf), &local_sys_err); #ifdef xDEBUG lib$signal(SS$_DEBUG); #endif PCexit(FAIL); } if ( ReenableASTs ) sys$setast(1); } return; }
STATUS disp_prompt(char *buffer,char *achar,char *range) { STATUS ret_val = OK ; char caracter ; char *legal = NULL ; char termBuffer [255] ; #ifdef NT_GENERIC COORD coordinate; int numchars, i; char tempchar [80]; #endif if (achar == NULL) { #ifndef NT_GENERIC STprintf(termBuffer,ERx("%s%s%s%s%s"),REG_CHAR,ATTR_OFF, PROMPT_POS,DEL_EOL,buffer); TEwrite(termBuffer,STlength(termBuffer)); TEflush(); #else SetConsoleActiveScreenBuffer(hTEconsole); coordinate.X=0; coordinate.Y=22; SetConsoleCursorPosition(hTEconsole, coordinate); WriteConsole(hTEconsole, buffer, strlen(buffer), &numchars, NULL); coordinate.X=strlen(buffer); coordinate.Y=22; SetConsoleCursorPosition(hTEconsole, coordinate); strcpy (tempchar, " "); for (i=2; i<=(80-strlen(buffer)); i++) strcat (tempchar, " "); WriteConsole(hTEconsole, tempchar, strlen(tempchar), &numchars, NULL); #endif } else { #ifndef NT_GENERIC STprintf(termBuffer,ERx("%s%s%s%s%s[ %s ]%s "),REG_CHAR,ATTR_OFF, PROMPT_POS,DEL_EOL,REV_VIDEO,buffer,ATTR_OFF); TEwrite(termBuffer,STlength(termBuffer)); TEflush(); #else SetConsoleActiveScreenBuffer(hTEconsole); coordinate.X=0; coordinate.Y=22; SetConsoleCursorPosition(hTEconsole, coordinate); SetConsoleTextAttribute(hTEconsole, FOREGROUND_BLUE|BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY); STpolycat(3, ERx("[ "), buffer, ERx(" ]"), &termBuffer); WriteConsole(hTEconsole, termBuffer, strlen(termBuffer), &numchars, NULL); coordinate.X=strlen(termBuffer); coordinate.Y=22; SetConsoleCursorPosition(hTEconsole, coordinate); strcpy (tempchar, " "); for (i=2; i<=(80-strlen(termBuffer)); i++) strcat (tempchar, " "); SetConsoleTextAttribute(hTEconsole, FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY|BACKGROUND_BLUE); WriteConsole(hTEconsole, tempchar, strlen(tempchar), &numchars, NULL); #endif TEinflush(); for (;;) { EXinterrupt(EX_OFF); #ifdef VMS sys$setast(0); #endif caracter = TEget(0); EXinterrupt(EX_ON); #ifdef VMS sys$setast(1); #endif if (range == NULL || (legal = STindex(range,&caracter,0)) != NULL) break; else { TEput(BELL); TEflush(); } } *achar = caracter; } return (ret_val); }