def __init__(self, chakanaRoot, coojaTimeout, doCompile="True", withGUI="False"): self._chakanaRoot = os.path.abspath(chakanaRoot) self._coojaTimeout = coojaTimeout self._threadManager = chakana.threads.ThreadManager() self._doCompile = doCompile self._withGUI = withGUI debug(MajorEvent, "Chakana harness created")
def unregisterWaitingMonitor(self, monitor): debug(Debug, "Unregistering waiting monitor: " + repr(monitor)) assert(isinstance(monitor, chakana.monitor.Monitor)) assert(monitor in self._monitors) assert(monitor in self._waitingMonitors) self._waitingMonitors.remove(monitor) debug(Debug2, repr(self))
def port(self): if self._port is None: laps = 0 debug(Event, "Waiting for COOJA to open server socket") debug(Debug, "Reading: " + self._outputFile) while 1: if self._timeout > 0 and laps > self._timeout: raise chakana.error.Timeout(self, self._timeout) logContents = "" try: logContents = chakana.utils.readFile(self._outputFile) except IOError, err: if err.errno != errno.ENOENT: raise match = re.search(r"Chakana server listening on port (\d+).", logContents) debug(Debug, "Log contents: " + logContents) if match: self._port = int(match.group(1)) debug(Event, "COOJA is now listening on port " + str(self._port)) break else: debug(Debug, "Waiting for COOJA to start") time.sleep(1) laps += 1 match = re.search(r"Unable to access jarfile", logContents) if match: raise RuntimeError("Could not locate COOJA JAR: " + logContents)
def waitForCoojaEventpoint(self, eventpoint): response = self.runCommand("ADD_EVENTPOINT", eventpoint.coojaArguments()) id = int(response.documentElement.childNodes[0].nodeValue) debug(Debug, "Waiting for COOJA eventpoint " + str(id)) resourceAllocated = 0 while resourceAllocated == 0: try: self._waitMap[id] = (eventpoint, threading.Event()) resourceAllocated = 1 except thread.error: resourceAllocated = 0 self.threadManager().registerPIDerror() self._registerWaitingEventpoint(eventpoint) eventpoint._isWaitingEvent.set() resourceAllocated = 0 while resourceAllocated == 0: try: self._waitMap[id][1].wait() resourceAllocated = 1 except thread.error: resourceAllocated = 0 self.threadManager().registerPIDerror() del self._waitMap[id] self._unregisterWaitingEventpoint(eventpoint) try: self.runCommand("DELETE_EVENTPOINT", { "id" : id }) debug(Debug, "COOJA event " + str(id) + " has occurred") except chakana.error.CoojaExit: pass except socket.error: pass
def registerBasicEventpoint(self, eventpoint): debug(Debug2, "Registering basic eventpoint: " + repr(eventpoint)) assert(isinstance(eventpoint, chakana.event.BasicEventpoint)) assert(not (eventpoint in self._eventpoints)) self._eventpoints.append(eventpoint) self._eventpoints.sort() debug(Debug2, repr(self))
def runCommand(self, name, args = None, xmlContent = ""): debug(Debug3, "Running cooja command " + name + ", args: " + repr(args) + " xml content: " + repr(xmlContent)) if args is None: args = {} self._connectionLock.acquire() try: if self._coojaStream.closed: raise chakana.error.CoojaExit() command = ['<command value="' + name + '">'] for (key, value) in args.items(): if value is None: command.append('<' + key + '/>') else: command.append('<' + key + '>' + str(value) + '</' + key + '>') command.append(xmlContent + '</command>') commandStr = "\n".join(command + ['\n']) debug(MinorEvent, '--> ' + commandStr) self._coojaStream.write(commandStr) self._coojaStream.flush() response = self.readFromCooja() debug(Debug, response.toprettyxml()) if response.documentElement.tagName == 'error': raise chakana.error.CoojaError(response) self._connectionLock.release() return response except socket.error: debug(MajorEvent, 'Socket error catched') except AttributeError: debug(MajorEvent, 'Attribute error catched')
def waitMonitor(self, parentEventpoint = None): debug(Debug, "Waiting for monitor to finish: " + repr(self)) # While monitor is registered, check for continuations while self in self.shepherd()._monitors: resourceAllocated = 0 while resourceAllocated == 0: try: self._isWaitingMonitor.wait() resourceAllocated = 1 except thread.error: resourceAllocated = 0 self.shepherd().threadManager().registerPIDerror() self._isWaitingMonitor.clear() self._ready = 1 # If all monitors ready, poll continuation allMonitorsReady = 1 for monitor in self.shepherd()._monitors: if not monitor._ready: allMonitorsReady = 0 if allMonitorsReady: if self in self.shepherd()._monitors: self.shepherd().pollContinuation() else: # A monitor may be waiting for us, tell parent we are ready if parentEventpoint is not None: parentEventpoint._isWaitingEvent.set() self.join()
def copyTree(src, dst, symlinks = False, predicate = lambda path: 1, preserveTimes = False): """Similar to shutil.copytree, but allows existing destination and passes exceptions.""" names = filter(predicate, os.listdir(src)) if not os.path.isdir(dst): os.mkdir(dst) for name in names: srcname = os.path.join(src, name) dstname = os.path.join(dst, name) try: if symlinks and os.path.islink(srcname): linkto = os.readlink(srcname) os.symlink(linkto, dstname) elif os.path.isdir(srcname): copyTree(srcname, dstname, symlinks, predicate, preserveTimes) else: if preserveTimes: shutil.copy2(srcname, dstname) else: shutil.copy(srcname, dstname) # XXX What about devices, sockets etc.? except (IOError, os.error), why: debug(Error, "Can't copy %s to %s: %s" % (`srcname`, `dstname`, str(why))) raise
def waitMonitor(self, parentEventpoint=None): debug(Debug, "Waiting for monitor to finish: " + repr(self)) # While monitor is registered, check for continuations while self in self.shepherd()._monitors: resourceAllocated = 0 while resourceAllocated == 0: try: self._isWaitingMonitor.wait() resourceAllocated = 1 except thread.error: resourceAllocated = 0 self.shepherd().threadManager().registerPIDerror() self._isWaitingMonitor.clear() self._ready = 1 # If all monitors ready, poll continuation allMonitorsReady = 1 for monitor in self.shepherd()._monitors: if not monitor._ready: allMonitorsReady = 0 if allMonitorsReady: if self in self.shepherd()._monitors: self.shepherd().pollContinuation() else: # A monitor may be waiting for us, tell parent we are ready if parentEventpoint is not None: parentEventpoint._isWaitingEvent.set() self.join()
def copyFile(src, dest): debug(Event, "cp " + src + " " + dest) srcFile = file(src) destFile = file(dest, "w") destFile.write(srcFile.read()) srcFile.close() destFile.close()
def readVariable(self, variable, ** kwArgs): response = self.readMemory( type = "variable", variable = variable, ** kwArgs) arrayString = response.documentElement.childNodes[0].nodeValue.split() bytes = map(eval, arrayString) debug(Debug, "Read variable " + variable + " as byte array: " + repr(bytes)) return bytes
def registerWaitingMonitor(self, monitor): debug(Debug, "Registering waiting monitor: " + repr(monitor)) assert(isinstance(monitor, chakana.monitor.Monitor)) assert(monitor in self._monitors) assert(not (monitor in self._waitingMonitors)) self._waitingMonitors.append(monitor) self._waitingMonitors.sort() debug(Debug2, repr(self))
def run(self): try: self.result = self._func(* self._args, ** self._kwArgs) except Exception, err: debug(Debug, "Caught exception in timeout function: " + str(err) + ":\n" + exceptionDump(sys.exc_info())) self.error = err self.exc_info = sys.exc_info()
def discard(self): self._discarded = 1 self._ready = 0 debug(Debug, "Discarding monitor:\n" + repr(self)) # Wake up thread with empty results if hasattr(self, "_resultQueue"): self._resultQueue.put(None)
def __init__(self): self._activeThreads = {} self._startedThreads = {} self._threadTerminations = [] self._pidErrors = 0 # Protects the three lists above self._listLock = threading.RLock() self._threadTerminationQueue = Queue.Queue() debug(Debug, self.summary())
def run(self): try: self.result = self._func(*self._args, **self._kwArgs) except Exception, err: debug( Debug, "Caught exception in timeout function: " + str(err) + ":\n" + exceptionDump(sys.exc_info())) self.error = err self.exc_info = sys.exc_info()
def run(self): debug(Event, self.getName() + " thread is now running") self.threadManager()._registerThreadStart(self) try: self.doRun() except Exception, err: debug(MajorEvent, "Caught exception in " + self.getName() + " thread" + ":\n" + exceptionDump(sys.exc_info())) self._exceptionInfo = sys.exc_info()
def doRun(self): debug(Debug, "Running monitor") try: if (not self._discarded): self.runMonitor() except chakana.error.Discarded: pass self.shepherd().unregisterMonitor(self) self._isWaitingMonitor.set() debug(Debug, "Monitor exiting")
def run(self): debug(Event, self.getName() + " thread is now running") self.threadManager()._registerThreadStart(self) try: self.doRun() except Exception, err: debug( MajorEvent, "Caught exception in " + self.getName() + " thread" + ":\n" + exceptionDump(sys.exc_info())) self._exceptionInfo = sys.exc_info()
def _registerThread(self, thread): "Called by thread classes when a thread is created." assert(isinstance(thread, ManagedThread)) self._listLock.acquire() try: assert(not thread.getName() in self._activeThreads) debug(Debug, "Registering " + thread.getName() + " thread") self._activeThreads[thread.getName()] = thread debug(Debug, self.summary()) finally: self._listLock.release()
def _registerThread(self, thread): "Called by thread classes when a thread is created." assert (isinstance(thread, ManagedThread)) self._listLock.acquire() try: assert (not thread.getName() in self._activeThreads) debug(Debug, "Registering " + thread.getName() + " thread") self._activeThreads[thread.getName()] = thread debug(Debug, self.summary()) finally: self._listLock.release()
def __init__(self, threadManager, ** kwArgs): self._threadManager = threadManager self._exceptionInfo = None resourceAllocated = 0 while resourceAllocated == 0: try: threading.Thread.__init__(self, ** kwArgs) resourceAllocated = 1 except thread.error: resourceAllocated = 0 self.threadManager().registerPIDerror() debug(Event, "Initialising thread " + self.getName()) self._threadManager._registerThread(self)
def __init__(self, threadManager, port, coojaHost = "localhost"): debug(MajorEvent, "Creating shepherd") self._pollConnLock = threading.Lock() self._threadManager = threadManager self._port = port self._monitors = [] self._waitingMonitors = [] # Only basic eventpoints in these lists self._eventpoints = [] self._waitingEventpoints = [] self._coojaContinueEvent = threading.Event() self._waitMap = {} self._coojaHost = coojaHost self._coojaConnection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) debug(MajorEvent, "Connecting to COOJA at " + coojaHost + ":" + str(self._port)) self._connectionLock = threading.Lock() self._coojaConnection.connect((self._coojaHost, self._port)) self._coojaStream = self._coojaConnection.makefile() self._coojaConnection.close() del self._coojaConnection self._connectionLock.acquire() hello = self.readFromCooja() debug(Debug, hello.toprettyxml()) self._connectionLock.release() self._shepherdThread = threads.ManagedThread( self._threadManager, target = self._shepherdMainLoop) self._shepherdThread.start() debug(Debug, "Shepherd created:\n" + repr(self))
def __init__(self, threadManager, **kwArgs): self._threadManager = threadManager self._exceptionInfo = None resourceAllocated = 0 while resourceAllocated == 0: try: threading.Thread.__init__(self, **kwArgs) resourceAllocated = 1 except thread.error: resourceAllocated = 0 self.threadManager().registerPIDerror() debug(Event, "Initialising thread " + self.getName()) self._threadManager._registerThread(self)
def waitAll(self, timeout=3600, mourningTime=5): "Wait for all threads to terminate." debug(MajorEvent, "Waiting for all test threads to terminate") debug(MinorEvent, self.summary()) limit = time.time() + timeout while self.numThreadsLeft() > 0: try: nextTimeout = limit - time.time() if nextTimeout <= 0: raise chakana.error.Timeout(self.unfinishedThreads()[0], timeout) else: self.waitOne(nextTimeout) except chakana.error.Timeout, err: debug( Error, "Timeout waiting for " + err.child.getName() + " thread, killing subprocesses.") self.killAll() while self.numThreadsLeft() > 0: try: self.waitOne(mourningTime) except chakana.error.Timeout: debug(Error, "Timeout while mourning threads, aborting") signal.signal(signal.SIGABRT, signal.SIG_DFL) os.abort() raise
def __init__(self, shepherd, routine=None, *args, **kwArgs): chakana.threads.ManagedThread.__init__(self, shepherd.threadManager()) self._shepherd = shepherd self._routine = routine self._args = args self._kwArgs = kwArgs self._ready = 0 self._discarded = 0 resourceAllocated = 0 while resourceAllocated == 0: try: self._isWaitingMonitor = threading.Event() resourceAllocated = 1 except thread.error: resourceAllocated = 0 shepherd.threadManager().registerPIDerror() debug(Debug, "Monitor created") self._shepherd.registerMonitor(self)
def readFromCooja(self): # XXX: Assume message ends with a newline debug(Debug, "Reading message from COOJA") responseLines = [self._coojaStream.readline()] debug(Debug2, "First line: " + repr(responseLines[0])) (rootElement, slash) = re.match(r"^\s*<(\w+)(/?)>", responseLines[0]).groups() debug(Debug3, "Root element: " + rootElement) if slash != "/": while 1: if re.search("</" + re.escape(rootElement) + ">$", responseLines[-1], re.M): break responseLines.append(self._coojaStream.readline()) debug(Debug3, "Read line: " + repr(responseLines[-1])) result = "".join(responseLines) debug(MinorEvent, '<-- ' + result) return xml.dom.minidom.parseString(result)
def __init__(self, shepherd, routine = None, * args, ** kwArgs): chakana.threads.ManagedThread.__init__(self, shepherd.threadManager()) self._shepherd = shepherd self._routine = routine self._args = args self._kwArgs = kwArgs self._ready = 0 self._discarded = 0 resourceAllocated = 0 while resourceAllocated == 0: try: self._isWaitingMonitor = threading.Event() resourceAllocated = 1 except thread.error: resourceAllocated = 0 shepherd.threadManager().registerPIDerror() debug(Debug, "Monitor created") self._shepherd.registerMonitor(self)
def realPath(path): """Similar to os.path.realpath, but handles amd gracefully.""" ret = os.path.realpath(path) for binDir in os.environ["PATH"].split(":") + ["/usr/sbin", "/sbin"]: amq = os.path.join(binDir, "amq") if os.path.isfile(amq): try: output = chakana.command.output(amq) except chakana.error.CommandFailed, err: debug(Debug, str(err)) # Assume amd is not running return ret for line in output.splitlines(): amdDir = line.split()[0] mountDir = line.split()[-1] if mountDir[0] == "/": match = re.match('^(' + re.escape(line) + ')(/$)', ret) if match: return amdDir + ret[len(line) :] return ret
def pollContinuation(self): self._pollConnLock.acquire() if len(self._waitingMonitors) != len(self._monitors): self._pollConnLock.release() return for monitor in self._monitors: if not monitor._ready: self._pollConnLock.release() return for monitor in self._monitors: assert(not monitor._discarded) for eventpoint in self._eventpoints: assert(not eventpoint._discarded) assert(self._waitingMonitors == self._monitors) assert(self._waitingEventpoints == self._eventpoints) debug(MinorEvent, "All monitors are waiting, activating COOJA") assert(not self._coojaContinueEvent.isSet()) self._coojaContinueEvent.set()
def newCustomMonitor(self, Type, routine = None, * args, ** kwArgs): """Start a new monitor thread running routine, with * args and ** kwArgs as arguments.""" debug(Debug, "Creating new monitor of type " + Type.__name__) debug(Debug3, "Routine: " + repr(routine) + ", arguments: " + repr(args) + ", keyword arguments: " + repr(kwArgs)) thread = Type(self, routine, * args, ** kwArgs) debug(MinorEvent, "New monitor thread created: " + repr(thread)) return thread
def quit(self): """Send a termination request to the debugger broker, and discard all debuggers.""" debug(Information, "Terminating the shepherd session") self.runCommand("EXIT_COOJA") self._connectionLock.acquire() self._coojaStream.close() self._connectionLock.release() self._coojaContinueEvent.set() debug(Information, "Number of PID errors reported: " + str(self.threadManager().nrPIDerrors())) for (eventpoint, event) in self._waitMap.values(): debug(Debug2, "Awakening eventpoint at exit: " + repr(eventpoint)) event.set()
def waitAll(self, timeout = 3600, mourningTime = 5): "Wait for all threads to terminate." debug(MajorEvent, "Waiting for all test threads to terminate") debug(MinorEvent, self.summary()) limit = time.time() + timeout while self.numThreadsLeft() > 0: try: nextTimeout = limit - time.time() if nextTimeout <= 0: raise chakana.error.Timeout(self.unfinishedThreads()[0], timeout) else: self.waitOne(nextTimeout) except chakana.error.Timeout, err: debug(Error, "Timeout waiting for " + err.child.getName() + " thread, killing subprocesses.") self.killAll() while self.numThreadsLeft() > 0: try: self.waitOne(mourningTime) except chakana.error.Timeout: debug(Error, "Timeout while mourning threads, aborting") signal.signal(signal.SIGABRT, signal.SIG_DFL) os.abort() raise
def makeSymlink(value, dest, force = True, debugLevel = MinorEvent, dryRun = False): if os.path.islink(dest): if os.readlink(dest) == value: debug(Debug, "Link " + dest + " already points to " + value) return elif force: debug(debugLevel, "Removing " + dest) if not dryRun: os.remove(dest) else: raise OSError((errno.EEXIST, "Link already exists", dest)) absValue = os.path.join(os.path.dirname(dest), value) if (not dryRun) and (not force) and (not os.path.isfile(absValue)): raise OSError((errno.ENOENT, "Link destination does not exist", absDest)) debug(debugLevel, "Linking " + dest + " to " + value) if not dryRun: os.symlink(value, dest)
def startCooja(self): # COMPILE COOJA AND PLUGIN if self._doCompile == "True": for target in ("cooja", "plugin"): buildCommand = 'cd ' + chakana.command.quote(self._chakanaRoot) + ' && ant compile_' + target debug(MajorEvent, "Building " + target) debug(Event, buildCommand) output = chakana.command.output(buildCommand) debug(MinorEvent, output) coojaOutputFile = os.path.join(self._chakanaRoot, "build/cooja.out") # START COOJA if os.path.isfile(coojaOutputFile): os.remove(coojaOutputFile) coojaThread = CoojaThread(self._threadManager, self._chakanaRoot, coojaOutputFile, self._coojaTimeout, withGUI=self._withGUI) coojaThread.start() return coojaThread.port()
def doRun(self): debug(MajorEvent, "Starting COOJA") buildDir = os.path.dirname(self._outputFile) chakana.utils.makeDirsSafe(buildDir) contikiRoot = os.path.join(self._chakanaRoot, '../..') contikiRoot = contikiRoot.replace('/cygdrive/c', 'c:') if self._withGUI == "True": coojaCommand = '( cd ' + chakana.command.quote(buildDir) + ' && java -jar ' + \ chakana.command.quote(os.path.join(contikiRoot, 'tools/cooja/dist/cooja.jar')) + ' ' + \ '-external_tools_config=../cooja.chakana.properties ' + \ '-contiki=' + chakana.command.quote(contikiRoot) + ' < /dev/null > ' + \ os.path.basename(self._outputFile) + ' 2>&1 )' else: coojaCommand = '( cd ' + chakana.command.quote(buildDir) + ' && java -jar ' + \ chakana.command.quote(os.path.join(contikiRoot, 'tools/cooja/dist/cooja.jar')) + ' ' + \ '-nogui ' + \ '-external_tools_config=../cooja.chakana.properties ' + \ '-contiki=' + chakana.command.quote(contikiRoot) + ' < /dev/null > ' + \ os.path.basename(self._outputFile) + ' 2>&1 )' debug(Event, coojaCommand) os.system(coojaCommand) debug(MajorEvent, "COOJA has finished")
def startCooja(self): # COMPILE COOJA AND PLUGIN if self._doCompile == "True": for target in ("cooja", "plugin"): buildCommand = 'cd ' + chakana.command.quote( self._chakanaRoot) + ' && ant compile_' + target debug(MajorEvent, "Building " + target) debug(Event, buildCommand) output = chakana.command.output(buildCommand) debug(MinorEvent, output) coojaOutputFile = os.path.join(self._chakanaRoot, "build/cooja.out") # START COOJA if os.path.isfile(coojaOutputFile): os.remove(coojaOutputFile) coojaThread = CoojaThread(self._threadManager, self._chakanaRoot, coojaOutputFile, self._coojaTimeout, withGUI=self._withGUI) coojaThread.start() return coojaThread.port()
def removeTree(path, ignoreErrors = False): debug(Debug, "rm -rf " + path) if os.path.isdir(path): shutil.rmtree(path, ignore_errors = ignoreErrors)
def _unregisterWaitingEventpoint(self, eventpoint): debug(Debug2, "Unregistering waiting eventpoint: " + repr(eventpoint)) assert(eventpoint in self._waitingEventpoints) assert(eventpoint in self._eventpoints) self._waitingEventpoints.remove(eventpoint) debug(Debug2, repr(self))
def _shepherdMainLoop(self): debug(Event, "Starting shepherd main loop") while 1: debug(Debug, "Waiting for eventpoints to enter wait state") debug(Debug2, repr(self)) self._coojaContinueEvent.wait() self._coojaContinueEvent.clear() if self._coojaStream.closed: debug(Event, "Terminating shepherd main loop") return debug(Debug, "Resuming COOJA") assert(len(self._eventpoints) == len(self._waitingEventpoints)) response = self.runCommand("CONTROL_SIM", { "RESUME" : None }) id = int(response.documentElement.childNodes[0].nodeValue) debug(MinorEvent, "Eventpoint " + str(id) + " was triggered") # Wake up triggered eventpoint self._waitMap[id][1].set() # Allow new main loop startups self._pollConnLock.release()