Exemple #1
0
/*
** Name: clean_channels		- garbage collect channels to dead processes
**
** Description:
**	Called whenever we're about to assign a channel to a new process.
**	Before assigning the new channel, we compact the existing channels
**	array by reclaiming any channels to old, dead processes.
**
** Inputs:
**	None
**
** Outputs:
**	None
**
** Returns:
**	STATUS
**
** History:
**	23-may-1994 (bryanp)
**	    Created as part of resolving B60736.
**	08-Nov-2007 (jonj)
**	    Check that PID is already known to be dead.
*/
static STATUS
clean_channels(void)
{
    i4		i;
    i4		j;
    i4		s;
    char	msg_buf[250];
    CL_ERR_DESC	local_sys_err;
    CP_CHANNEL	*CPchan;

    for (i = 0; i < cpres_num_channels_assigned; i++)
    {
	CPchan = &cpres_channels[i];

	if ( CPchan->state == CPchanIsDead || !(PCis_alive(CPchan->pid)) )
	{
	    TRdisplay("%@ cscpres: garbage collect channel to %x\n",
			CPchan->pid);
	    /*
	    ** What cleanup is required:
	    **	    1) cancel any outstanding I/O on this channel
	    **	    2) deassign the channel
	    **	    3) shift all the other channels down one in the array
	    **		(ugh, but we don't do this very often)
	    **	    4) back 'i' off by one so that we don't skip any
	    **		channels in the loop
	    **	    5) back cpres_num_channels_assigned off by one to
	    **		reflect the cleaned-up channel.
	    */

	    /*
	    ** If already known to be dead, we've cancelled/deassigned
	    ** already.
	    */
	    if ( CPchan->state != CPchanIsDead )
	    {
		CPchan->state = CPchanIsDead;

		s = sys$cancel(CPchan->chan);
		if ( s != SS$_NORMAL )
		{
		    STprintf(msg_buf, "Error %x cancelling channel %x",
				s, CPchan->chan);
		    ERlog(msg_buf, STlength(msg_buf), &local_sys_err);
		    TRdisplay("%s\n", msg_buf);
		    return (FAIL);
		}
		s = sys$dassgn(CPchan->chan);
		if ( s != SS$_NORMAL )
		{
		    STprintf(msg_buf, "Error %x releasing channel %x",
				s, CPchan->chan);
		    ERlog(msg_buf, STlength(msg_buf), &local_sys_err);
		    TRdisplay("%s\n", msg_buf);
		    return (FAIL);
		}
	    }

	    for (j = i + 1; j < cpres_num_channels_assigned; j++)
	    {
		cpres_channels[j - 1].pid  = cpres_channels[j].pid;
		cpres_channels[j - 1].state  = cpres_channels[j].state;
		cpres_channels[j - 1].chan = cpres_channels[j].chan;
	    }

	    i--;
	    cpres_num_channels_assigned--;
	}
    }
    return (OK);
}
Exemple #2
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;
}
Exemple #3
0
/*
** Name: cpres_mbx_assign	- get channel to target process, assign if need
**
** Description:
**	This subroutine looks up the channel to the target process. If we have
**	not yet assigned a channel to the target process, then we assign one
**	and remember it. The resulting channel is returned.
**
** Inputs:
**	pid			- the target process's pid
**
** Outputs:
**	CPchan			- Pointer to CP_CHANNEL of process.
**
** Returns:
**	OK, !OK
**
** History:
**	Summer, 1992 (bryanp)
**	    Working on the new portable logging and locking system.
**	14-dec-1992 (bryanp)
**	    ERsend() calls should be ERlog() calls.
**	23-may-1994 (bryanp) B60736
**	    Added clean_channels() routine and called it periodically to
**		ensure that a process doesn't accumulate channels to dead
**		processes indefinitely.
**	02-May-2007 (jonj)
**	    Use of CSp/v_semaphore is prohibited from within an AST as
**	    it corrupts cs_inkernel and the ready queues. Use CS_ASET/ACLR
**	    instead.
**	08-Nov-2007 (jonj)
**	    Changed function to return pointer to CP_CHANNEL instead
**	    of channel number, initialize IsDead to FALSE.
**	04-Apr-2008 (jonj)
**	    Remove disabling of ASTs here, caller will have already done
**	    that.
**	    Check if PID has been deadified by write AST; if so,
**	    cancel any pending I/O, deassign channel, mark CPchan
**	    as unusuable (dead).
*/
static STATUS
cpres_mbx_assign(PID pid, CP_CHANNEL **CPchan)
{
    i4	    	i;
    struct	dsc$descriptor_s    name_desc;
    i4		vms_status;
    char	mbx_name[100];
    char	*inst_id;
    char	msg_buf[250];
    STATUS	status;
    STATUS	cl_status;
    PID		my_pid;
    CL_ERR_DESC	local_sys_err;
    CP_CHANNEL	*NewCPchan;

    /* Loop until we get the sem */
    while ( !CS_TAS(&cpres_channels_sem) );

    for (i = 0; i < cpres_num_channels_assigned; i++)
    {
	if (cpres_channels[i].pid == pid)
	{
	    /*
	    ** If write completion AST noticed that
	    ** the reading process has died or gone away,
	    ** mark its PID as dead, cancel any leftover
	    ** I/O and deassign the channel.
	    */
	    if ( cpres_channels[i].state == CPchanIsDying )
	    {
		sys$cancel(cpres_channels[i].chan);
		sys$dassgn(cpres_channels[i].chan);

		cpres_channels[i].state = CPchanIsDead;

		STprintf(msg_buf, "%x PID %x on channel %d is dead, deassigned",
				Cs_srv_block.cs_pid,
				cpres_channels[i].pid, 
				cpres_channels[i].chan);
		ERlog(msg_buf, STlength(msg_buf), &local_sys_err);
	    }

	    /* Return channel, dead or alive */
	    *CPchan = &cpres_channels[i];
	    CS_ACLR(&cpres_channels_sem);
	    return (OK);
	}
    }

    if ( status = clean_channels() )
    {
	CS_ACLR(&cpres_channels_sem);
	return (status);
    }

    if ( cpres_num_channels_assigned <
		    (sizeof(cpres_channels)/sizeof(CP_CHANNEL)) )
    {
	/*
	** New process, and room remains in the channel array, so assign a
	** channel.
	*/
	NewCPchan = &cpres_channels[cpres_num_channels_assigned];

	NMgtAt("II_INSTALLATION", &inst_id);
	if (inst_id && *inst_id)
	    STprintf(mbx_name, "II_CPRES_%s_%x", inst_id, (i4)pid);
	else
	    STprintf(mbx_name, "II_CPRES_%x", (i4)pid);

	name_desc.dsc$a_pointer = mbx_name;
	name_desc.dsc$w_length = STlength(mbx_name);
	name_desc.dsc$b_dtype = DSC$K_DTYPE_T;
	name_desc.dsc$b_class = DSC$K_CLASS_S;

	vms_status = sys$assign(&name_desc,	/* devname */
			    &NewCPchan->chan,	/* channel */
			    0, 			/* access_mode */
			    0,			/* mbxnam */
			    AGN$M_WRITEONLY);	/* flags */

	if ( vms_status == SS$_NORMAL )
	{
	    NewCPchan->pid = pid;
	    NewCPchan->state = CPchanIsAlive;
	    *CPchan = NewCPchan;
	    cpres_num_channels_assigned++;
	    CS_ACLR(&cpres_channels_sem);
	    return (OK);
	}
	else
	{
	    STprintf(msg_buf,
		    "%x cpres_mbx_assign: Error (%x) assigning channel to %s",
		    Cs_srv_block.cs_pid, vms_status, mbx_name);
	    ERlog(msg_buf, STlength(msg_buf), &local_sys_err);
	}
    }
    else
    {
	/*
	** No room left in channels array. One possibility is to go through
	** the array looking for assigned channels to mailboxes of dead
	** processes and clean those up.
	*/
	STcopy("PANIC! No room left in channels array!", msg_buf);
	ERlog(msg_buf, STlength(msg_buf), &local_sys_err);
    }

    CS_ACLR(&cpres_channels_sem);
    return (FAIL);
}
Exemple #4
0
STATUS
ERsend(i4 flag, char *message, i4 msg_length, CL_ERR_DESC *err_code)
{
# ifdef NT_GENERIC
    static bool		er_init = FALSE;
    static bool		is_w95 = FALSE;
# else /* !NT_GENERIC */
    static int		er_ifi = -2;
    static int          ar_ifi = -2;
# endif /* !NT_GENERIC */
    STATUS		status;
    char                tmp_buf[ER_MAX_LEN];
    char*               logmsg = message;

    /*	Check for bad paramters. */

    CL_CLEAR_ERR( err_code );

    if ((message == 0 || msg_length == 0) && flag != ER_AUDIT_MSG)
        return (ER_BADPARAM);

    if ((flag != ER_ERROR_MSG) && (flag != ER_AUDIT_MSG) &&
        ( flag != ER_OPER_MSG))
        return (ER_BADPARAM);

# ifndef NT_GENERIC
    if (flag & ER_AUDIT_MSG)
    {
        key_t msg_key;
        char  *ipc_number;
        struct
        {
            long    mtype;
            char    mtext[ER_MAX_LEN];
        }   msg;

        if (ar_ifi == -2)
        {
            NMgtAt("II_AUDIT_IPC", &ipc_number);
            if (ipc_number && ipc_number[0])
            {
                CVal(ipc_number, &msg_key);
                ar_ifi = msgget(msg_key, 0);
                if (ar_ifi == -1)
                {
                    SETCLERR(err_code, 0, ER_open);
                    return(ER_NO_AUDIT);
                }
            }
            else
            {
                SETCLERR(err_code, 0, ER_open);
                return(ER_NO_AUDIT);
            }

        }
 
        /*  Handle special case to connect only but not send message. */
 
        if (msg_length == 0 && message == 0)
                return (OK);

        MEcopy(message, msg_length, msg.mtext);
        msg.mtype = 1;
        if (msgsnd(ar_ifi, &msg, msg_length, 0))
        {
            SETCLERR(err_code, 0, ER_open);
            return(ER_BADSEND);
        }
        return (OK);
    }
    else
# endif /* ! NT_GENERIC */
    if (flag & ER_OPER_MSG)
    {
        char    hostname[GL_MAXNAME];
        STATUS  status;
 
        message[msg_length] = EOS;
        TRdisplay("ER Operator:\"%s\"\n",message);
	if (!ERsysinit)
	    ERinitsyslog();
# ifdef NT_GENERIC
        {
        wchar_t *wmessage = NULL;

        /*
        ** Update the ReportEvent to report information in the event log.
        */
        if ( ReportEvent( EventLog,
                        (WORD) EVENTLOG_INFORMATION_TYPE,
                        (WORD) 0,             /* event category */
                        (DWORD) I_ING_INFO,   /* event identifier */
                        (PSID) NULL,
                        (WORD) 1,             /* number of strings */
                        (DWORD) 0,
                        &message,
                        NULL ) == FALSE)   
                status = GetLastError();
	if ( !er_init )
	{
	    char		VersionString[256];
	    FUNC_EXTERN BOOL	GVosvers(char *OSVersionString);

	    GVosvers(VersionString);
	    is_w95 = ( STstrindex(VersionString, "Microsoft Windows 9",
				  0, FALSE) != NULL ) ? TRUE : FALSE;

	    if ( !is_w95 ) /* netapi32 only on NT */
	    {
		HANDLE hDll;
                if ((hDll = LoadLibrary(TEXT("netapi32.dll"))) != NULL)
                {
                    pNetMessageNameAdd = 
		     (NET_API_STATUS (*)(LPCWSTR,LPCWSTR))
		     GetProcAddress(hDll, TEXT("NetMessageNameAdd"));
                    pNetMessageNameDel = 
		     (NET_API_STATUS (*)(LPCWSTR,LPCWSTR))
		     GetProcAddress(hDll, TEXT("NetMessageNameDel"));
                    pNetMessageBufferSend = 
		      (NET_API_STATUS (*)(LPCWSTR,LPCWSTR,LPCWSTR,LPBYTE,DWORD))
		      GetProcAddress(hDll, TEXT("NetMessageBufferSend"));
		}
		/* if any problem, pretend we don't support it */
		if ( pNetMessageNameAdd == NULL ||
		     pNetMessageNameDel == NULL ||
		     pNetMessageBufferSend == NULL )
		    is_w95 = TRUE;
	    }
	}

	if ( !is_w95 )
	{
	    /*
	    ** Now, send the message to the server console,
	    ** putting up a message box (if the messenger service
	    ** is running.  Everything must be in Unicode.
	    */

	    if ( whostname[0] == 0 )
	    {
		unsigned int len = sizeof(hostname);
                /* 
		** get the hostname in Unicode format for use 
		** by messenger service 
		*/
                GetComputerName( (char *)hostname, &len );
		MultiByteToWideChar( GetACP(), 0,
				     hostname, sizeof(hostname),
				     whostname, sizeof(whostname) );
	    }
            /* initialize the messenger service */
            status = (*pNetMessageNameAdd)( whostname, msgname );
            if ( status != NERR_Success )
	        status = GetLastError();

	    /* Allocate a buffer for the Unicode */
	    wmessage = (wchar_t *) MEreqmem( 0, msg_length * sizeof(wchar_t), 
				             TRUE, &status );
	    if ( wmessage )
	    {
	        /* copy the message to the Unicode buffer */
		MultiByteToWideChar( GetACP(), 0,
				     message, msg_length,
				     wmessage, msg_length * sizeof(wchar_t) );
                status = (*pNetMessageBufferSend)( whostname, 
					       msgname, 
					       NULL, 
				               (LPBYTE) wmessage, 
					       msg_length*sizeof(wchar_t) );
                if ( status != NERR_Success )
	            status = GetLastError();
	        MEfree( (PTR)wmessage );
	    }

            /* re-initialize the messenger service */
            status = (*pNetMessageNameDel)( whostname, msgname );
            if ( status != NERR_Success )
	        status = GetLastError();

	}
	}
# elif defined(OS_THREADS_USED) && defined(any_aix)
	syslog_r( LOG_ALERT|LOG_ERR, message );
# else
	syslog( LOG_ALERT|LOG_ERR, message );
# endif /* NT_GENERIC */
    }

    if (flag & ER_OPER_MSG)
    {
        i4 msglen = 0;
	char* host = PMhost();

        MEfill( ER_MAX_LEN, 0, tmp_buf );

        /*
        ** Format the message string for the event log.  As the source is
        ** not known a fixed string of INGSYSLOG is used.
        */
        TRformat( NULL, 0, tmp_buf, ER_MAX_LEN - 1,
            "%8.8t::[INGSYSLOG         , 00000000]: %@ ", STlength(host),
            host );
        msglen = STlength(tmp_buf);
        STcat( tmp_buf, message );  /* append original message */
        msg_length += msglen;
        logmsg = tmp_buf;
    }
    status = ERlog( logmsg, msg_length, err_code );
    return( status );
}