Hi Folks:

Last week, I wrote my first rough cut of a deadlock detection module. I haven't 
had a chance to thoroughly test it. Still, I would like comments. Many of the 
ideas come from previous posts on deadlock:

http://www.stackless.com/pipermail/stackless/2005-December/000290.html

and the "Adventures in Stackless Python Twisted Integration" Pycon 2008 talk. 

I envision the deadlock detector used as follows: a developer believes they 
have deadlock. They include the detection module and use the register() method 
to tell the detector which channels a tasklet uses. The programme is executed.

When stackless.run() prematurely returns, the detector goes through the graph, 
looking for cycles, returning a list of tuples, describing the tasklets and 
channels in question.

I make the assumption that cooperative scheduling automatically gives one 
no-premption  and mutual exclusion off the bat. So we have to look for hold and 
wait and circular wait. For hold-and-wait, I believe hold-and-wait looks as 
follows:

tasklet A:
     a.receive()
     b.send()

tasklet B
     b.send()
     a.receive()


To help detect hold-and-wait and circular wait, I create a wait-for graph. 
Wait-for graphs are described in section 16.6 of Silberschatz's "Database 
System Concepts."

I treat send/receive's as transactions. A channel with a balance of zero is 
assumed to be either a completed transaction or a transaction that never 
started. Consequently it is ignored. 

The register() creates the holding table (as in Hold-and-wait). This insight 
comes from Asgeir Ingvarsson's insight in the December 2005 thread.

When detect() is invoked, the detector goes though the holding table. If the 
balance is non-zero (this is the wait), tasklets associated with that channel 
are added to the graph.

Once the graph is completed, I use a variation of the graph traversal algorithm 
in Sedgewick. If a cycle is found, the detector stops and the path is returned. 
I imagine something like pygraph(?) could be used to visual the deadlocked 
tasklets and channels.

Anyhow I have included the code and a simple example. I suspect the detector is 
naive to catch every case (i know it won't case the of a single tasklet waiting 
on a single channel). Still I think the detection module would be useful to a 
new Stackless programmer. Maybe I could use stuff like class decorators to make 
the module easier to use. Anyhow comments could be appreciated. Enjoy!

Cheers,
Andrew




 












      
"""
DeadlockDetection.py

The purpose of this programme is to experiment with
deadlock detection in Stackless Python

February 14th, 2009

<song>Swimming - Martha and the Muffins </song>
"""

import stackless

class Detector(object):
    def __init__(self):
        self.visits = {}
        self.graph = {}
        self.holding = {}
        return


    def __buildGraph__(self):
        for channel in self.holding:
            a,b,(balance, flag, queue) = channel.__reduce__()
            for task in queue:
                if channel.balance == 0:
                   continue
                for t in self.holding[channel]:
                    if t == task:
                       continue 
                    else:
                       self.add(task, t)
                       self.visits[task] = 0


    def add(self, vertex1, vertex2):
        if vertex1 not in self.graph:
           self.graph[vertex1] = []
        self.graph[vertex1].append(vertex2) 


    def dumpGraph(self):
        for i in self.graph:
            print i, '->', self.graph[i]


    def dumpHoldings(self):
        for i in self.holding:
            print i, self.holding[i] 


    def registerResources(self,channels):
        t = stackless.getcurrent()
        for c in channels:
            if c not in self.holding.keys():
               self.holding[c] = [] 
            self.holding[c].append(t) 


    def __visit__(self, list, parent):
        result = None
        for edge in list:
            if self.visits[edge] == 1:
               result = [edge]
               break 
            elif self.visits[edge] == 0:
               self.visits[edge] += 1
               result = self.__visit__(self.graph[edge], edge) 
               if result != None:
                  result.append(edge)
        return result


    def printCycle(self, root, cycle):
        last = root 
        while (len(cycle) != 0):
              node = cycle.pop()
              print last,'->',node
              last = node


    def detect(self):
        for key in self.graph.keys():
            if self.visits[key] == 0:
               self.visits[key] += 1
               result = self.__visit__(self.graph[key], key)
               if result != None: 
                  self.printCycle(key, result)
                  break


def T(name, receiving, sending):
    global detector

    detector.registerResources([receiving, sending])
    print name, "about to receive"
    receiving.receive()
    print name,"about to receive"
    sending.send()
    print "done"

if __name__  == "__main__":

   global detector
   detector = Detector()

   c1 = stackless.channel()
   c2 = stackless.channel()
   c3 = stackless.channel()
   channels = [c1, c2, c3]

   stackless.tasklet(T)("T1",c1,c3)
   stackless.tasklet(T)("T2",c2,c1)
   stackless.tasklet(T)("T3",c3,c2)

   stackless.run()

   detector.__buildGraph__()
   detector.detect()
"""
DeadlockTest.py

The purpose of this programme is to experiment with
deadlock detection in Stackless Python

February 18th, 2009

<song>Plug in Baby - Muse </song>
"""

import stackless
from   DeadlockDetector  import DeadlockDetector

global detector

def T(name, receiving, sending):
    detector.registerResources(stackless.getcurrent(), [receiving, sending])
    receiving.receive()
    sending.send()
    print "done"

if __name__  == "__main__":

   detector = DeadlockDetector()

   c1 = stackless.channel()
   c2 = stackless.channel()
   c3 = stackless.channel()
   channels = [c1, c2, c3]

   stackless.tasklet(T)("T1",c1,c3)
   stackless.tasklet(T)("T2",c2,c1)
   stackless.tasklet(T)("T3",c3,c2)

   stackless.run()

   detector.detect()
   detector.__dumpGraph__()
   detector.__dumpHoldings__()
_______________________________________________
Stackless mailing list
[email protected]
http://www.stackless.com/mailman/listinfo/stackless

Reply via email to