Example #1
0
def test_rwmutex():
    mu = sync.RWMutex()

    # Unlock  without lock -> panic
    # RUnlock without lock -> panic
    with panics("sync: Unlock of unlocked RWMutex"):
        mu.Unlock()
    with panics("sync: RUnlock of unlocked RWMutex"):
        mu.RUnlock()

    # Lock vs Lock; was also tested in test_rwmutex_basic
    mu.Lock()
    l = []
    done = chan()

    def _():
        mu.Lock()
        l.append('b')
        mu.Unlock()
        done.close()

    go(_)
    time.sleep(1 * dt)
    l.append('a')
    mu.Unlock()
    done.recv()
    assert l == ['a', 'b']
Example #2
0
def test_waitgroup():
    wg = sync.WaitGroup()
    wg.add(2)

    ch = chan(3)

    def _():
        wg.wait()
        ch.send('a')

    for i in range(3):
        go(_)

    wg.done()
    assert len(ch) == 0
    time.sleep(0.1)
    assert len(ch) == 0
    wg.done()

    for i in range(3):
        assert ch.recv() == 'a'

    wg.add(1)
    go(_)
    time.sleep(0.1)
    assert len(ch) == 0
    wg.done()
    assert ch.recv() == 'a'

    with panics("sync: negative WaitGroup counter"):
        wg.done()
Example #3
0
def _test_mutex(mu, lock, unlock):
    # verify that g2 mu.lock() blocks until g1 does mu.unlock()
    getattr(mu, lock)()
    l = []
    done = chan()

    def _():
        getattr(mu, lock)()
        l.append('b')
        getattr(mu, unlock)()
        done.close()

    go(_)
    time.sleep(1 * dt)
    l.append('a')
    getattr(mu, unlock)()
    done.recv()
    assert l == ['a', 'b']

    # the same via with
    with mu:
        l = []
        done = chan()

        def _():
            with mu:
                l.append('d')
            done.close()

        go(_)
        time.sleep(1 * dt)
        l.append('c')
    done.recv()
    assert l == ['c', 'd']
Example #4
0
def main():
    ng = 100  # N(tasks) to spawn
    gstarted = chan()  # main <- g
    mainexit = chan()  # main -> all g

    # a task that wants to live longer than main
    def leaktask():
        gstarted.send(1)
        mainexit.recv()

        # normally when main thread exits, the whole process is terminated.
        # however if go spawns a thread with daemon=0, we are left here to continue.
        # make sure it is not the case
        time.sleep(3)
        print("leaked goroutine: process did not terminate", file=sys.stderr)
        sys.stderr.flush()
        time.sleep(1)
        os._exit(1)  # not sys.exit - that can be used only from main thread

    for i in range(ng):
        go(leaktask)

    # make sure all tasks are started
    for i in range(ng):
        gstarted.recv()

    # now we can exit
    mainexit.close()
    sys.exit(0)
Example #5
0
    def _serve(n):
        # XXX net.socket.close does not interrupt sk.accept
        # XXX we workaround it with accept timeout and polling for ._down
        n._oslistener.settimeout(1E-3)  # 1ms
        while 1:
            if ready(n._down):
                break

            try:
                osconn, _ = n._oslistener.accept()
            except net.timeout:
                continue

            except Exception as e:
                n._vnet_down(e)
                return

            # XXX wg.Add(1)
            def _(osconn):
                # XXX defer wg.Done()

                myaddr = addrstr4(*n._oslistener.getsockname())
                peeraddr = addrstr4(*osconn.getpeername())

                try:
                    n._loaccept(osconn)
                except Exception as e:
                    if errcause(e) is not ErrConnRefused:
                        log.error("lonet %s: serve %s <- %s : %s" %
                                  (qq(n._network), myaddr, peeraddr, e))

            go(_, osconn)
Example #6
0
def accept(l):
    h = l._socket._host

    with errctx("accept %s %s" % (h.network(), l.addr())):
        while 1:
            _, _rx = select(
                l._down.recv,  # 0
                l._dialq.recv,  # 1
            )
            if _ == 0:
                l._excDown()
            if _ == 1:
                req = _rx

            with h._sockmu:
                sk = h._allocFreeSocket()

            ack = chan()
            req._resp.send(Accept(sk.addr(), ack))

            _, _rx = select(
                l._down.recv,  # 0
                ack.recv,  # 1
            )
            if _ == 0:

                def purgesk():
                    err = ack.recv()
                    if err is None:
                        try:
                            req._netsk.close()
                        except:
                            pass
                    with h._sockmu:
                        h._socketv[sk._port] = None

                go(purgesk)
                l._excDown()

            if _ == 1:
                err = _rx

            if err is not None:
                with h._sockmu:
                    h._socketv[sk._port] = None
                continue

            c = conn(sk, req._from, req._netsk)
            with h._sockmu:
                sk.conn = c

            return c
Example #7
0
def test_sema_wakeup_different_thread():
    sema = sync.Sema()
    sema.acquire()
    l = []
    done = chan()
    def _():
        time.sleep(1*dt)
        l.append('a')
        sema.release()
        done.close()
    go(_)
    sema.acquire()
    l.append('b')
    done.recv()
    assert l == ['a', 'b']
Example #8
0
def test_rwmutex_lock_vs_rlock(unlock_via_downgrade):
    mu = sync.RWMutex()

    # Lock vs RLock
    l = []  # accessed as R R R ... R  W  R R R ... R
    Nr1 = 10  # Nreaders queued before W
    Nr2 = 15  # Nreaders queued after  W
    mu.RLock()
    locked = chan(Nr1 + 1 * 3 + Nr2)  # main <- R|W: mu locked
    rcont = chan()  # main -> R: continue

    def R():  # readers
        mu.RLock()
        locked.send(('R', len(l)))
        rcont.recv()
        mu.RUnlock()

    for i in range(Nr1):
        go(R)

    # make sure all Nr1 readers entered mu.RLock
    for i in range(Nr1):
        assert locked.recv() == ('R', 0)

    # spawn W
    def W():  # 1 writer
        mu.Lock()
        time.sleep(
            Nr2 *
            dt)  # give R2 readers more chance to call mu.RLock and run first
        locked.send('W')
        l.append('a')
        if not unlock_via_downgrade:
            locked.send('_WUnlock')
            mu.Unlock()
        else:
            locked.send('_WUnlockToRLock')
            mu.UnlockToRLock()
            time.sleep(Nr2 * dt)
            locked.send('_WRUnlock')
            mu.RUnlock()

    go(W)

    # spawn more readers to verify that Lock has priority over RLock
    time.sleep(1 * dt)  # give W more chance to call mu.Lock first
    for i in range(Nr2):
        go(R)

    # release main rlock, make sure nor W nor more R are yet ready, and let all readers continue
    time.sleep((1 + 1) * dt)
    mu.RUnlock()
    time.sleep(1 * dt)
    for i in range(100):
        _, _rx = select(
            default,  # 0
            locked.recv,  # 1
        )
        assert _ == 0
    rcont.close()

    # W must get the lock first and all R2 readers only after it
    assert locked.recv() == 'W'
    if not unlock_via_downgrade:
        assert locked.recv() == '_WUnlock'
    else:
        assert locked.recv() == '_WUnlockToRLock'
    for i in range(Nr2):
        assert locked.recv() == ('R', 1)
    if unlock_via_downgrade:
        assert locked.recv() == '_WRUnlock'