def runner(): global v v = 0 print "First, without dreadlock" t = time.time() cd = Countdown(500) for x in xrange(500): fork(nolocks, cd) cd.wait() print "Test took %.3f" % (time.time() - t) print "%s < %s?" % (v, 50 * 500) assert (v < 50 * 500) print '-' * 72 v = 0 locker = DreadlockService('localhost', 6001, 100) t = time.time() cd = Countdown(500) for x in xrange(500): fork(withlocks, locker, cd) cd.wait() print "Test took %.3f" % (time.time() - t) print "%s == %s?" % (v, 50 * 500) assert (v == 50 * 500) print '-' * 72 print "okay."
def host_specific_send(self, host, msg, typ, transport_cb): if host not in self.host_queues: q = Queue() fork(host_loop, host, q) self.host_queues[host] = q self.host_queues[host].put((msg, typ, transport_cb))
def populate(self): def go(): diesel.wait('ready') for i in xrange(N): self.queue.put(i) diesel.fork(go)
def test_overwriting_custom_signal_handler_fails(): readings = [] success = Event() failure = Event() def append_reading(sig, frame): readings.append(sig) signal.signal(signal.SIGUSR1, signal.SIG_DFL) signal.signal(signal.SIGUSR1, append_reading) def overwriter(): try: diesel.signal(signal.SIGUSR1) except diesel.ExistingSignalHandler: success.set() else: failure.set() diesel.fork(overwriter) diesel.sleep() os.kill(os.getpid(), signal.SIGUSR1) evt, _ = diesel.first(waits=[success, failure]) assert evt is success assert readings
def parent(): COUNT = 10000 v = [0] for x in xrange(COUNT): fork(tottering_child, v) sleep(8) # long enough on core 2-era WVPASS(v[0] == COUNT) quickstop()
def __call__(self): for h, p in self.hosts: pq = Queue() sq = Queue() gq = Queue() fork(manage_peer_connection, h, p, pq, sq, gq) self.proposal_qs.append(pq) self.save_qs.append(sq) self.get_qs.append(gq)
def setup(self): self.done = Countdown(10) self.fan = Fanout() self.subscriber_data = {} for x in xrange(10): diesel.fork(self.subscriber) diesel.sleep() for i in xrange(10): self.fan.pub(i) self.done.wait()
def chat(self): fork(self.input_handler) nick = self.input.get() send("%s\r\n" % nick) while True: evt, data = first(until_eol=True, waits=[self.input]) if evt == "until_eol": print data.strip() else: send("%s\r\n" % data)
def main(): diesel.fork(track_cpu_stats) actor_pairs = int(sys.argv[1]) done = Countdown(actor_pairs) for i in xrange(actor_pairs): pair(done) start = time.time() done.wait() print "done in %.2f secs" % (time.time() - start) diesel.sleep(1) diesel.quickstop()
def do_upgrade(self, req): if req.headers.get_one('Upgrade') != 'WebSocket': return self.web_handler(req) # do upgrade response org = req.headers.get_one('Origin') send( '''HTTP/1.1 101 Web Socket Protocol Handshake\r Upgrade: WebSocket\r Connection: Upgrade\r WebSocket-Origin: %s\r WebSocket-Location: %s\r WebSocket-Protocol: diesel-generic\r \r ''' % (org, self.ws_location)) inq = Queue() outq = Queue() def wrap(inq, outq): self.web_socket_handler(inq, outq) outq.put(WebSocketDisconnect()) fork(wrap, inq, outq) while True: try: typ, val = first(receive=1, waits=[outq.wait_id]) if typ == 'receive': assert val == '\x00' val = until('\xff')[:-1] if val == '': inq.put(WebSocketDisconnect()) else: data = dict((k, v[0]) if len(v) == 1 else (k, v) for k, v in cgi.parse_qs(val).iteritems()) inq.put(WebSocketData(data)) else: try: v = outq.get(waiting=False) except QueueEmpty: pass else: if type(v) is WebSocketDisconnect: send('\x00\xff') break else: data = dumps(dict(v)) send('\x00%s\xff' % data) except ConnectionClosed: inq.put(WebSocketDisconnect()) raise ConnectionClosed("remote disconnected")
def main(): client = RedisClient('localhost', 6379) client.delete(key) client.set(incr_key, 0) for _ in xrange(500): fork(take_lock) if random.random() > 0.1: sleep(random.random() / 10) sleep(2) assert counter == int(client.get(incr_key)), 'Incr failed!' quickstop()
def test_sleep_independence(): v = [0] def i(): v[0] += 1 sleep(0.1) v[0] += 1 fork(i) fork(i) sleep(0.05) assert (v[0] == 2) sleep(0.1) assert (v[0] == 4)
def test_multiple_signal_waiters(): N_WAITERS = 5 c = Countdown(N_WAITERS) def mwaiter(): diesel.signal(signal.SIGUSR1) c.tick() for i in xrange(N_WAITERS): diesel.fork(mwaiter) diesel.sleep() os.kill(os.getpid(), signal.SIGUSR1) evt, data = diesel.first(sleep=1, waits=[c]) assert evt is c, "all waiters were not triggered!"
def consume(self): def worker(myid): while True: # Test both queue.get and wait() on queue (both are valid # APIs for getting items from the queue). The results should # be the same. if random.random() > 0.5: v = self.queue.get() else: v = diesel.wait(self.queue) self.results.append(v) self.handled[myid] += 1 self.done.tick() for i in xrange(W): diesel.fork(worker, i)
def make_and_wait(): q1 = Queue() q2 = Queue() both = [q1, q2] fork(fire_random, both) while True: q, v = first(waits=both) assert v is None if q == q1: print 'q1' elif q == q2: print 'q2' else: assert 0
def websocket_protocol(self, req): """Runs the WebSocket protocol after the handshake is complete. Creates two `Queue` instances for incoming and outgoing messages and passes them to the `web_socket_handler` that was supplied to the `WebSocketServer` constructor. """ inq = Queue() outq = Queue() def wrap(req, inq, outq): self.web_socket_handler(req, inq, outq) outq.put(WebSocketDisconnect()) handler_loop = fork(wrap, req, inq, outq) if req.rfc_handshake: handle_frames = self.handle_rfc_6455_frames else: handle_frames = self.handle_non_rfc_frames try: handle_frames(inq, outq) except ConnectionClosed: if handler_loop.running: inq.put(WebSocketDisconnect()) raise
def test_signals_are_handled_while_event_loop_is_blocked(): done = Event() def handler(): diesel.signal(signal.SIGUSR1) done.set() def killer(): time.sleep(0.1) os.kill(os.getpid(), signal.SIGUSR1) diesel.fork(handler) diesel.thread(killer) diesel.sleep() evt, _ = diesel.first(sleep=1, waits=[done]) assert evt is done
def test_sleep_zero(): '''Sleep w/out argument allows other loops to run ''' v = [0] def i(): for i in xrange(10000): v[0] += 1 sleep() fork(i) sleep(0.05) cur = v[0] sleep() # allow i to get scheduled now = v[0] assert (now == cur + 1)
def test_can_wait_on_os_signals(): # Start our Loop that will wait on USR1 diesel.fork(waiter) # Let execution switch to the newly spawned loop diesel.sleep() # We haven't sent the signal, so the state should not be triggered assert not state['triggered'] # Send the USR1 signal os.kill(os.getpid(), signal.SIGUSR1) # Again, force a switch so the waiter can act on the signal diesel.sleep() # Now that we're back, the waiter should have triggered the state assert state['triggered']
def handle(request): """Handle a request for a websocket. """ if request.transport != 'xhr-polling': raise Response(404) org = request.headers.one('Origin') inq = Queue() outq = Queue() def wrap(request, inq, outq): handler(request, inq, outq) outq.put(WebSocketDisconnect()) fork(wrap, request, inq, outq) while True: try: log.debug("trying websocket thing") typ, val = first(receive=1, waits=[outq.wait_id]) log.debug(typ) log.debug(val) if typ == 'receive': assert val == '\x00' val = until('\xff')[:-1] if val == '': inq.put(WebSocketDisconnect()) else: inq.put(request) else: try: v = outq.get(waiting=False) except QueueEmpty: pass else: if type(v) is WebSocketDisconnect: send('\x00\xff') break else: send('\x00%s\xff' % response.to_http(request.version)) except ConnectionClosed: inq.put(WebSocketDisconnect()) raise ConnectionClosed("remote disconnected")
def test_basic_fire(): done = Event() v = [0] def w(): while True: wait("boom!") v[0] += 1 def f(): sleep(0.05) fire("boom!") sleep(0.05) fire("boom!") done.set() fork(f) fork(w) ev, _ = first(sleep=1, waits=[done]) assert v[0] == 2
def __enter__(self): trans = self.client.transaction(watch=[self.key]) v = self.client.get(self.key) if v: raise LockNotAcquired() else: try: with trans as t: t.setex(self.key, self.timeout, self.me) def touch(): with RedisClient(self.client.addr, self.client.port) as c: while self.in_block: c.expire(self.key, self.timeout) sleep(self.timeout / 2) self.in_block = True fork(touch) except RedisTransactionError: raise LockNotAcquired()
def scan(self): now = time.time() for cid, (t, ls) in self.clients.items(): if now - t > self.TIMEOUT: nls = [] for l, rollback in ls: new = store.maybe_remove(l, rollback) if new is not None: fork( group.network_set, None, l, new, None, ) nls.append((l, rollback)) if (cid, rollback) in store[l].transactions: store[l].transactions.remove((cid, rollback)) if nls: self.clients[cid] = (t, nls) else: del self.clients[cid]
def websocket_protocol(self, req): """Runs the WebSocket protocol after the handshake is complete. Creates two `Queue` instances for incoming and outgoing messages and passes them to the `web_socket_handler` that was supplied to the `WebSocketServer` constructor. """ inq = Queue() outq = Queue() if req.rfc_handshake: handle_frames = self.handle_rfc_6455_frames else: # Finish the non-RFC handshake key1 = req.headers.get('Sec-WebSocket-Key1') key2 = req.headers.get('Sec-WebSocket-Key2') # The final key can be in two places. The first is in the # `Request.data` attribute if diesel is *not* being proxied # to by a smart proxy that parsed HTTP requests. If it is being # proxied to, that data will not have been sent until after our # initial 101 Switching Protocols response, so we will need to # receive it here. if req.data: key3 = req.data else: evt, key3 = first(receive=8, sleep=5) assert evt == "receive", "timed out while finishing handshake" num1 = int(''.join(c for c in key1 if c in '0123456789')) num2 = int(''.join(c for c in key2 if c in '0123456789')) assert num1 % key1.count(' ') == 0 assert num2 % key2.count(' ') == 0 final = pack('!II8s', num1 / key1.count(' '), num2 / key2.count(' '), key3) handshake_finish = hashlib.md5(final).digest() send(handshake_finish) handle_frames = self.handle_non_rfc_frames def wrap(req, inq, outq): self.web_socket_handler(req, inq, outq) outq.put(WebSocketDisconnect()) handler_loop = fork(wrap, req, inq, outq) try: handle_frames(inq, outq) except ConnectionClosed: if handler_loop.running: inq.put(WebSocketDisconnect()) raise
def get_many(self, keys, concurrency_limit=100, no_failures=False): assert self.used_client_context, "Cannot fetch in parallel without a pooled make_client_context!" inq = Queue() outq = Queue() for k in keys: inq.put(k) for x in xrange(min(len(keys), concurrency_limit)): diesel.fork(self._subrequest, inq, outq) failure = False okay, err = [], [] for k in keys: (key, success, val) = outq.get() if success: okay.append((key, val)) else: err.append((key, val)) if no_failures: raise BucketSubrequestException("Error in parallel subrequests", err) return okay, err
def test_basic_sleep(): delt = [None] STIME = 0.3 def l(): t = time() sleep(STIME) delt[0] = time() - t l_ = fork(l) sleep() while l_.running: sleep() min_bound = (STIME - Timer.ALLOWANCE) max_bound = (STIME + Timer.ALLOWANCE) assert (delt[0] > min_bound and delt[0] < max_bound), delt[0]
def get_many(self, keys, concurrency_limit=100, no_failures=False): assert self.used_client_context,\ "Cannot fetch in parallel without a pooled make_client_context!" inq = Queue() outq = Queue() for k in keys: inq.put(k) for x in xrange(min(len(keys), concurrency_limit)): diesel.fork(self._subrequest, inq, outq) failure = False okay, err = [], [] for k in keys: (key, success, val) = outq.get() if success: okay.append((key, val)) else: err.append((key, val)) if no_failures: raise BucketSubrequestException("Error in parallel subrequests", err) return okay, err
def test_wait_tokens_dont_accumulate_forever(): """Wait tokens and related structures should be disposed of after use. They are tracked in a dictionary in the internal diesel.events.WaitPool. If a wait_id has no more objects waiting on it, it should be removed from that dictionary along with the set of waiting objects. """ done = [] wait_ids = [] expected_length = len(diesel.runtime.current_app.waits.waits) for i in xrange(50): wait_id = uuid.uuid4().hex diesel.fork(waiting_green_thread, wait_id, done) diesel.sleep() wait_ids.append(wait_id) for wait_id in wait_ids: diesel.fire(wait_id) diesel.sleep() while len(done) != 50: diesel.sleep(0.1) actual_length = len(diesel.runtime.current_app.waits.waits) assert actual_length == expected_length, actual_length
def setup(self): self.result = Event() self.queue = Queue() self.timeouts = 0 diesel.fork(self.consumer, 0.01) diesel.fork(self.producer, 0.05) diesel.fork(self.consumer, 0.10) ev, val = diesel.first(sleep=TIMEOUT, waits=[self.result]) if ev == 'sleep': assert 0, 'timed out'
def test_incoming_message_loop_is_kept_alive(): def stop_after_10_sends(sock): if sock.send_calls == 10: raise StopIteration svc = MisbehavingService('something', max_ticks=10) loop = diesel.fork(svc.run) diesel.sleep() start = time.time() maxtime = 0.5 while loop.running and time.time() - start < maxtime: diesel.sleep(0.1) if loop.running: loop.reschedule_with_this_value(diesel.TerminateLoop()) diesel.sleep() assert not loop.running assert svc.zmq_socket.exceptions > 1, svc.zmq_socket.exceptions
def main(): def waiting(ident): print ident, "waiting ..." t = sleep_pool(4) print ident, "woken up after", t diesel.fork(waiting, 'a') diesel.fork(waiting, 'b') diesel.fork(waiting, 'c') for i in xrange(11): print "busy!" diesel.sleep(1) div = spawn(lambda x, y: x / y) try: div(1, 0) except ZeroDivisionError, e: diesel.log.error(e.original_traceback)
def main(): def waiting(ident): print ident, "waiting ..." t = sleep_pool(4) print ident, "woken up after", t diesel.fork(waiting, 'a') diesel.fork(waiting, 'b') diesel.fork(waiting, 'c') for i in xrange(11): print "busy!" diesel.sleep(1) div = spawn(lambda x,y: x/y) try: div(1,0) except ZeroDivisionError, e: diesel.log.error(e.original_traceback)
def test_fire_miss(): done = Event() v = [0] def w(): while True: wait("boom!") v[0] += 1 def f(): sleep(0.05) fire("fizz!") done.set() fork(f) fork(w) fork(w) ev, _ = first(sleep=1, waits=[done]) assert v[0] == 0 # should not have woken up!
def do_upgrade(self, req): if req.headers.get('Upgrade', '').lower() != 'websocket': return self.web_handler(req) headers = {} # do upgrade response org = req.headers.get('Origin') handshake_finish = None if 'Sec-WebSocket-Key' in req.headers: assert req.headers.get('Sec-WebSocket-Version') in ['8', '13'], \ "We currently only support Websockets version 8 and 13 (ver=%s)" % \ req.headers.get('Sec-WebSocket-Version') protocol = req.headers.get('Sec-WebSocket-Protocol', None) key = req.headers.get('Sec-WebSocket-Key') accept = b64encode(hashlib.sha1(key + self.GUID).digest()) headers = { 'Upgrade' : 'websocket', 'Connection' : 'Upgrade', 'Sec-WebSocket-Accept' : accept, } elif 'Sec-WebSocket-Key1' in req.headers: protocol = req.headers.get('Sec-WebSocket-Protocol', None) key1 = req.headers.get('Sec-WebSocket-Key1') key2 = req.headers.get('Sec-WebSocket-Key2') headers = { 'Upgrade': 'WebSocket', 'Connection': 'Upgrade', 'Sec-WebSocket-Origin': org, 'Sec-WebSocket-Location': req.url.replace('http', 'ws', 1), } key3 = req.data assert len(key3) == 8, len(key3) num1 = int(''.join(c for c in key1 if c in '0123456789')) num2 = int(''.join(c for c in key2 if c in '0123456789')) assert num1 % key1.count(' ') == 0 assert num2 % key2.count(' ') == 0 final = pack('!II8s', num1 / key1.count(' '), num2 / key2.count(' '), key3) handshake_finish = hashlib.md5(final).digest() else: assert 0, "Unsupported WebSocket handshake." if protocol: headers['Sec-WebSocket-Protocol'] = protocol resp = Response( response='' if not handshake_finish else handshake_finish, status=101, headers=headers, ) self.send_response(resp) inq = Queue() outq = Queue() def wrap(req, inq, outq): self.web_socket_handler(req, inq, outq) outq.put(WebSocketDisconnect()) fork(wrap, req._get_current_object(), inq, outq) if not handshake_finish: handle_frames = self.handle_rfc_6455_frames else: handle_frames = self.handle_non_rfc_frames try: handle_frames(inq, outq) except ConnectionClosed: inq.put(WebSocketDisconnect()) raise
def forker(): for x in xrange(5): fork(sleep_and_print, x)
def pair(done): q = Queue() diesel.fork(producer, q) diesel.fork(consumer, q, done)
def do_upgrade(self, req): if req.headers.get_one('Upgrade') != 'websocket' and req.headers.get_one('Upgrade') != 'WebSocket': return self.web_handler(req) hybi = False # do upgrade response org = req.headers.get_one('Origin') if 'Sec-WebSocket-Key' in req.headers: assert req.headers.get_one('Sec-WebSocket-Version') == '8', \ "We currently only support version 8 and below" protocol = (req.headers.get_one('Sec-WebSocket-Protocol') if 'Sec-WebSocket-Protocol' in req.headers else None) key = req.headers.get_one('Sec-WebSocket-Key') accept = b64encode(hashlib.sha1(key + self.GUID).digest()) send(server_handshake_hybi % accept) if protocol: send("Sec-WebSocket-Protocol: %s\r" % protocol) send("\r\n\r\n") hybi = True elif 'Sec-WebSocket-Key1' in req.headers: protocol = (req.headers.get_one('Sec-WebSocket-Protocol') if 'Sec-WebSocket-Protocol' in req.headers else None) key1 = req.headers.get_one('Sec-WebSocket-Key1') key2 = req.headers.get_one('Sec-WebSocket-Key2') key3 = receive(8) num1 = int(''.join(c for c in key1 if c in '0123456789')) num2 = int(''.join(c for c in key2 if c in '0123456789')) assert num1 % key1.count(' ') == 0 assert num2 % key2.count(' ') == 0 final = pack('!II8s', num1 / key1.count(' '), num2 / key2.count(' '), key3) secure_response = hashlib.md5(final).digest() send( '''HTTP/1.1 101 Web Socket Protocol Handshake\r Upgrade: WebSocket\r Connection: Upgrade\r Sec-WebSocket-Origin: %s\r Sec-WebSocket-Location: %s\r '''% (org, self.ws_location)) if protocol: send("Sec-WebSocket-Protocol: %s\r\n" % (protocol,)) send("\r\n") send(secure_response) else: send( '''HTTP/1.1 101 Web Socket Protocol Handshake\r Upgrade: WebSocket\r Connection: Upgrade\r WebSocket-Origin: %s\r WebSocket-Location: %s\r WebSocket-Protocol: diesel-generic\r \r ''' % (org, self.ws_location)) inq = Queue() outq = Queue() def wrap(inq, outq): self.web_socket_handler(inq, outq) outq.put(WebSocketDisconnect()) fork(wrap, inq, outq) while True: try: if hybi: typ, val = first(receive=2, waits=[outq.wait_id]) if typ == 'receive': b1, b2 = unpack(">BB", val) opcode = b1 & 0x0f fin = (b1 & 0x80) >> 7 has_mask = (b2 & 0x80) >> 7 assert has_mask == 1, "Frames must be masked" if opcode == 8: inq.put(WebSocketDisconnect()) else: assert opcode == 1, "Currently only opcode 1 is supported" length = b2 & 0x7f if length == 126: length = unpack('>H', receive(2)) elif length == 127: length = unpack('>L', receive(8)) mask = unpack('>BBBB', receive(4)) payload = array('>B', receive(length)) for i in xrange(len(payload)): payload[i] ^= mask[i % 4] data = dict((k, v[0]) if len(v) == 1 else (k, v) for k, v in cgi.parse_qs(payload.tostring()).iteritems()) inq.put(WebSocketData(data)) else: try: v = outq.get(waiting=False) except QueueEmpty: pass else: if type(v) is WebSocketDisconnect: b1 = 0x80 | (8 & 0x0f) # FIN + opcode send(pack('>BB', b1, 0)) break else: payload = dumps(v) b1 = 0x80 | (1 & 0x0f) # FIN + opcode payload_len = len(payload) if payload_len <= 125: header = pack('>BB', b1, payload_len) elif payload_len > 125 and payload_len < 65536: header = pack('>BBH', b1, 126, payload_len) elif payload_len >= 65536: header = pack('>BBQ', b1, 127, payload_len) send(header + payload) else: typ, val = first(receive=1, waits=[outq.wait_id]) if typ == 'receive': assert val == '\x00' val = until('\xff')[:-1] if val == '': inq.put(WebSocketDisconnect()) else: data = dict((k, v[0]) if len(v) == 1 else (k, v) for k, v in cgi.parse_qs(val).iteritems()) inq.put(WebSocketData(data)) else: try: v = outq.get(waiting=False) except QueueEmpty: pass else: if type(v) is WebSocketDisconnect: send('\x00\xff') break else: data = dumps(dict(v)) send('\x00%s\xff' % data) except ConnectionClosed: inq.put(WebSocketDisconnect()) raise ConnectionClosed("remote disconnected")
sleep_pool = ProcessPool(2, sleep_and_return) def main(): def waiting(ident): print ident, "waiting ..." t = sleep_pool(4) print ident, "woken up after", t diesel.fork(waiting, 'a') diesel.fork(waiting, 'b') diesel.fork(waiting, 'c') for i in xrange(11): print "busy!" diesel.sleep(1) div = spawn(lambda x, y: x / y) try: div(1, 0) except ZeroDivisionError, e: diesel.log.error(e.original_traceback) print '^^ That was an intentional exception.' term(div) psleep = spawn(sleep_and_return) diesel.fork(psleep, 0.5) diesel.fork(psleep, 0.5) diesel.sleep(1) print '^^ That was an intentional exception.' diesel.quickstop() diesel.quickstart(sleep_pool.pool, main)