示例#1
0
def main(arguments=None):
    parser = argparse.ArgumentParser(
        description=desc, formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("-v",
                        dest="verbose",
                        action="count",
                        default=0,
                        help="print verbose output")
    parser.add_argument("--version",
                        action="version",
                        version=f"%(prog)s {__version__}")
    parser.add_argument("server", nargs="+", type=get_server)
    args = parser.parse_args(arguments)
    if args.verbose == 0:
        level = logging.ERROR
    elif args.verbose == 1:
        level = logging.INFO
    else:
        level = logging.DEBUG
    gvars.logger.setLevel(level)
    try:
        resource.setrlimit(resource.RLIMIT_NOFILE, (50000, 50000))
    except Exception:
        gvars.logger.warning("Require root permission to allocate resources")
    kernel = curio.Kernel()
    try:
        kernel.run(multi_server(*args.server))
    except Exception as e:
        gvars.logger.exception(str(e))
    except KeyboardInterrupt:
        kernel.run(shutdown=True)
示例#2
0
    def curio_runner(pvdb, client, *, threaded_client=False):
        async def server_main():
            try:
                ctx = caproto.curio.server.Context(pvdb)
                await ctx.run()
            except caproto.curio.server.ServerExit:
                print('Server exited normally')
            except Exception as ex:
                print('Server failed', ex)
                raise
            finally:
                print('Server exiting')

        async def run_server_and_client():
            try:
                server_task = await curio.spawn(server_main)
                # Give this a couple tries, akin to poll_readiness.
                for _ in range(15):
                    try:
                        if threaded_client:
                            await threaded_in_curio_wrapper(client)()
                        else:
                            await client()
                    except TimeoutError:
                        continue
                    else:
                        break
                else:
                    raise TimeoutError(f"ioc failed to start")
            finally:
                await server_task.cancel()

        with curio.Kernel() as kernel:
            kernel.run(run_server_and_client)
示例#3
0
def main():
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('-v',
                        dest='verbose',
                        action='count',
                        default=0,
                        help='print verbose output')
    parser.add_argument('--version',
                        action='version',
                        version=f'%(prog)s {__version__}')
    parser.add_argument('server', nargs='+', type=get_server)
    args = parser.parse_args()
    global verbose
    verbose = args.verbose
    try:
        resource.setrlimit(resource.RLIMIT_NOFILE, (50000, 50000))
    except Exception as e:
        print('Require root permission to allocate resources')
    kernel = curio.Kernel()
    try:
        kernel.run(multi_server(*args.server))
    except Exception as e:
        traceback.print_exc()
        for k, v in kernel._selector.get_map().items():
            print(k, v, file=sys.stderr)
        for conn in connections:
            print('|', conn, file=sys.stderr)
    except KeyboardInterrupt:
        kernel.run(shutdown=True)
        print()
示例#4
0
def kernel():
    kernel = curio.Kernel(log_errors=False)

    def handle_crash(current):
        raise current.exc_info[1]

    kernel._crash_handler = handle_crash

    return kernel
示例#5
0
def test_thread_client_example(curio_server):
    from caproto.examples.thread_client_simple import main as example_main
    server_runner, prefix, caget_pvdb = curio_server

    @conftest.threaded_in_curio_wrapper
    def client():
        example_main(pvname1=prefix + 'int', pvname2=prefix + 'str')

    with curio.Kernel() as kernel:
        kernel.run(server_runner, client)
示例#6
0
def get_kernel():
    try:
        return _locals.curio_kernel
    except AttributeError:
        _locals.curio_kernel = k = curio.Kernel()

        if 'CURIOMONITOR' in os.environ:
            m = Monitor(k)
            k._call_at_shutdown(m.close)

        return k
示例#7
0
def test_repeater():
    from caproto.asyncio.repeater import main
    logging.getLogger('caproto').setLevel(logging.DEBUG)
    logging.basicConfig()

    loop = asyncio.get_event_loop()

    def run_repeater():
        asyncio.set_event_loop(loop)
        main()

    thread_repeater = threading.Thread(target=run_repeater)
    thread_repeater.start()
    threads = [thread_repeater]

    try:
        print('Waiting for the repeater to start up...')
        time.sleep(2)

        async def check_repeater():
            for pv in (
                    "XF:31IDA-OP{Tbl-Ax:X1}Mtr.VAL",
                    "XF:31IDA-OP{Tbl-Ax:X2}Mtr.VAL",
            ):
                data = await run_caget(pv)
                print(data)

            udp_sock = ca.bcast_socket()
            for i in range(3):
                print('Sending repeater register request ({})'.format(i + 1))
                udp_sock.sendto(bytes(ca.RepeaterRegisterRequest('0.0.0.0')),
                                ('127.0.0.1', REPEATER_PORT))

            await curio.sleep(1)

        with curio.Kernel() as kernel:
            kernel.run(check_repeater)

    finally:
        print('Stopping the event loop')
        loop.call_soon_threadsafe(loop.stop)

        for th in threads:
            print('Joining the thread')
            th.join()

        print('Closing the event loop')
        loop.close()

        print('Setting a new event loop')
        # new event loop for other tests
        asyncio.set_event_loop(asyncio.new_event_loop())
        print('Done')
示例#8
0
def test_curio_server():
    import caproto.curio.client as client
    from caproto.curio.server import _test as example_server
    kernel = curio.Kernel()
    called = []

    async def run_client():
        # Some user function to call when subscriptions receive data.

        def user_callback(command):
            print("Subscription has received data.")
            called.append(True)

        broadcaster = client.SharedBroadcaster(log_level='DEBUG')
        await broadcaster.register()
        ctx = client.Context(broadcaster, log_level='DEBUG')
        await ctx.search('pi')
        print('done searching')
        chan1 = await ctx.create_channel('pi')
        chan1.register_user_callback(user_callback)
        # ...and then wait for all the responses.
        await chan1.wait_for_connection()
        reading = await chan1.read()
        print('reading:', reading)
        sub_id = await chan1.subscribe()
        await chan1.unsubscribe(sub_id)
        await chan1.write((5, ))
        reading = await chan1.read()
        print('reading:', reading)
        await chan1.write((6, ))
        reading = await chan1.read()
        print('reading:', reading)
        await chan1.disconnect()
        await chan1.circuit.socket.close()

    async def task():
        # os.environ['EPICS_CA_ADDR_LIST'] = '255.255.255.255'
        try:
            server_task = await curio.spawn(example_server())
            await curio.sleep(1)  # Give server some time to start up.
            await run_client()
            print('client is done')
        finally:
            await server_task.cancel()
            print('server is canceled', server_task.cancelled)  # prints True
            print(kernel._tasks)

    with kernel:
        kernel.run(task)
    assert called, 'subscription not called in client'
    print('done')
示例#9
0
def test_with_caput(curio_server, pv, put_value, check_value, async_put=True):
    curio_server, caget_pvdb = curio_server

    async def client():
        print('* client_test', pv, 'put value', put_value, 'check value',
              check_value)

        db_entry = caget_pvdb[pv]
        db_old = db_entry.value
        data = await run_caput(pv,
                               put_value,
                               as_string=isinstance(db_entry, ca.ChannelChar))
        db_new = db_entry.value

        if isinstance(db_entry, (ca.ChannelInteger, ca.ChannelDouble)):
            clean_func = ast.literal_eval
        # elif isinstance(db_entry, ca.ChannelString):
        #     clean_func = lambda v: v.split(' ', 1)[1]
        else:
            clean_func = None

        if clean_func is not None:
            for key in ('old', 'new'):
                data[key] = clean_func(data[key])
        print('caput data', data)
        print('old from db', db_old)
        print('new from db', db_new)
        print('old from caput', data['old'])
        print('new from caput', data['new'])

        # check value from database compared to value from caput output
        assert db_new == data['new']
        # check value from database compared to value the test expects
        assert db_new == check_value

    async def task():
        server_task = await curio.spawn(curio_server)

        try:
            await client()
        finally:
            await server_task.cancel()

    with curio.Kernel() as kernel:
        kernel.run(task)
    print('done')
示例#10
0
def test_curio_server_and_thread_client(curio_server):
    from caproto.threading.client import (SharedBroadcaster,
                                          PVContext)
    from .conftest import threaded_in_curio_wrapper
    curio_server, caget_pvdb = curio_server

    @threaded_in_curio_wrapper
    def client_test():
        shared_broadcaster = SharedBroadcaster()
        cntx = PVContext(broadcaster=shared_broadcaster, log_level='DEBUG')

        pv = cntx.get_pv('int')
        assert pv.get() == caget_pvdb['int'].value
        print('get', pv.get())

        monitor_values = []

        def callback(value=None, **kwargs):
            print('monitor', value)
            monitor_values.append(value[0])

        pv.add_callback(callback)
        pv.put(1, wait=True)
        pv.put(2, wait=True)
        pv.put(3, wait=True)

        for i in range(3):
            if pv.get() == 3:
                break
            else:
                time.sleep(0.1)

        assert len(monitor_values) == 4

    async def task():
        server_task = await curio.spawn(curio_server)

        try:
            await curio.run_in_thread(client_test)
            await client_test.wait()
        finally:
            await server_task.cancel()

    with curio.Kernel() as kernel:
        kernel.run(task)
示例#11
0
def bench_curio_many_connections(pv_names,
                                 *,
                                 initial_value=None,
                                 log_level='DEBUG'):
    kernel = curio.Kernel()

    async def test():
        broadcaster = ca.curio.client.SharedBroadcaster(log_level=log_level)
        await broadcaster.register()
        ctx = ca.curio.client.Context(broadcaster, log_level=log_level)

        pvs = {}
        async with curio.TaskGroup() as connect_task:
            async with curio.TaskGroup() as search_task:
                for pvname in pv_names:
                    await search_task.spawn(ctx.search, pvname)

                while True:
                    res = await search_task.next_done()
                    if res is None:
                        break
                    pvname = res.result
                    await connect_task.spawn(ctx.create_channel, pvname)

            while True:
                res = await connect_task.next_done()
                if res is None:
                    break
                curio_channel = res.result
                pvname = curio_channel.channel.name
                pvs[pvname] = curio_channel

        assert len(pvs) == len(pv_names)
        # TODO: can't successfully test as this hammers file creation; this
        # will be important to resolve...
        await curio.sleep(1)

    def curio_client():
        kernel.run(test())

    yield curio_client

    logger.debug('Shutting down the kernel')
    kernel.run(shutdown=True)
    logger.debug('Done')
示例#12
0
def test_curio_server_example(prefix, run_client):
    import caproto.curio.client as client
    from caproto.ioc_examples.type_varieties import (pvdb)
    from caproto.curio.server import ServerExit, start_server as server_main

    pvdb = {prefix + key: value for key, value in pvdb.items()}
    pi_pv = prefix + 'int'
    broadcaster = client.SharedBroadcaster()
    ctx = client.Context(broadcaster)

    async def connect():
        await broadcaster.register()
        await ctx.search(pi_pv)
        print('done searching')
        chan1 = await ctx.create_channel(pi_pv)
        # ...and then wait for all the responses.
        await chan1.wait_for_connection()
        return chan1

    async def task():
        async def server_wrapper():
            try:
                await server_main(pvdb)
            except ServerExit:
                print('Server exited normally')

        try:
            server_task = await curio.spawn(server_wrapper)
            await curio.sleep(1)  # Give server some time to start up.
            chan1 = await connect()
            await run_client(chan1, pvdb, ctx)
            await chan1.disconnect()
            print('client is done')
        finally:
            try:
                await server_task.cancel()
                await server_task.join()
            except curio.KernelExit:
                print('Server exited normally')

    with curio.Kernel() as kernel:
        kernel.run(task)
    print('done')
示例#13
0
def test_sync_repeater(ioc):
    logging.getLogger('caproto').setLevel(logging.DEBUG)
    logging.basicConfig()

    async def check_repeater():
        for pv in (ioc.pvs['float'], ioc.pvs['str']):
            data = await run_caget('curio', pv)
            print(data)

        udp_sock = ca.bcast_socket()
        for i in range(3):
            print('Sending repeater register request ({})'.format(i + 1))
            udp_sock.sendto(bytes(ca.RepeaterRegisterRequest('0.0.0.0')),
                            ('127.0.0.1', REPEATER_PORT))

        await curio.sleep(1)

    with curio.Kernel() as kernel:
        kernel.run(check_repeater)
示例#14
0
def bench_curio_get_speed(pvname, *, initial_value=None, log_level='DEBUG'):
    kernel = curio.Kernel()

    async def curio_setup():
        logger.debug('Registering...')
        broadcaster = ca.curio.client.SharedBroadcaster(log_level=log_level)
        await broadcaster.register()
        ctx = ca.curio.client.Context(broadcaster, log_level=log_level)
        logger.debug('Registered')

        logger.debug('Searching for %s...', pvname)
        await ctx.search(pvname)
        logger.debug('... found!')
        chan = await ctx.create_channel(pvname)
        await chan.wait_for_connection()
        logger.debug('Connected to %s', pvname)

        if initial_value is not None:
            logger.debug('Writing initial value')
            await chan.write(initial_value)
            logger.debug('Wrote initial value')
        logger.debug('Init complete')
        return chan

    def curio_client():
        async def get():
            reading = await chan.read()
            if initial_value is not None:
                assert len(reading.data) == len(initial_value)

        kernel.run(get())

    chan = kernel.run(curio_setup())

    assert chan.channel.states[ca.CLIENT] is ca.CONNECTED, 'Not connected'

    yield curio_client

    logger.debug('Shutting down the kernel')
    kernel.run(shutdown=True)
    logger.debug('Done')
示例#15
0
def bench_curio_get_speed(pvname, *, initial_value=None, log_level='DEBUG'):
    logging.getLogger('caproto').setLevel(log_level)
    kernel = curio.Kernel()

    async def curio_setup():
        ctx = await get_curio_context()

        logger.debug('Searching for %s...', pvname)
        await ctx.search(pvname)
        logger.debug('... found!')
        chan = await ctx.create_channel(pvname)
        await chan.wait_for_connection()
        logger.debug('Connected to %s', pvname)

        if initial_value is not None:
            logger.debug('Writing initial value')
            await chan.write(initial_value, notify=True)
            logger.debug('Wrote initial value')
        logger.debug('Init complete')
        return chan

    def curio_client():
        async def get():
            reading = await chan.read()
            if initial_value is not None:
                assert len(reading.data) == len(initial_value)

        kernel.run(get())

    chan = kernel.run(curio_setup())

    assert chan.channel.states[ca.CLIENT] is ca.CONNECTED, 'Not connected'

    try:
        yield curio_client
    finally:
        logger.debug('Shutting down the kernel')
        kernel.run(shutdown=True)
        logger.debug('Done')
示例#16
0
    def curio_runner(pvdb, client, *, threaded_client=False):
        # Hide these imports so that the other fixtures are usable by other
        # libraries (e.g. ophyd) without the experimental dependencies.
        import curio

        import caproto.curio

        async def server_main():
            try:
                ctx = caproto.curio.server.Context(pvdb)
                await ctx.run()
            except caproto.curio.server.ServerExit:
                logger.info('Server exited normally')
            except Exception as ex:
                logger.error('Server failed: %s %s', type(ex), ex)
                raise

        async def run_server_and_client():
            try:
                server_task = await curio.spawn(server_main)
                # Give this a couple tries, akin to poll_readiness.
                for _ in range(15):
                    try:
                        if threaded_client:
                            await threaded_in_curio_wrapper(client)()
                        else:
                            await client()
                    except TimeoutError:
                        continue
                    else:
                        break
                else:
                    raise TimeoutError("ioc failed to start")
            finally:
                await server_task.cancel()

        with curio.Kernel() as kernel:
            kernel.run(run_server_and_client)
示例#17
0
def bench_curio_put_speed(pvname, *, value, log_level='DEBUG'):
    kernel = curio.Kernel()

    async def curio_setup():
        logger.debug('Registering...')
        broadcaster = ca.curio.client.SharedBroadcaster(log_level=log_level)
        await broadcaster.register()
        ctx = ca.curio.client.Context(broadcaster, log_level=log_level)
        logger.debug('Registered')

        logger.debug('Searching for %s...', pvname)
        await ctx.search(pvname)
        logger.debug('... found!')
        chan = await ctx.create_channel(pvname)
        await chan.wait_for_connection()
        logger.debug('Connected to %s', pvname)
        return chan

    def curio_client():
        async def put():
            await chan.write(value)

        kernel.run(put())

    chan = kernel.run(curio_setup())

    assert chan.channel.states[ca.CLIENT] is ca.CONNECTED, 'Not connected'

    yield curio_client

    async def check():
        reading = await chan.read()
        np.testing.assert_array_almost_equal(reading.data, value)

    kernel.run(check())
    logger.debug('Shutting down the kernel')
    kernel.run(shutdown=True)
    logger.debug('Done')
示例#18
0
def bench_curio_put_speed(pvname, *, value, log_level='DEBUG'):
    logging.getLogger('caproto').setLevel(log_level)
    kernel = curio.Kernel()

    async def curio_setup():
        ctx = await get_curio_context()

        logger.debug('Searching for %s...', pvname)
        await ctx.search(pvname)
        logger.debug('... found!')
        chan = await ctx.create_channel(pvname)
        await chan.wait_for_connection()
        logger.debug('Connected to %s', pvname)
        return chan

    def curio_client():
        async def put():
            await chan.write(value, notify=True)

        kernel.run(put())

    chan = kernel.run(curio_setup())

    assert chan.channel.states[ca.CLIENT] is ca.CONNECTED, 'Not connected'

    try:
        yield curio_client

        async def check():
            reading = await chan.read()
            np.testing.assert_array_almost_equal(reading.data, value)

        kernel.run(check())
    finally:
        logger.debug('Shutting down the kernel')
        kernel.run(shutdown=True)
        logger.debug('Done')
def _get_kernel():
    global test_kernel
    if test_kernel is None:
        test_kernel = curio.Kernel()
    return test_kernel
示例#20
0
 def curio_client():
     with curio.Kernel() as kernel:
         kernel.run(test)
示例#21
0
def test_curio_server_with_caget(curio_server, pv, dbr_type):
    ctrl_keys = ('upper_disp_limit', 'lower_alarm_limit', 'upper_alarm_limit',
                 'lower_warning_limit', 'upper_warning_limit',
                 'lower_ctrl_limit', 'upper_ctrl_limit', 'precision')

    async def run_client_test():
        print('* client_test', pv, dbr_type)
        db_entry = caget_pvdb[pv]
        # native type as in the ChannelData database
        db_native = ca.native_type(db_entry.data_type)
        # native type of the request
        req_native = ca.native_type(dbr_type)

        data = await run_caget(pv, dbr_type=dbr_type)
        print('dbr_type', dbr_type, 'data:')
        print(data)

        db_value = db_entry.value

        # convert from string value to enum if requesting int
        if (db_native == ChType.ENUM
                and not (req_native == ChType.STRING
                         or dbr_type in (ChType.CTRL_ENUM, ChType.GR_ENUM))):
            db_value = db_entry.enum_strings.index(db_value)
        if req_native in (ChType.INT, ChType.LONG, ChType.SHORT, ChType.CHAR):
            if db_native == ChType.CHAR:
                assert int(data['value']) == ord(db_value)
            else:
                assert int(data['value']) == int(db_value)
        elif req_native in (ChType.STSACK_STRING, ):
            db_string_value = db_entry.alarm.alarm_string
            string_length = len(db_string_value)
            read_value = data['value'][:string_length]
            assert read_value == db_string_value
        elif req_native in (ChType.CLASS_NAME, ):
            assert data['class_name'] == 'caproto'
        elif req_native in (ChType.FLOAT, ChType.DOUBLE):
            assert float(data['value']) == float(db_value)
        elif req_native == ChType.STRING:
            if db_native == ChType.STRING:
                db_string_value = str(db_value)
                string_length = len(db_string_value)
                read_value = data['value'][:string_length]
                assert int(data['element_count']) == string_length
                assert read_value == db_string_value
                # due to how we monitor the caget output, we get @@@s where
                # null padding bytes are. so long as we verify element_count
                # above and the set of chars that should match, this assertion
                # should pass
            else:
                assert data['value'] == str(db_value)
        elif req_native == ChType.ENUM:
            bad_strings = ['Illegal Value (', 'Enum Index Overflow (']
            for bad_string in bad_strings:
                if data['value'].startswith(bad_string):
                    data['value'] = data['value'][len(bad_string):-1]

            if (db_native == ChType.ENUM
                    and (dbr_type in (ChType.CTRL_ENUM, ChType.GR_ENUM))):
                # ctrl enum gets back the full string value
                assert data['value'] == db_value
            else:
                assert int(data['value']) == int(db_value)
        else:
            raise ValueError('TODO ' + str(dbr_type))

        # TODO metadata should be cast to requested type as well!
        same_type = (ca.native_type(dbr_type) == db_native)

        if (dbr_type in ca.control_types and same_type
                and dbr_type != ChType.CTRL_ENUM):
            for key in ctrl_keys:
                if (key == 'precision'
                        and ca.native_type(dbr_type) != ChType.DOUBLE):
                    print('skipping', key)
                    continue
                print('checking', key)
                assert float(data[key]) == getattr(db_entry, key), key

        if dbr_type in ca.time_types:
            timestamp = datetime.datetime.fromtimestamp(db_entry.timestamp)
            assert data['timestamp'] == timestamp

        if (dbr_type in ca.time_types or dbr_type in ca.status_types
                or dbr_type == ChType.STSACK_STRING):
            severity = data['severity']
            if not severity.endswith('_ALARM'):
                severity = '{}_ALARM'.format(severity)
            severity = getattr(ca._dbr.AlarmSeverity, severity)
            assert severity == db_entry.severity, key

            status = data['status']
            status = getattr(ca._dbr.AlarmStatus, status)
            assert status == db_entry.status, key

            if 'ackt' in data:
                ack_transient = data['ackt'] == 'YES'
                assert ack_transient == db_entry.alarm.acknowledge_transient

            if 'acks' in data:
                ack_severity = data['acks']
                ack_severity = getattr(ca._dbr.AlarmSeverity, ack_severity)
                assert ack_severity == db_entry.alarm.acknowledge_severity

    async def task():
        server_task = await curio.spawn(curio_server)

        try:
            await run_client_test()
        finally:
            await server_task.cancel()

    with curio.Kernel() as kernel:
        kernel.run(task)
    print('done')
示例#22
0
def test_curio_client():
    from caproto.curio.client import main
    with curio.Kernel() as kernel:
        kernel.run(main())
示例#23
0
 def func_wrapper(*args, **kwargs):
     kernel = curio.Kernel()
     kernel.run(func(*args, **kwargs))
     kernel.run(shutdown=True)
示例#24
0
def server_thread(context):
    async def server():
        return await context.run(log_pv_names=True)

    kernel = curio.Kernel()
    kernel.run(server)
示例#25
0
        "target":
        request.target.decode("ascii"),
        "headers": [(name.decode("ascii"), value.decode("ascii"))
                    for (name, value) in request.headers],
        "body":
        "",
    }
    while True:
        event = await wrapper.next_event()
        if type(event) is h11.EndOfMessage:
            break
        assert type(event) is h11.Data
        response_json["body"] += event.data.decode("ascii")
    response_body_unicode = json.dumps(response_json,
                                       sort_keys=True,
                                       indent=4,
                                       separators=(",", ": "))
    response_body_bytes = response_body_unicode.encode("utf-8")
    await send_simple_response(wrapper, 200, "application/json; charset=utf-8",
                               response_body_bytes)


