class StartupDaemon : def __init__(self, phys_id) : self._event_api = EventAPI() self._event_api.start() self._phys_id = phys_id self._running_pids = set([]) self._running = True def _on_startup(self, event) : self.terminate_all() self._event_api.unsubscribe_all(StartupEvent) self._event_api.subscribe(StartSimulationEvent, self._on_sim_start) self._event_api.publish(AckStartupEvent(self._phys_id)) self._world = event.get_world() def terminate_all(self) : for p in self._running_pids : p.kill() self._running_pids.clear() def _start_entity_process(self, entity) : print 'Starting subprocess for uid %s' % entity.get_uid() p = subprocess.Popen(('python entity.py %s %s' % (entity.pickle(), self._world.pickle())).split(' ')) self._running_pids.add(p) def _on_sim_start(self, event) : local_entities = event.get_mapping()[self._phys_id] for e in local_entities : self._start_entity_process(e) def start(self) : self._event_api.subscribe(StartupEvent, self._on_startup) self._event_api.subscribe(StopSimulationEvent, self._restart) self._event_api.get_thread().join() # while self._running : # pass def _restart(self, event) : self.terminate_all() self._event_api.clear_subscriptions() self._running_pids = set([]) print 'Got stop event. State cleared.' self._event_api.subscribe(StartupEvent, self._on_startup) self._event_api.subscribe(StopSimulationEvent, self._restart) def stop(self) : self._event_api.stop() self.terminate_all() self._running = False
class Simulation : def __init__(self, world_inst) : self._event_api = EventAPI() self._event_api.start() self._startup_acks = set([]) self._world = world_inst def get_world(self) : return self._world def _on_ack_startup(self, event) : print 'Got ack startup:', event.get_daemon_id() self._startup_acks.add(event.get_daemon_id()) def start(self, wait) : self._event_api.subscribe(AckStartupEvent, self._on_ack_startup) # Do *NOT* change self._world after this point. It is pickled here and sent to other phy nodes self._event_api.publish(StartupEvent(self._world)) time.sleep(wait) if len(self._startup_acks) > 0 : print 'Got %s startup acks. Starting simulation.' % (len(self._startup_acks),) self._event_api.unsubscribe_all(AckStartupEvent) #TODO: Fix the division entities_per_phy_node = int(len(self._world.get_entities()) / float(len(self._startup_acks))) print ' allocating %s entities per node' % entities_per_phy_node mapping = {} to_allocate = list(self._world.get_entities()) for i, phy in enumerate(list(self._startup_acks)) : alloc = to_allocate[i*entities_per_phy_node:(i+1)*entities_per_phy_node] print i, alloc if len(alloc) == 0 : break mapping[phy] = alloc self._world.initialize() self._event_api.publish(StartSimulationEvent(mapping)) else : print 'Got no startup acks. Quitting...' def stop(self) : self._event_api.publish(StopSimulationEvent()) self._event_api.stop()