From: Cristiano Giuffrida Date: Wed, 16 Dec 2009 23:32:08 +0000 (+0000) Subject: Fix bug in IPC deadlock detection code. X-Git-Tag: v3.1.6~151 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/host.html?a=commitdiff_plain;h=b4d6d9db26105e225818951daf5b4a5817f05465;p=minix.git Fix bug in IPC deadlock detection code. The old deadlock code was misplaced and unable to deal with asynchronous IPC primitives (notify and senda) effectively. As an example, the following sequence of messages allowed the deadlock detection code to trigger a false positive: 1. A.notify(B) 2. A.receive(B) 3. B.receive(A) 1. B.notify(A) The solution is to run the deadlock detection routine only when a process is about to block in mini_send() or mini_receive(). --- diff --git a/kernel/proc.c b/kernel/proc.c index f693525d6..4ae5a5e00 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -297,7 +297,6 @@ long bit_map; /* notification event set or flags */ */ register struct proc *caller_ptr = proc_ptr; /* get pointer to caller */ int mask_entry; /* bit to check in send mask */ - int group_size; /* used for deadlock check */ int result; /* the system call's result */ int src_dst_p; /* Process slot number */ size_t msg_size; @@ -464,17 +463,6 @@ long bit_map; /* notification event set or flags */ msg_size = sizeof(*m_ptr); } - /* Check for a possible deadlock for blocking SEND(REC) and RECEIVE. */ - if (call_nr == SEND || call_nr == SENDREC || call_nr == RECEIVE) { - if (group_size = deadlock(call_nr, caller_ptr, src_dst_p)) { -#if 0 - kprintf("sys_call: trap %d from %d to %d deadlocked, group size %d\n", - call_nr, proc_nr(caller_ptr), src_dst_p, group_size); -#endif - 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 @@ -630,6 +618,11 @@ int flags; return(ENOTREADY); } + /* Check for a possible deadlock before actually blocking. */ + if (deadlock(SEND, caller_ptr, dst_p)) { + return(ELOCKED); + } + /* Destination is not waiting. Block and dequeue caller. */ PHYS_COPY_CATCH(linaddr, vir2phys(&caller_ptr->p_sendmsg), sizeof(message), addr); @@ -773,6 +766,11 @@ int flags; * Block the process trying to receive, unless the flags tell otherwise. */ if ( ! (flags & NON_BLOCKING)) { + /* Check for a possible deadlock before actually blocking. */ + if (deadlock(RECEIVE, caller_ptr, src_p)) { + return(ELOCKED); + } + caller_ptr->p_getfrom_e = src_e; RTS_SET(caller_ptr, RTS_RECEIVING); return(OK);