################################################################
# Run the server
################################################################

if __name__ == "__main__":
    kernel = curio.Kernel()
    print("Listening on http://localhost:8080")
    kernel.run(curio.tcp_server("localhost", 8080, http_serve))
示例#26
0
def kernel(request):
    """Create an instance of the default kernel for each test case."""
    kernel = curio.Kernel()

    # request.addfinalizer(kernel.shutdown)
    return kernel
示例#27
0
def test_curio_client_example():
    from caproto.examples.curio_client_simple import main
    with curio.Kernel() as kernel:
        kernel.run(main())
示例#28
0
 def run(self, host, port):
     kernel = curio.Kernel()
     logging.info(f"Listening on http://{host}:{port}")
     kernel.run(curio.tcp_server(host, port, self.http_serve))
示例#29
0
def kernel(request):
    """Create an instance of the default kernel for each test case."""
    kernel = curio.Kernel()
    request.addfinalizer(lambda: kernel.run(shutdown=True))
    return kernel
示例#30
0
        for n in range(50):
            total += await curio.run_cpu_bound(fib, n)
    except curio.CancelledError:
        print('Fine. Saving my work.')


async def parent():
    print('Parent PID', os.getpid())
    kid_task = await curio.new_task(kid())
    await curio.sleep(5)
    print("Yes, go play")
    await start_evt.set()

    await curio.SignalSet(signal.SIGHUP).wait()

    print("Let's go")
    count_task = await curio.new_task(countdown(10))
    await count_task.join()
    print("We're leaving!")
    try:
        await kid_task.join(timeout=10)
    except TimeoutError:
        print('I warned you!')
        await kid_task.cancel()
    print("Leaving!")


if __name__ == '__main__':
    kernel = curio.Kernel(with_monitor=True)
    kernel.run(parent())