New deadlock check at proc.c.

New exit checks (stop IPC).
This commit is contained in:
Jorrit Herder 2005-10-12 15:08:23 +00:00
parent 5a9dec8bd2
commit b16a88692a
4 changed files with 78 additions and 23 deletions

View file

@ -25,5 +25,6 @@
#define CHECK_PTR 0x0B /* 1 0 1 1 : validate message buffer */
#define CHECK_DST 0x05 /* 0 1 0 1 : validate message destination */
#define CHECK_SRC 0x02 /* 0 0 1 0 : validate message source */
#define CHECK_DEADLOCK 0x03 /* 0 0 1 1 : check for deadlock */
#endif /* IPC_H */

View file

@ -46,15 +46,16 @@
* interrupts to prevent race conditions.
*/
FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dst,
message *m_ptr, unsigned flags) );
message *m_ptr, unsigned flags));
FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, int src,
message *m_ptr, unsigned flags) );
FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dst) );
FORWARD _PROTOTYPE( void enqueue, (struct proc *rp) );
FORWARD _PROTOTYPE( void dequeue, (struct proc *rp) );
FORWARD _PROTOTYPE( void sched, (struct proc *rp, int *queue, int *front) );
FORWARD _PROTOTYPE( void pick_proc, (void) );
message *m_ptr, unsigned flags));
FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dst));
FORWARD _PROTOTYPE( int deadlock, (int function,
register struct proc *caller, int src_dst));
FORWARD _PROTOTYPE( void enqueue, (struct proc *rp));
FORWARD _PROTOTYPE( void dequeue, (struct proc *rp));
FORWARD _PROTOTYPE( void sched, (struct proc *rp, int *queue, int *front));
FORWARD _PROTOTYPE( void pick_proc, (void));
#define BuildMess(m_ptr, src, dst_ptr) \
(m_ptr)->m_source = (src); \
@ -99,6 +100,7 @@ message *m_ptr; /* pointer to message in the caller's space */
int function = call_nr & SYSCALL_FUNC; /* get system call function */
unsigned flags = call_nr & SYSCALL_FLAGS; /* get flags */
int mask_entry; /* bit to check in send mask */
int group_size; /* used for deadlock check */
int result; /* the system call's result */
vir_clicks vlo, vhi; /* virtual clicks containing message to send */
@ -150,12 +152,21 @@ message *m_ptr; /* pointer to message in the caller's space */
*/
if (function & CHECK_DST) {
if (! get_sys_bit(priv(caller_ptr)->s_ipc_to, nr_to_id(src_dst))) {
kprintf("sys_call: ipc mask denied %d sending to %d\n",
proc_nr(caller_ptr), src_dst);
kprintf("sys_call: ipc mask denied trap %d from %d to %d\n",
function, proc_nr(caller_ptr), src_dst);
return(ECALLDENIED); /* call denied by ipc mask */
}
}
/* Check for a possible deadlock for blocking SEND(REC) and RECEIVE. */
if (function & CHECK_DEADLOCK) {
if (group_size = deadlock(function, caller_ptr, src_dst)) {
kprintf("sys_call: trap %d from %d to %d deadlocked, group size %d\n",
function, proc_nr(caller_ptr), src_dst, group_size);
return(ELOCKED);
}
}
/* Now check if the call is known and try to perform the request. The only
* system calls that exist in MINIX are sending and receiving messages.
* - SENDREC: combines SEND and RECEIVE in a single system call
@ -194,6 +205,56 @@ message *m_ptr; /* pointer to message in the caller's space */
return(result);
}
/*===========================================================================*
* deadlock *
*===========================================================================*/
PRIVATE int deadlock(function, cp, src_dst)
int function; /* trap number */
register struct proc *cp; /* pointer to caller */
register int src_dst; /* src or dst process */
{
/* Check for deadlock. This can happen if 'caller_ptr' and 'src_dst' have
* a cyclic dependency of blocking send and receive calls. The only cyclic
* depency that is not fatal is if the caller and target directly SEND(REC)
* and RECEIVE to each other. If a deadlock is found, the group size is
* returned. Otherwise zero is returned.
*/
register struct proc *xp; /* process pointer */
int group_size = 1; /* start with only caller */
int trap_flags;
while (src_dst != ANY) { /* check while process nr */
xp = proc_addr(src_dst); /* follow chain of processes */
group_size ++; /* extra process in group */
/* Check whether the last process in the chain has a depency. If it
* has not, the cycle cannot be closed and we are done.
*/
if (xp->p_rts_flags & RECEIVING) { /* xp has dependency */
src_dst = xp->p_getfrom; /* get xp's source */
} else if (xp->p_rts_flags & SENDING) { /* xp has dependency */
src_dst = xp->p_sendto; /* get xp's destination */
} else {
return(0); /* not a deadlock */
}
/* Now check if there is a cyclic dependency. For group sizes of two,
* a combination of SEND(REC) and RECEIVE is not fatal. Larger groups
* or other combinations indicate a deadlock.
*/
if (src_dst == proc_nr(cp)) { /* possible deadlock */
if (group_size == 2) { /* caller and src_dst */
/* The function number is magically converted to flags. */
if ((xp->p_rts_flags ^ (function << 2)) & SENDING) {
return(0); /* not a deadlock */
}
}
return(group_size); /* deadlock found */
}
}
return(0); /* not a deadlock */
}
/*===========================================================================*
* mini_send *
*===========================================================================*/
@ -209,14 +270,6 @@ unsigned flags; /* system call flags */
*/
register struct proc *dst_ptr = proc_addr(dst);
register struct proc **xpp;
register struct proc *xp;
/* Check for deadlock by 'caller_ptr' and 'dst' sending to each other. */
xp = dst_ptr;
while (xp->p_rts_flags & SENDING) { /* check while sending */
xp = proc_addr(xp->p_sendto); /* get xp's destination */
if (xp == caller_ptr) return(ELOCKED); /* deadlock if cyclic */
}
/* Check if 'dst' is blocked waiting for this message. The destination's
* SENDING flag may be set when its SENDREC call blocked while sending.

View file

@ -65,7 +65,9 @@ register struct proc *rc; /* slot of process to clean up */
while (*xpp != NIL_PROC) { /* check entire queue */
if (*xpp == rc) { /* process is on the queue */
*xpp = (*xpp)->p_q_link; /* replace by next process */
break; /* done, can only send one */
kprintf("Proc %d removed from queue at %d\n",
proc_nr(rc), rc->p_sendto);
break; /* can only be queued once */
}
xpp = &(*xpp)->p_q_link; /* proceed to next queued */
}
@ -81,11 +83,13 @@ register struct proc *rc; /* slot of process to clean up */
if ((rp->p_rts_flags & RECEIVING) && rp->p_getfrom == proc_nr(rc)) {
rp->p_reg.retreg = EDEADSRCDST; /* report source died */
rp->p_rts_flags &= ~RECEIVING; /* no longer receiving */
kprintf("Proc %d receive dead src %d\n", proc_nr(rp), proc_nr(rc));
lock_enqueue(rp); /* let process run again */
}
else if ((rp->p_rts_flags & SENDING) && rp->p_sendto == proc_nr(rc)) {
rp->p_reg.retreg = EDEADSRCDST; /* report destination died */
rp->p_rts_flags &= ~SENDING; /* no longer sending */
kprintf("Proc %d send dead dst %d\n", proc_nr(rp), proc_nr(rc));
lock_enqueue(rp); /* let process run again */
}
}

View file

@ -107,10 +107,7 @@ PUBLIC struct boot_image image[] = {
{ MEM_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, DRV_M, MEM_C, "memory"},
{ LOG_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, DRV_C, "log" },
{ DRVR_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, DRV_C, "driver"},
#if DEAD_CODE
... WARNING: replace ~0 with USR_T / USR_M
#endif
{ INIT_PROC_NR, 0, USR_F, 8, USER_Q, 0, ~0, ~0, 0, "init" },
{ INIT_PROC_NR, 0, USR_F, 8, USER_Q, 0, USR_T, USR_M, 0, "init" },
};
/* Verify the size of the system image table at compile time. Also verify that