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)
Beispiel #2
0
/* 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;
	}
Beispiel #3
0
/*
**++
**  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 */
Beispiel #4
0
/*
**++
**  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 */
Beispiel #5
0
/*
**++
**  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 */
Beispiel #6
0
/*
** 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;
}
Beispiel #7
0
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);
}