Giter Club home page Giter Club logo

libmill's People

Contributors

acornejo avatar amitsaha avatar antonmes avatar banks avatar cooloppo avatar duncaen avatar ebfe avatar fourcube avatar isaachier avatar jfsmig avatar jimjag avatar johneh avatar mato avatar millerlogic avatar mobiliodevelopment avatar msteinert avatar nirs avatar nxtreaming avatar pandora-jshimpf avatar paulofaria avatar raedwulf avatar redxu avatar reqshark avatar sustrik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libmill's Issues

tests/tcp hangs on FreeBSD

tests/tcp hangs forever in poll() on FreeBSD.

truss output:

...
socket(PF_INET,SOCK_STREAM,0)                    = 3 (0x3)
fcntl(3,F_GETFL,)                                = 2 (0x2)
fcntl(3,F_SETFL,O_NONBLOCK|0x2)                  = 0 (0x0)
setsockopt(0x3,0xffff,0x4,0x7fffffffe78c,0x4,0xfffffff4) = 0 (0x0)
setsockopt(0x3,0xffff,0x800,0x7fffffffe78c,0x4,0xfffffff4) = 0 (0x0)
bind(3,{ AF_INET 0.0.0.0:5555 },16)              = 0 (0x0)
listen(0x3,0xa,0x10,0x7fffffffe78c,0x4,0xfffffff4) = 0 (0x0)
sigprocmask(SIG_BLOCK,0x0,0x0)                   = 0 (0x0)
socket(PF_INET,SOCK_STREAM,0)                    = 4 (0x4)
fcntl(4,F_GETFL,)                                = 2 (0x2)
fcntl(4,F_SETFL,O_NONBLOCK|0x2)                  = 0 (0x0)
setsockopt(0x4,0xffff,0x4,0x801857c7c,0x4,0x800fd5e80) = 0 (0x0)
setsockopt(0x4,0xffff,0x800,0x801857c7c,0x4,0x800fd5e80) = 0 (0x0)
connect(4,{ AF_INET 255.127.0.0:5555 },16)       ERR#36 'Operation now in progress'
sigprocmask(SIG_BLOCK,0x0,0x0)                   = 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0)                 = 0 (0x0)
accept(3,0x0,0x0)                                ERR#35 'Resource temporarily unavailable'
sigprocmask(SIG_BLOCK,0x0,0x0)                   = 0 (0x0)
poll({4/POLLOUT 3/POLLIN},2,-1)                  ERR#4 'Interrupted system call'

The following patch makes the test pass:

diff --git a/tests/tcp.c b/tests/tcp.c
index d30d75c..6f75d36 100644
--- a/tests/tcp.c
+++ b/tests/tcp.c
@@ -28,6 +28,7 @@
 #include "../libmill.h"

 void client(int port) {
+    msleep(now()+100);
     tcpsock cs = tcpconnect("127.0.0.1", port, -1);
     assert(cs);

I guess these connect/accept should be synchronized in some way.

Provide a way to avoid name clashes

libmill uses rather generic keywords like 'in' or 'choose'. It may happen that user would want to integrate it with legacy code that's using those identifiers for other purposes.

libmill should define a macro that would switch all the libmill names to mill_-prefixed variants:

#define LIBMILL_USE_PREFIX
...
mill_choose {
mill_in(...

Segfault when corutine times out

  1. Build step6 of the tutorial on Fedora 20:

    gcc -o server step6.c -lmill

  2. Run server

  3. Connect two clients

  4. Wait until server times out and close the connection

  5. As soon as the first connection times out, server segfaults

$ gdb ./server 
GNU gdb (GDB) Fedora 7.7.1-21.fc20
...
Reading symbols from ./server...(no debugging symbols found)...done.
(gdb) run
Starting program: /home/nsoffer/src/libmill/tutorial/server 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Total number of connections: 1
Active connections: 1
Failed connections: 0

Total number of connections: 2
Active connections: 2
Failed connections: 0

Total number of connections: 2
Active connections: 1
Failed connections: 1


Program received signal SIGSEGV, Segmentation fault.
0x000000305fa10c78 in ?? () from /lib64/libc.so.6
(gdb) bt full
#0  0x000000305fa10c78 in ?? () from /lib64/libc.so.6
No symbol table info available.
#1  0x000000305f6092b9 in check_match (sym=0x7ffff7d84b04) at dl-lookup.c:149
        stt = <optimized out>
        verstab = <optimized out>
        type_class = 32767
        ref = 0x700000001
        strtab = 0x0
        undef_name = 0x0
        map = 0xffffffff00000001
        version = 0x600000000
        symidx = 4158409904
        flags = -1
        num_versions = 1
        versioned_sym = 0x4
#2  0x000000305f609acb in do_lookup_x (new_hash=new_hash@entry=294296705, old_hash=old_hash@entry=0x7ffff7d84c00, result=result@entry=0x7ffff7d84c10, scope=<optimized out>, 
    i=<optimized out>, i@entry=0, flags=1, flags@entry=-8096, skip=skip@entry=0x0, undef_map=undef_map@entry=0x305f821168) at dl-lookup.c:249
        hasharr = 0x7ffff7dc92b4
        bucket = <optimized out>
        bitmask_word = <optimized out>
        hashbit1 = 1
        hashbit2 = <optimized out>
        symtab = 0x7ffff7dc9350
        sym = <optimized out>
        bitmask = <optimized out>
        n = 6
        list = 0x0
        num_versions = 0
        versioned_sym = 0x0
        map = 0x7ffff7ffa660
        type_class = 1
        undef_name = 0x40060f "mill_go_epilogue"
        strtab = 0x7ffff7dc9b00 ""
        symidx = 44
        ref = 0x4004e8
        version = 0x0
#3  0x000000305f609daf in _dl_lookup_symbol_x (undef_name=0x40060f "mill_go_epilogue", undef_map=0x305f821168, ref=0x7ffff7d84cc8, symbol_scope=0x305f8214c0, version=0x0, 
    type_class=1, flags=-8096, skip_map=0x0) at dl-lookup.c:737
        res = <optimized out>
        start = 0
        new_hash = 294296705
---Type <return> to continue, or q <return> to quit---
        old_hash = 4294967295
        current_value = {s = 0x7ffff7dc9770, m = 0x7ffff7ffa660}
        scope = 0x305f8214c0
        i = 0
        protected = <optimized out>
#4  0x0000000000000001 in ?? ()
No symbol table info available.
#5  0x00007fffffffe060 in ?? ()
No symbol table info available.
#6  0x0000000000000000 in ?? ()
No symbol table info available.

Channels in C

Hi,

Firstly i'm sorry if it's a stupid question, i haven't programmed in C in quite a long time.
So, Mill looks interesting as a lightweight alternative to Go for concurrent software. But go has channels for communication between coroutines, and those seem like a useful thing.

I was wondering if you have seen the C implementation of channels at (https://github.com/tylertreat/chan). And have you tried to use them together.

I was also wondering if it would be possible to make some syntactic sugar for those using the code generation lib you made. (something like c <- value). Sort of poor man's Go as a library, without the GC.

Thanks

Consider (optional) stack overflow protection

Can be done like this:

static void *mill_alloc(size_t sz) {
     int pagesize = sysconf(_SC_PAGE_SIZE);
     assert(pagesize > 0);
     void *p;
     int rc = posix_memalign(&p, pagesize, pagesize + sz);
     assert(rc == 0);
     rc = mprotect(p, 1, PROT_READ | PROT_WRITE | PROT_EXEC);
     assert(rc == 0);
     return ((char*)p) + pagesize;
}

static void mill_free(void *p) {
    int pagesize = sysconf(_SC_PAGE_SIZE);
    assert(pagesize > 0);
    free(((char*)p) - pagesize);
}

void *mill_allocstack(void) {
    if(!mill_slist_empty(&mill_cached_stacks))
        return (void*)(mill_slist_pop(&mill_cached_stacks) + 1);
    char *ptr = mill_alloc(MILL_STACK_SIZE);
    assert(ptr);
    return ptr + MILL_STACK_SIZE; 
}

void mill_freestack(void *stack) {
    if(mill_num_cached_stacks >= MILL_MAX_CACHED_STACKS) {
        char *ptr = ((char*)stack) - MILL_STACK_SIZE;
        mill_free(ptr);
        return;
    }
    struct mill_slist_item *item = ((struct mill_slist_item*)stack) - 1;
    mill_slist_push(&mill_cached_stacks, item);
    ++mill_num_cached_stacks;
}

channel value destructor

I'd like to be able to pass a complex object via pointer across a channel and have it be freed after it is no longer needed (e.g. after it is read, or if the channel is closed before it is read). I think all that's needed to solve this is for the app to be able to pass a destructor function when sending a value, which libmill can call when it is done with the value.

global hang up

Runing this script simulating concurrent using turorial/step6 in expected way:

import socket
import time

def connect():
    s = socket.socket()
    s.connect(("127.0.0.1", 5555))
    return s

while 1:
    connections = [connect() for _ in range(10)]                                                                                                                                
    for s in connections:
        s.recv(100)
    for s in connections:
        s.sendall("Name\r\n")
    for s in connections:
        s.recv(100)
    for s in connections:
        s.close()

tutorial/step6 hang up after 20 connections, when the last connection is closed.

$ tutorial/step6
Total number of connections: 1
Active connections: 1
Failed connections: 0

Total number of connections: 2
Active connections: 2
Failed connections: 0

Total number of connections: 3
Active connections: 3
Failed connections: 0

Total number of connections: 4
Active connections: 4
Failed connections: 0

Total number of connections: 5
Active connections: 5
Failed connections: 0

Total number of connections: 6
Active connections: 6
Failed connections: 0

Total number of connections: 7
Active connections: 7
Failed connections: 0

Total number of connections: 8
Active connections: 8
Failed connections: 0

Total number of connections: 9
Active connections: 9
Failed connections: 0

Total number of connections: 10
Active connections: 10
Failed connections: 0

Total number of connections: 10
Active connections: 9
Failed connections: 0

Total number of connections: 10
Active connections: 8
Failed connections: 0

Total number of connections: 10
Active connections: 7
Failed connections: 0

Total number of connections: 10
Active connections: 6
Failed connections: 0

Total number of connections: 10
Active connections: 5
Failed connections: 0

Total number of connections: 10
Active connections: 4
Failed connections: 0

Total number of connections: 10
Active connections: 3
Failed connections: 0

Total number of connections: 10
Active connections: 2
Failed connections: 0

Total number of connections: 10
Active connections: 1
Failed connections: 0

Total number of connections: 10
Active connections: 0
Failed connections: 0

Total number of connections: 11
Active connections: 1
Failed connections: 0

Total number of connections: 12
Active connections: 2
Failed connections: 0

Total number of connections: 13
Active connections: 3
Failed connections: 0

Total number of connections: 14
Active connections: 4
Failed connections: 0

Total number of connections: 15
Active connections: 5
Failed connections: 0

Total number of connections: 16
Active connections: 6
Failed connections: 0

Total number of connections: 17
Active connections: 7
Failed connections: 0

Total number of connections: 18
Active connections: 8
Failed connections: 0

Total number of connections: 19
Active connections: 9
Failed connections: 0

panic: global hang-up

I replaced the mill_panic() with mill_assert() so we can inspect the process state when it panics:

Total number of connections: 114
Active connections: 4
Failed connections: 0

Total number of connections: 115
Active connections: 5
Failed connections: 0

Total number of connections: 116
Active connections: 6
Failed connections: 0

Total number of connections: 117
Active connections: 7
Failed connections: 0

Total number of connections: 118
Active connections: 8
Failed connections: 0

Total number of connections: 119
Active connections: 9
Failed connections: 0

Assert failed: 0 (poller.c:160)

Program received signal SIGABRT, Aborted.
0x000000305fa35877 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56    return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
(gdb) p goredump()

COROUTINE  state                                      current                                  created
------------------------------------------------------------------------------------------------------------------------
{0}        fdwait(-1)                                 tcp.c:178                                <main>
{1}        ready                                      tutorial/step6.c:41                      tutorial/step6.c:105
{112}      chs(<1>)                                   tutorial/step6.c:86                      tutorial/step6.c:111
{113}      chs(<1>)                                   tutorial/step6.c:86                      tutorial/step6.c:111
{114}      chs(<1>)                                   tutorial/step6.c:86                      tutorial/step6.c:111
{115}      chs(<1>)                                   tutorial/step6.c:86                      tutorial/step6.c:111
{116}      chs(<1>)                                   tutorial/step6.c:86                      tutorial/step6.c:111
{117}      chs(<1>)                                   tutorial/step6.c:86                      tutorial/step6.c:111
{118}      chs(<1>)                                   tutorial/step6.c:86                      tutorial/step6.c:111
{119}      chs(<1>)                                   tutorial/step6.c:86                      tutorial/step6.c:111
{120}      chs(<1>)                                   tutorial/step6.c:86                      tutorial/step6.c:111
{121}      chs(<1>)                                   ---                                      tutorial/step6.c:111

CHANNEL  msgs/max    senders/receivers                          refs  done  created
------------------------------------------------------------------------------------------------------------------------
<1>      0/0         s:{112},{113},{114},{115},{116},{117},{118},{119},{120},{121} 1     no    tutorial/step6.c:104

$1 = void
(gdb) p *mill_running
$2 = {state = MILL_CHS, u_ready = {item = {next = 0x0}}, u_fdwait = {item = {next = 0x0, prev = 0x0}, expiry = 128496030}, u_choose = {clauses = {first = 0x7ffff7e4bab0, 
      last = 0x7ffff7e4bab0}, othws = 0, available = 0}, ctx = {jbuf = {{__jmpbuf = {140737488346752, 6321267569117360643, 4198560, 140737488347248, 0, 0, 
          6321267569111069187, -6321285767971081725}, __mask_was_saved = 0, __saved_mask = {__val = {0 <repeats 16 times>}}}}}, valbuf = {ptr = 0x0, capacity = 128, 
    buf = '\000' <repeats 127 times>}, result = 1, cls = 0x0, debug = {item = {next = 0x0, prev = 0x7ffff7d8bee8}, id = 121, created = 0x40573c "tutorial/step6.c:111", 
    current = 0x4056ce "tutorial/step6.c:86"}}

default formatting

Also, we should consider adding a .clang-format file. These can be auto generated. My recommendation is pick one that doesn't mess up the blame too much, and require PRs run all code through it before committing.

chs, chr incorrect order

This code:

#include "libmill.h"

void foo(chan channel) {

    chs(channel, int, 2);
    chs(channel, int, 3);

}

void main() {

    chan channel = chmake(int, 1);
    chs(channel, int, 1);

    go(foo(channel));

    msleep(now() + 100);
    printf("received %i\n", chr(channel, int));
    msleep(now() + 100);
    printf("received %i\n", chr(channel, int));
    msleep(now() + 100);
    printf("received %i\n", chr(channel, int));

}

Prints this:

received 2
received 3
received 1

I believe it should print:

received 1
received 2
received 3

cmake build broken

...
[ 91%] Linking C executable tests/tcp
libmill.a(ip.c.o): In function `ipremote':
ip.c:(.text+0xc3f): undefined reference to `getaddrinfo_a'
ip.c:(.text+0xd0b): undefined reference to `gai_cancel'
ip.c:(.text+0xd88): undefined reference to `gai_error'
collect2: error: ld returned 1 exit status
CMakeFiles/test_tcp.dir/build.make:95: recipe for target 'tests/tcp' failed
make[2]: *** [tests/tcp] Error 1
CMakeFiles/Makefile2:696: recipe for target 'CMakeFiles/test_tcp.dir/all' failed
make[1]: *** [CMakeFiles/test_tcp.dir/all] Error 2
Makefile:94: recipe for target 'all' failed
make: *** [all] Error 2

I guess -lanl is missing from the linker flags. Not sure where/how to add it.

How to resume a coroutine from application code?

Sorry this is more like a question than a bug report but I couldn't find any example of how to do this. I believe calls like tcprecv(), tcpflush() and fdwait() internally yield coroutine when they are about to block and resume it when the socket is ready (using epoll etc.?). But if I explicitly call yield() from my coroutine how can my application code resume that specific coroutine later? Is there anything like a coroutine handle returned by go() call that can be stored and used later to resume the coroutine?

Use monotonic clock

This is to ensure that deadlines work consistently even in face of daylight changes, timezone shifts and such.

tcpattach/unixattach api

Maybe {tcp,unix}attach should take another argument to indicate wether the given fd is listening or not. The autodetection seems to only work on Linux and FreeBSD and I'm not sure if there is really a usecase where you want to attach to an fd and don't know wether it is a listening or connected socket.

Segfault when client disconnect in fdwait

Running this Python script on debug build against tutorial/step6, running in gdb.

import socket
import time

def connect():
    s = socket.socket()
    s.connect(("127.0.0.1", 5555))
    return s

while 1:                                                                                                                                                                        
    connections = [connect() for _ in range(10)]
    for s in connections:
        s.recv(100)
    for s in connections:
        s.close()
==> 01:28:43.240256 {1}      chr(<1>) at tutorial/step6.c:41
==> 01:28:43.240271 {11}     chs(<1>) at tutorial/step6.c:88
==> 01:28:43.240283 {10}     chs(<1>) at tutorial/step6.c:88
==> 01:28:43.240293 {9}      chs(<1>) at tutorial/step6.c:88
==> 01:28:43.240304 {8}      chs(<1>) at tutorial/step6.c:88
==> 01:28:43.240314 {7}      chs(<1>) at tutorial/step6.c:88
Total number of connections: 10
Active connections: 4
Failed connections: 6

==> 01:28:43.240328 {1}      chr(<1>) at tutorial/step6.c:41
==> 01:28:43.240376 {11}     go() done
==> 01:28:43.240397 {10}     go() done
Total number of connections: 10
Active connections: 3
Failed connections: 7

==> 01:28:43.240406 {1}      chr(<1>) at tutorial/step6.c:41
==> 01:28:43.240425 {9}      go() done
Total number of connections: 10
Active connections: 2
Failed connections: 8

==> 01:28:43.240459 {1}      chr(<1>) at tutorial/step6.c:41
==> 01:28:43.240499 {8}      go() done
Total number of connections: 10
Active connections: 1
Failed connections: 9

==> 01:28:43.240516 {1}      chr(<1>) at tutorial/step6.c:41
==> 01:28:43.240555 {7}      go() done
Total number of connections: 10
Active connections: 0
Failed connections: 10

==> 01:28:43.240574 {1}      chr(<1>) at tutorial/step6.c:41

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) p goredump()

COROUTINE  state                                      current                                  created
------------------------------------------------------------------------------------------------------------------------
{0}        fdwait(-1)                                 tcp.c:178                                <main>
{1}        chr(<1>)                                   tutorial/step6.c:41                      tutorial/step6.c:105

CHANNEL  msgs/max    senders/receivers                          refs  done  created
------------------------------------------------------------------------------------------------------------------------
<1>      0/0         r:{1}                                      1     no    tutorial/step6.c:104

$1 = void
(gdb) list
84      cleanup:
85      if(errno == 0)
86          chs(ch, int, CONN_SUCCEEDED);
87      else
88          chs(ch, int, CONN_FAILED);
89      tcpclose(as);
90  }
91  
92  int main(int argc, char *argv[]) {
93      gotrace(1);
(gdb) bt
#0  0x0000000000000000 in ?? ()
#1  0x00007ffff7e4bd20 in ?? ()
#2  0x000000305fa51a47 in __fprintf (stream=<optimized out>, format=<optimized out>) at fprintf.c:32
#3  0x0000000000403114 in mill_trace_ (location=<error reading variable: Cannot access memory at address 0xfffffffffffffe08>, 
    format=<error reading variable: Cannot access memory at address 0xfffffffffffffe00>) at debug.c:225
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

Will it support this goroutine scheduler feature: auto start another available goroutime when the current goroutine is blocked?

To test benchmark of libmill, I write this libmill version echo server demo to compare with other echoserver:

// server_libmill.c
#include <libmill.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void echoserver(tcpsock as)
{
    char buf[256] = {0};
    size_t sz;

    for (;;) {
        sz = tcprecvuntil(as, buf, sizeof(buf), "\n", 1, -1);
        if (sz <= 0)
            break;
        sz = tcpsend(as, buf, sz, -1);
        tcpflush(as, -1);
    }
    tcpclose(as);
}

int main(int argc, char **argv)
{
    int port = 5000;
    if (argc > 1)
        port = atoi(argv[1]);

    ipaddr addr = iplocal(NULL, port, 0);
    tcpsock ls = tcplisten(addr, 10);
    if (!ls) {
        perror("Can't open listening socket");
        return 1;
    }
    while (1) {
        tcpsock as = tcpaccept(ls, -1);
        if (!as)
            continue;
        go(echoserver(as));
    }
    return 0;
}

Client is here.

Test command:

$ ./server_libmill
$ ./client -p 5000 -c10 -o2 -h10000 localhost
Throughput: 106289.58 [#/sec]

and the Golang version result:

$ ./server_go
$ ./client -p 5000 -c10 -o2 -h10000 localhost
Throughput: 106140.64 [#/sec]

It can see that libmill has awesome performance :)

Then I add the usleep() line to simulate the blocking:

// server_libmill.c
#include <libmill.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void echoserver(tcpsock as)
{
    char buf[256] = {0};
    size_t sz;

    for (;;) {
        sz = tcprecvuntil(as, buf, sizeof(buf), "\n", 1, -1);
        if (sz <= 0)
            break;
    // msleep(10); // it is fast, but trick, no blocking~
    usleep(10000);
        sz = tcpsend(as, buf, sz, -1);
        tcpflush(as, -1);
    }
    tcpclose(as);
}

int main(int argc, char **argv)
{
    int port = 5000;
    if (argc > 1)
        port = atoi(argv[1]);

    ipaddr addr = iplocal(NULL, port, 0);
    tcpsock ls = tcplisten(addr, 10);
    if (!ls) {
        perror("Can't open listening socket");
        return 1;
    }
    while (1) {
        tcpsock as = tcpaccept(ls, -1);
        if (!as)
            continue;
        go(echoserver(as));
    }
    return 0;
}

And the Go version:

package main

import (
    "io"
    "log"
    "net"
    "time"
)

func echo_handler(conn net.Conn) {
    defer conn.Close()
    time.Sleep(10 * time.Millisecond)
    io.Copy(conn, conn)
}

func main() {
    psock, e := net.Listen("tcp", ":5000")
    if e != nil {
        log.Fatal(e)
        return
    }
    for {
        conn, e := psock.Accept()
        if e != nil {
            log.Fatal(e)
            return
        }
        go echo_handler(conn)
    }
}

Now the performance of server_libmill drops like most version of echoserver(e.g., server_epoll.cpp, server_thread.cpp, server_erlang.erl, server_haskell.hs):

$ ./client -p 5000 -c10 -o2 -h100 localhost 
Throughput: 92.74 [#/sec]

But the performance of server_go influenced tiny:

$ ./client -p 5000 -c10 -o2 -h10000 localhost
Throughput: 105174.19 [#/sec]

Will libmill support this goroutine scheduler feature in future?

I think this link may be useful: http://www.quora.com/Go-programming-language/What-happens-when-a-goroutine-blocks

Core dump

Under OSX, the following test results in a core-dump BUT the test itself appears to PASS:

Process: chan [16616]
Path: /Users/USER/*/chan
Identifier: chan
Version: 0
Code Type: X86-64 (Native)
Parent Process: chan [16602]
Responsible: iTerm [421]
User ID: 501

Date/Time: 2015-09-10 10:47:53.999 -0400
OS Version: Mac OS X 10.10.5 (14F27)
Report Version: 11
Anonymous UUID: D833ECC0-5E70-9179-BE00-CCBECD4DDFB6

Time Awake Since Boot: 260000 seconds

Crashed Thread: 0 Dispatch queue: com.apple.main-thread

Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000

Application Specific Information:
crashed on child side of fork pre-exec

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x00007fff8fe54286 __pthread_kill + 10
1 libsystem_c.dylib 0x00007fff896f19b3 abort + 129
2 libmill.7.dylib 0x000000010be130d7 mill_panic + 39
3 libmill.7.dylib 0x000000010be10a1b mill_wait + 59 (poller.c:162)
4 libmill.7.dylib 0x000000010be0f356 mill_suspend + 102 (cr.c:112)
5 libmill.7.dylib 0x000000010be0efca mill_chs + 138 (chan.c:322)
6 chan 0x000000010be07597 main + 4711 (chan.c:205)
7 libdyld.dylib 0x00007fff8bbd45c9 start + 1

/Applications/Xcode.app/Contents/Developer/usr/bin/make check-TESTS
PASS: tests/example
PASS: tests/go
PASS: tests/cls
PASS: tests/chan
PASS: tests/choose
PASS: tests/sleep
PASS: tests/fdwait
PASS: tests/tcp
PASS: tests/udp
PASS: tests/unix
PASS: tests/signals

PASS: tests/overload

Testsuite summary for libmill 0.10-beta-241-g9be57bf

TOTAL: 12

PASS: 12

SKIP: 0

XFAIL: 0

FAIL: 0

XPASS: 0

ERROR: 0

segmentation fault

Hi Martin,
I just downloaded and installed 0.7 and I am getting a segmentation fault when I run the example in tests. I am on a MacOS. Any advice?
Thanks,
-Isam

Consider using file descriptors as clauses in choose{}

This is a far-fetched idea, but I am documenting it here so that it's not forgot:

choose {
tcprecv(s, buf, sz):
    ...
msleep(now() + 1000):
   ...
in(ch, int, val):
   ...
}

The problems:

  • unlike channels, fd-based operations can return errors
  • requires unlimited number of clause types: tcp, udp, unix et c.
  • inconsistent with Golang

avoid assert from assert.h

we should also take a look at the use of assert throughout the code base, since configuring with cmake -DCMAKE_BUILD_TYPE=Release .. for optimized builds will use the -NDEBUG flag which will remove the expressions within assert statements entirely. That, or possibly force cmake to not build with that flag for the tests at least.

The problem with assert from assert.h is that they're meant to be removed with -NDEBUG. It would be preferable to have an assert macro that either checked the return code or didn't based on symbol definition at compile time, not whether to execute code and test or not at all.

signal problem on solaris

I've been able to compile and run libmill on ancient solaris version running on ancient SPARC box:

SunOS 5.10 Generic_141414-10 sun4u sparc SUNW,Sun-Blade-100

The only problem seem to be signals used in two tests (chan, signals). Those two tests fail in weird ways.

0.18-rc: "redeclaration of โ€˜ptrโ€™ with no linkage" compile time error

[ 14%] Building C object CMakeFiles/mill.dir/stack.c.o
/home/constantine/Desktop/libmill/stack.c: In function โ€˜mill_allocstackmemโ€™:
/home/constantine/Desktop/libmill/stack.c:100:11: error: redeclaration of โ€˜ptrโ€™ with no linkage
     void *ptr = malloc(mill_get_stack_size());
           ^
/home/constantine/Desktop/libmill/stack.c:82:11: note: previous declaration of โ€˜ptrโ€™ was here
     void *ptr;
           ^
make[2]: *** [CMakeFiles/mill.dir/stack.c.o] Error 1
make[1]: *** [CMakeFiles/mill.dir/all] Error 2
make: *** [all] Error 2

Makefile was generated from CMake.

Missing anl library

When trying to compile a test by hand:

sustrik@sustrik-glaptop:~/libmill/tests$ gcc -o tcp tcp.c -lmill
//usr/local/lib/libmill.a(libmill_la-ip.o): In function `ipremote':
/home/sustrik/libmill/ip.c:262: undefined reference to `getaddrinfo_a'
/home/sustrik/libmill/ip.c:273: undefined reference to `gai_cancel'
/home/sustrik/libmill/ip.c:278: undefined reference to `gai_error'

Why isn't anl library dragged in automatically? (adding -lanl helps)

Assert failed: res & FDW_IN (tcp.c:390)

Running following script with tutorial/step6, cause reproducible crash.

Configured with --enable-debug --disable-shared.

Tested with 430c295

import socket
import time

COUNT = 100                                                                                                                                                                     

def connect():
    s = socket.socket()
    s.connect(("127.0.0.1", 5555))
    return s

while 1:
    connections = [connect() for _ in range(COUNT)]
    time.sleep(1)
    for s in connections:
        s.close()
$ tutorial/step6
Total number of connections: 1
Active connections: 1
Failed connections: 0

Total number of connections: 2
Active connections: 2
Failed connections: 0

Total number of connections: 3
Active connections: 3
Failed connections: 0

Total number of connections: 4
Active connections: 4
Failed connections: 0

Total number of connections: 5
Active connections: 5
Failed connections: 0

Total number of connections: 6
Active connections: 6
Failed connections: 0

Total number of connections: 7
Active connections: 7
Failed connections: 0

Total number of connections: 8
Active connections: 8
Failed connections: 0

Total number of connections: 9
Active connections: 9
Failed connections: 0

Total number of connections: 10
Active connections: 10
Failed connections: 0

Total number of connections: 11
Active connections: 11
Failed connections: 0

Total number of connections: 12
Active connections: 12
Failed connections: 0

Total number of connections: 13
Active connections: 13
Failed connections: 0

Total number of connections: 14
Active connections: 14
Failed connections: 0

Total number of connections: 15
Active connections: 15
Failed connections: 0

Total number of connections: 16
Active connections: 16
Failed connections: 0

Total number of connections: 17
Active connections: 17
Failed connections: 0

Total number of connections: 18
Active connections: 18
Failed connections: 0

Total number of connections: 19
Active connections: 19
Failed connections: 0

Total number of connections: 20
Active connections: 20
Failed connections: 0

Total number of connections: 21
Active connections: 21
Failed connections: 0

Total number of connections: 22
Active connections: 22
Failed connections: 0

Total number of connections: 23
Active connections: 23
Failed connections: 0

Total number of connections: 24
Active connections: 24
Failed connections: 0

Total number of connections: 25
Active connections: 25
Failed connections: 0

Total number of connections: 26
Active connections: 26
Failed connections: 0

Total number of connections: 27
Active connections: 27
Failed connections: 0

Total number of connections: 28
Active connections: 28
Failed connections: 0

Total number of connections: 29
Active connections: 29
Failed connections: 0

Total number of connections: 30
Active connections: 30
Failed connections: 0

Total number of connections: 31
Active connections: 31
Failed connections: 0

Total number of connections: 32
Active connections: 32
Failed connections: 0

Total number of connections: 33
Active connections: 33
Failed connections: 0

Total number of connections: 34
Active connections: 34
Failed connections: 0

Total number of connections: 35
Active connections: 35
Failed connections: 0

Total number of connections: 36
Active connections: 36
Failed connections: 0

Total number of connections: 37
Active connections: 37
Failed connections: 0

Total number of connections: 38
Active connections: 38
Failed connections: 0

Total number of connections: 39
Active connections: 39
Failed connections: 0

Total number of connections: 40
Active connections: 40
Failed connections: 0

Total number of connections: 41
Active connections: 41
Failed connections: 0

Total number of connections: 42
Active connections: 42
Failed connections: 0

Total number of connections: 43
Active connections: 43
Failed connections: 0

Total number of connections: 44
Active connections: 44
Failed connections: 0

Total number of connections: 45
Active connections: 45
Failed connections: 0

Total number of connections: 46
Active connections: 46
Failed connections: 0

Total number of connections: 47
Active connections: 47
Failed connections: 0

Total number of connections: 48
Active connections: 48
Failed connections: 0

Total number of connections: 49
Active connections: 49
Failed connections: 0

Total number of connections: 50
Active connections: 50
Failed connections: 0

Total number of connections: 51
Active connections: 51
Failed connections: 0

Total number of connections: 52
Active connections: 52
Failed connections: 0

Total number of connections: 53
Active connections: 53
Failed connections: 0

Total number of connections: 54
Active connections: 54
Failed connections: 0

Total number of connections: 55
Active connections: 55
Failed connections: 0

Total number of connections: 56
Active connections: 56
Failed connections: 0

Total number of connections: 57
Active connections: 57
Failed connections: 0

Total number of connections: 58
Active connections: 58
Failed connections: 0

Total number of connections: 59
Active connections: 59
Failed connections: 0

Total number of connections: 60
Active connections: 60
Failed connections: 0

Total number of connections: 61
Active connections: 61
Failed connections: 0

Total number of connections: 62
Active connections: 62
Failed connections: 0

Total number of connections: 63
Active connections: 63
Failed connections: 0

Total number of connections: 64
Active connections: 64
Failed connections: 0

Total number of connections: 65
Active connections: 65
Failed connections: 0

Total number of connections: 66
Active connections: 66
Failed connections: 0

Total number of connections: 67
Active connections: 67
Failed connections: 0

Total number of connections: 68
Active connections: 68
Failed connections: 0

Total number of connections: 69
Active connections: 69
Failed connections: 0

Total number of connections: 70
Active connections: 70
Failed connections: 0

Total number of connections: 71
Active connections: 71
Failed connections: 0

Total number of connections: 72
Active connections: 72
Failed connections: 0

Total number of connections: 73
Active connections: 73
Failed connections: 0

Total number of connections: 74
Active connections: 74
Failed connections: 0

Total number of connections: 75
Active connections: 75
Failed connections: 0

Total number of connections: 76
Active connections: 76
Failed connections: 0

Total number of connections: 77
Active connections: 77
Failed connections: 0

Total number of connections: 78
Active connections: 78
Failed connections: 0

Total number of connections: 79
Active connections: 79
Failed connections: 0

Total number of connections: 80
Active connections: 80
Failed connections: 0

Total number of connections: 81
Active connections: 81
Failed connections: 0

Total number of connections: 82
Active connections: 82
Failed connections: 0

Total number of connections: 83
Active connections: 83
Failed connections: 0

Total number of connections: 84
Active connections: 84
Failed connections: 0

Total number of connections: 85
Active connections: 85
Failed connections: 0

Total number of connections: 86
Active connections: 86
Failed connections: 0

Total number of connections: 87
Active connections: 87
Failed connections: 0

Total number of connections: 88
Active connections: 88
Failed connections: 0

Total number of connections: 89
Active connections: 89
Failed connections: 0

Total number of connections: 90
Active connections: 90
Failed connections: 0

Total number of connections: 91
Active connections: 91
Failed connections: 0

Total number of connections: 92
Active connections: 92
Failed connections: 0

Total number of connections: 93
Active connections: 93
Failed connections: 0

Total number of connections: 94
Active connections: 94
Failed connections: 0

Total number of connections: 95
Active connections: 95
Failed connections: 0

Total number of connections: 96
Active connections: 96
Failed connections: 0

Total number of connections: 97
Active connections: 97
Failed connections: 0

Total number of connections: 98
Active connections: 98
Failed connections: 0

Total number of connections: 99
Active connections: 99
Failed connections: 0

Total number of connections: 100
Active connections: 100
Failed connections: 0

Total number of connections: 100
Active connections: 99
Failed connections: 1

Total number of connections: 100
Active connections: 98
Failed connections: 2

Total number of connections: 100
Active connections: 97
Failed connections: 3

Total number of connections: 100
Active connections: 96
Failed connections: 4

Total number of connections: 100
Active connections: 95
Failed connections: 5

Total number of connections: 100
Active connections: 94
Failed connections: 6

Total number of connections: 100
Active connections: 93
Failed connections: 7

Total number of connections: 100
Active connections: 92
Failed connections: 8

Total number of connections: 100
Active connections: 91
Failed connections: 9

Total number of connections: 100
Active connections: 90
Failed connections: 10

Total number of connections: 100
Active connections: 89
Failed connections: 11

Total number of connections: 100
Active connections: 88
Failed connections: 12

Total number of connections: 100
Active connections: 87
Failed connections: 13

Total number of connections: 100
Active connections: 86
Failed connections: 14

Total number of connections: 100
Active connections: 85
Failed connections: 15

Total number of connections: 100
Active connections: 84
Failed connections: 16

Total number of connections: 100
Active connections: 83
Failed connections: 17

Total number of connections: 100
Active connections: 82
Failed connections: 18

Total number of connections: 100
Active connections: 81
Failed connections: 19

Total number of connections: 100
Active connections: 80
Failed connections: 20

Total number of connections: 100
Active connections: 79
Failed connections: 21

Total number of connections: 100
Active connections: 78
Failed connections: 22

Total number of connections: 100
Active connections: 77
Failed connections: 23

Total number of connections: 100
Active connections: 76
Failed connections: 24

Total number of connections: 100
Active connections: 75
Failed connections: 25

Total number of connections: 100
Active connections: 74
Failed connections: 26

Total number of connections: 100
Active connections: 73
Failed connections: 27

Total number of connections: 100
Active connections: 72
Failed connections: 28

Total number of connections: 100
Active connections: 71
Failed connections: 29

Total number of connections: 100
Active connections: 70
Failed connections: 30

Total number of connections: 100
Active connections: 69
Failed connections: 31

Total number of connections: 100
Active connections: 68
Failed connections: 32

Total number of connections: 100
Active connections: 67
Failed connections: 33

Total number of connections: 100
Active connections: 66
Failed connections: 34

Total number of connections: 100
Active connections: 65
Failed connections: 35

Total number of connections: 100
Active connections: 64
Failed connections: 36

Total number of connections: 100
Active connections: 63
Failed connections: 37

Total number of connections: 100
Active connections: 62
Failed connections: 38

Total number of connections: 100
Active connections: 61
Failed connections: 39

Total number of connections: 100
Active connections: 60
Failed connections: 40

Total number of connections: 100
Active connections: 59
Failed connections: 41

Total number of connections: 100
Active connections: 58
Failed connections: 42

Total number of connections: 100
Active connections: 57
Failed connections: 43

Total number of connections: 100
Active connections: 56
Failed connections: 44

Total number of connections: 100
Active connections: 55
Failed connections: 45

Total number of connections: 100
Active connections: 54
Failed connections: 46

Total number of connections: 100
Active connections: 53
Failed connections: 47

Total number of connections: 100
Active connections: 52
Failed connections: 48

Total number of connections: 100
Active connections: 51
Failed connections: 49

Total number of connections: 100
Active connections: 50
Failed connections: 50

Total number of connections: 100
Active connections: 49
Failed connections: 51

Total number of connections: 100
Active connections: 48
Failed connections: 52

Total number of connections: 100
Active connections: 47
Failed connections: 53

Total number of connections: 100
Active connections: 46
Failed connections: 54

Total number of connections: 100
Active connections: 45
Failed connections: 55

Total number of connections: 100
Active connections: 44
Failed connections: 56

Total number of connections: 100
Active connections: 43
Failed connections: 57

Total number of connections: 100
Active connections: 42
Failed connections: 58

Total number of connections: 100
Active connections: 41
Failed connections: 59

Total number of connections: 100
Active connections: 40
Failed connections: 60

Total number of connections: 100
Active connections: 39
Failed connections: 61

Total number of connections: 100
Active connections: 38
Failed connections: 62

Total number of connections: 100
Active connections: 37
Failed connections: 63

Total number of connections: 100
Active connections: 36
Failed connections: 64

Total number of connections: 100
Active connections: 35
Failed connections: 65

Total number of connections: 100
Active connections: 34
Failed connections: 66

Total number of connections: 100
Active connections: 33
Failed connections: 67

Total number of connections: 100
Active connections: 32
Failed connections: 68

Total number of connections: 100
Active connections: 31
Failed connections: 69

Total number of connections: 100
Active connections: 30
Failed connections: 70

Total number of connections: 100
Active connections: 29
Failed connections: 71

Total number of connections: 100
Active connections: 28
Failed connections: 72

Total number of connections: 100
Active connections: 27
Failed connections: 73

Total number of connections: 100
Active connections: 26
Failed connections: 74

Total number of connections: 100
Active connections: 25
Failed connections: 75

Total number of connections: 100
Active connections: 24
Failed connections: 76

Total number of connections: 100
Active connections: 23
Failed connections: 77

Total number of connections: 100
Active connections: 22
Failed connections: 78

Total number of connections: 100
Active connections: 21
Failed connections: 79

Total number of connections: 100
Active connections: 20
Failed connections: 80

Total number of connections: 100
Active connections: 19
Failed connections: 81

Total number of connections: 100
Active connections: 18
Failed connections: 82

Total number of connections: 100
Active connections: 17
Failed connections: 83

Total number of connections: 100
Active connections: 16
Failed connections: 84

Total number of connections: 100
Active connections: 15
Failed connections: 85

Total number of connections: 100
Active connections: 14
Failed connections: 86

Total number of connections: 100
Active connections: 13
Failed connections: 87

Total number of connections: 100
Active connections: 12
Failed connections: 88

Total number of connections: 100
Active connections: 11
Failed connections: 89

Total number of connections: 100
Active connections: 10
Failed connections: 90

Total number of connections: 100
Active connections: 9
Failed connections: 91

Total number of connections: 100
Active connections: 8
Failed connections: 92

Total number of connections: 100
Active connections: 7
Failed connections: 93

Total number of connections: 100
Active connections: 6
Failed connections: 94

Total number of connections: 100
Active connections: 5
Failed connections: 95

Total number of connections: 100
Active connections: 4
Failed connections: 96

Total number of connections: 100
Active connections: 3
Failed connections: 97

Total number of connections: 100
Active connections: 2
Failed connections: 98

Total number of connections: 100
Active connections: 1
Failed connections: 99

Total number of connections: 100
Active connections: 0
Failed connections: 100

Total number of connections: 101
Active connections: 1
Failed connections: 100

Total number of connections: 102
Active connections: 2
Failed connections: 100

Total number of connections: 103
Active connections: 3
Failed connections: 100

Total number of connections: 104
Active connections: 4
Failed connections: 100

Total number of connections: 105
Active connections: 5
Failed connections: 100

Total number of connections: 106
Active connections: 6
Failed connections: 100

Total number of connections: 107
Active connections: 7
Failed connections: 100

Total number of connections: 108
Active connections: 8
Failed connections: 100

Total number of connections: 109
Active connections: 9
Failed connections: 100

Total number of connections: 110
Active connections: 10
Failed connections: 100

Total number of connections: 111
Active connections: 11
Failed connections: 100

Total number of connections: 112
Active connections: 12
Failed connections: 100

Total number of connections: 113
Active connections: 13
Failed connections: 100

Total number of connections: 114
Active connections: 14
Failed connections: 100

Total number of connections: 115
Active connections: 15
Failed connections: 100

Total number of connections: 116
Active connections: 16
Failed connections: 100

Total number of connections: 117
Active connections: 17
Failed connections: 100

Total number of connections: 118
Active connections: 18
Failed connections: 100

Total number of connections: 119
Active connections: 19
Failed connections: 100

Total number of connections: 120
Active connections: 20
Failed connections: 100

Total number of connections: 121
Active connections: 21
Failed connections: 100

Total number of connections: 122
Active connections: 22
Failed connections: 100

Total number of connections: 123
Active connections: 23
Failed connections: 100

Total number of connections: 124
Active connections: 24
Failed connections: 100

Total number of connections: 125
Active connections: 25
Failed connections: 100

Total number of connections: 126
Active connections: 26
Failed connections: 100

Total number of connections: 127
Active connections: 27
Failed connections: 100

Total number of connections: 128
Active connections: 28
Failed connections: 100

Total number of connections: 129
Active connections: 29
Failed connections: 100

Total number of connections: 130
Active connections: 30
Failed connections: 100

Total number of connections: 131
Active connections: 31
Failed connections: 100

Total number of connections: 132
Active connections: 32
Failed connections: 100

Total number of connections: 133
Active connections: 33
Failed connections: 100

Total number of connections: 134
Active connections: 34
Failed connections: 100

Total number of connections: 135
Active connections: 35
Failed connections: 100

Total number of connections: 136
Active connections: 36
Failed connections: 100

Total number of connections: 137
Active connections: 37
Failed connections: 100

Total number of connections: 138
Active connections: 38
Failed connections: 100

Total number of connections: 139
Active connections: 39
Failed connections: 100

Total number of connections: 140
Active connections: 40
Failed connections: 100

Total number of connections: 141
Active connections: 41
Failed connections: 100

Total number of connections: 142
Active connections: 42
Failed connections: 100

Total number of connections: 143
Active connections: 43
Failed connections: 100

Total number of connections: 144
Active connections: 44
Failed connections: 100

Total number of connections: 145
Active connections: 45
Failed connections: 100

Total number of connections: 146
Active connections: 46
Failed connections: 100

Total number of connections: 147
Active connections: 47
Failed connections: 100

Total number of connections: 148
Active connections: 48
Failed connections: 100

Total number of connections: 149
Active connections: 49
Failed connections: 100

Total number of connections: 150
Active connections: 50
Failed connections: 100

Total number of connections: 151
Active connections: 51
Failed connections: 100

Total number of connections: 152
Active connections: 52
Failed connections: 100

Total number of connections: 153
Active connections: 53
Failed connections: 100

Total number of connections: 154
Active connections: 54
Failed connections: 100

Total number of connections: 155
Active connections: 55
Failed connections: 100

Total number of connections: 156
Active connections: 56
Failed connections: 100

Total number of connections: 157
Active connections: 57
Failed connections: 100

Total number of connections: 158
Active connections: 58
Failed connections: 100

Total number of connections: 159
Active connections: 59
Failed connections: 100

Total number of connections: 160
Active connections: 60
Failed connections: 100

Total number of connections: 161
Active connections: 61
Failed connections: 100

Total number of connections: 162
Active connections: 62
Failed connections: 100

Total number of connections: 163
Active connections: 63
Failed connections: 100

Total number of connections: 164
Active connections: 64
Failed connections: 100

Total number of connections: 165
Active connections: 65
Failed connections: 100

Total number of connections: 166
Active connections: 66
Failed connections: 100

Total number of connections: 167
Active connections: 67
Failed connections: 100

Total number of connections: 168
Active connections: 68
Failed connections: 100

Total number of connections: 169
Active connections: 69
Failed connections: 100

Total number of connections: 170
Active connections: 70
Failed connections: 100

Total number of connections: 171
Active connections: 71
Failed connections: 100

Total number of connections: 172
Active connections: 72
Failed connections: 100

Total number of connections: 173
Active connections: 73
Failed connections: 100

Total number of connections: 174
Active connections: 74
Failed connections: 100

Total number of connections: 175
Active connections: 75
Failed connections: 100

Total number of connections: 176
Active connections: 76
Failed connections: 100

Total number of connections: 177
Active connections: 77
Failed connections: 100

Total number of connections: 178
Active connections: 78
Failed connections: 100

Total number of connections: 179
Active connections: 79
Failed connections: 100

Total number of connections: 180
Active connections: 80
Failed connections: 100

Total number of connections: 181
Active connections: 81
Failed connections: 100

Total number of connections: 182
Active connections: 82
Failed connections: 100

Total number of connections: 183
Active connections: 83
Failed connections: 100

Total number of connections: 184
Active connections: 84
Failed connections: 100

Total number of connections: 185
Active connections: 85
Failed connections: 100

Total number of connections: 186
Active connections: 86
Failed connections: 100

Total number of connections: 187
Active connections: 87
Failed connections: 100

Total number of connections: 188
Active connections: 88
Failed connections: 100

Total number of connections: 189
Active connections: 89
Failed connections: 100

Total number of connections: 190
Active connections: 90
Failed connections: 100

Total number of connections: 191
Active connections: 91
Failed connections: 100

Total number of connections: 192
Active connections: 92
Failed connections: 100

Total number of connections: 193
Active connections: 93
Failed connections: 100

Total number of connections: 194
Active connections: 94
Failed connections: 100

Total number of connections: 195
Active connections: 95
Failed connections: 100

Total number of connections: 196
Active connections: 96
Failed connections: 100

Total number of connections: 197
Active connections: 97
Failed connections: 100

Total number of connections: 198
Active connections: 98
Failed connections: 100

Total number of connections: 199
Active connections: 99
Failed connections: 100

Total number of connections: 200
Active connections: 100
Failed connections: 100

Total number of connections: 200
Active connections: 99
Failed connections: 101

Total number of connections: 200
Active connections: 98
Failed connections: 102

Total number of connections: 200
Active connections: 97
Failed connections: 103

Total number of connections: 200
Active connections: 96
Failed connections: 104

Total number of connections: 200
Active connections: 95
Failed connections: 105

Total number of connections: 200
Active connections: 94
Failed connections: 106

Total number of connections: 200
Active connections: 93
Failed connections: 107

Total number of connections: 200
Active connections: 92
Failed connections: 108

Assert failed: res & FDW_IN (tcp.c:390)
Aborted (core dumped)
$ gdb -c core.27502 
GNU gdb (GDB) Fedora 7.7.1-21.fc20
...
[New LWP 27502]
Missing separate debuginfo for the main executable file
Try: yum --enablerepo='*debug*' install /usr/lib/debug/.build-id/56/a73ab86b669a4b30a79ab32f119b0fdd65528d
Core was generated by `tutorial/step6'.
Program terminated with signal SIGABRT, Aborted.
#0  0x000000305fa35877 in ?? ()
(gdb) bt
#0  0x000000305fa35877 in ?? ()
#1  0x000000305fa36f68 in ?? ()
#2  0x0000000000000020 in ?? ()
#3  0x0000000000000000 in ?? ()

time based tests are flaky

On a small arm system, most of the time based tests randomly fail

FAIL: tests/fdwait
==================

fdwait: tests/fdwait.c:87: main: Assertion `diff > 40 && diff < 60' failed.
FAIL tests/fdwait (exit status: 134)

FAIL: tests/tcp
===============

tcp: tests/tcp.c:77: main: Assertion `diff > -10 && diff < 10' failed.
FAIL tests/tcp (exit status: 134)

Not sure if the problem is the slow cpu or the low resolution of CLOCK_MONOTONIC (clock_getres reports 10ms). Switching to gettimeofday based now() does not help.

Do not abort from a library

I recommend never calling 'abort' or 'exit' from within library code, unless it is built in a Debug mode for testing.

https://github.com/sustrik/libmill/blob/master/utils.h#L74 is called from:
https://github.com/sustrik/libmill/blob/master/valbuf.c#L47

You undermine the behavior of programs using your library. Some programs may be running in critical or sensitive contexts and need to do some level of cleanup before exiting.

You should return an error instead and let the calling code handle that.

Failure with clang and -O2 optimisation level

Following error happens:

chan: chan.c:87: int main(): Assertion `val == 888' failed.
make: *** [test_chan] Aborted

The value is actually 999. Seems like there's some aggressive and possibly incorrect reordering going on.

Windows/MSVC support and on-flow ideas

Hi, love the library.
I've been playing around with porting it to windows under msvc.
The go function was fairly straight forward although I had to resort to assembly in the end. MSVC doesn't support VLAs, and things crashed if I tried alloca. I think it tries to write to the intervening memory. It ends up looking something like the following:

if defined _M_IX86

define mill_rax eax

define mill_rsp esp

elif defined _M_X64

define mill_rax rax

define mill_rsp rsp

elif defined _M_ARM

define mill_rax r0

define mill_rsp r15

endif

define go(fn) \

do {\
    void *mill_sp = mill_go_prologue();\
    if(mill_sp) {\
        __asm {mov mill_rax, mill_rsp}\
        __asm {mov mill_rsp, mill_sp}\
        __asm {push mill_rax}\
        fn;\
        __asm {pop mill_rsp}\
        mill_go_epilogue();\
    }\
} while(0)

For the choose statement I've taken a different approach. The choose implementation at the moment uses goto labels which is very specific to GCC. The approach I've been playing with looks like the following:

switch (choose(IN, ch1, IN, ch2, END)) {
case 0:
    printf("coroutine 'a(%d)' has finished first!\n", ch1->value);
    break;
case 1:
    printf("coroutine 'b(%d)' has finished first!\n", ch2->value);
    break;
}

choose is then a var arg function which takes an enum (IN, OUT, END, DEFAULT) channel pairs. The value can be accessed as channel->value, which works because the channels pointers are typed (see next). This approach also seems to drastically simplify the choose logic as it doesn't have to track the labels (e.g. I've removed the clause structure and the channel just tracks the list of continuations).

I've also been playing with having the channels be typed. I've played with this concept before with a containers library. To use a channel you would first have a call to DECL_CHAN(name, type) somewhere in the header. You can then use chan(name) as the channel type. For example:

DECL_CHAN(int, int);

void worker(int count, const char *text, chan(int) ch) {
int i;
for(i = 0; i != count; ++i) {
printf("%s\n", text);
musleep(10000);
}
chs(ch, count);
chclose(ch);
}

int main() {

chan(int) ch1 = chmake(int, 0);
go(worker(4, "a", chdup(ch1)));
chan(int) ch2 = chmake(int, 0);
go(worker(2, "b", chdup(ch2)));

switch (choose(IN, ch1, IN, ch2, END)) {
case 0:
    printf("coroutine 'a(%d)' has finished first!\n", ch1->value);
    break;
case 1:
    printf("coroutine 'b(%d)' has finished first!\n", ch2->value);
    break;
}

chclose(ch2);
chclose(ch1);

return 0;

}

Thoughts?

Unix sockets

Is there any interest in supporting unix sockets?

tcp/udp tests failing on FreeBSD

tcpsock ls = tcplisten(iplocal(NULL, 5555, 0)) results in a IPv6 only listening socket, but the tests assume IPv4.

    ipaddr addr = ipremote("127.0.0.1", port, 0, -1);
    tcpsock cs = tcpconnect(addr, -1);

The following patch fixes the tests, though I'm unsure if this is the right fix.

diff --git a/tests/tcp.c b/tests/tcp.c
index bb337fb..9a860f0 100644
--- a/tests/tcp.c
+++ b/tests/tcp.c
@@ -49,7 +49,7 @@ void client(int port) {
 int main() {
     char buf[16];

-    tcpsock ls = tcplisten(iplocal(NULL, 5555, 0));
+    tcpsock ls = tcplisten(iplocal(NULL, 5555, IPADDR_IPV4));
     assert(ls);

     go(client(tcpport(ls)));
diff --git a/tests/udp.c b/tests/udp.c
index 4ff0dd8..6517e09 100644
--- a/tests/udp.c
+++ b/tests/udp.c
@@ -29,8 +29,8 @@
 #include <stdio.h>

 int main() {
-    udpsock s1 = udplisten(iplocal(NULL, 5555, 0));
-    udpsock s2 = udplisten(iplocal(NULL, 5556, 0));
+    udpsock s1 = udplisten(iplocal(NULL, 5555, IPADDR_IPV4));
+    udpsock s2 = udplisten(iplocal(NULL, 5556, IPADDR_IPV4));

     ipaddr addr = ipremote("127.0.0.1", 5556, 0, -1);

Allow attaching listening sockets

In tcpattach() and unixattach(), SO_ACCEPTCONN should be checked to find out whether socket is listening. If so, listener socket should be created.

Segfault on master (commit: 4d3e3e021ae4420d2a7d7b3d34deb3ee2c2bf542)

I'm seeing a segfault when running from master.

backtrace from gdb (compiled using --disable-shared --enable-debug):

Program received signal SIGSEGV, Segmentation fault.
__memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:166
166 ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S: No such file or directory.
(gdb) bt
#0  __memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:166
#1  0x0000000000402d10 in mill_dequeue (ch=0x608010, val=0x610148) at chan.c:222
#2  0x0000000000402eb5 in mill_choose_wait () at chan.c:253
#3  0x000000000040311d in mill_chr (ch=0x608010, sz=4, current=0x4052cd "main.c:53") at chan.c:304
#4  0x00000000004015e6 in process_input (in=0x608010, out=0x60c0c0, out_var=0x60c160, open_pattern=0x405468 "{{", close_pattern=0x405465 "}}") at main.c:53
#5  0x000000000040201b in main () at main.c:237
(gdb) p goredump()

COROUTINE  state                                      current                                  created
------------------------------------------------------------------------------------------------------------------------
{0}        ready                                      (null)                                   <main>
{1}        ready                                      main.c:32                                main.c:232
{2}        chr(<1>)                                   ---                                      main.c:237
{3}        chr(<3>)                                   main.c:189                               main.c:241

CHANNEL  msgs/max    senders/receivers                          refs  done  created
------------------------------------------------------------------------------------------------------------------------
<1>      4215439/-140103639                                            6325855 no    main.c:231
<-1920270 1224736763/692846592 
Program received signal SIGSEGV, Segmentation fault.
0x0000000000403c7e in goredump () at debug.c:179
179             pos += sprintf(&buf[pos], "{%d}", (int)cl->cr->debug.id);
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(goredump) will be abandoned.
When the function is done executing, GDB will silently stop.
(gdb) 


Lines in question from my code:

  while(true){

    char in_buffer[ 4096 ];
    ssize_t in_len = read(0, in_buffer, sizeof(in_buffer));

    fprintf(stderr, "reader read: %ld\n", in_len ); // IMPORTANT LINE HERE

    if( in_len < 0 ){
      break;
    }

    for(ssize_t offset = 0; offset < in_len ; offset ++ ){
      int send = in_buffer[offset];
      chs(out, int, send);
    }
  }

It is important to note that if the fprintf line is commented, the code doesn't segfault, but doesn't behave as expected (that is, it hangs indefinitely).

msleep will not wake with certain goroutines/channels setup

It is possible to cause an endless loop using two coroutines communicating over two channels, preventing msleep from wakeup in the main coroutine.

I found it while trying to add these coroutines to tests/signals, to create some other activity when receiving signals, and i get the same endless loop, breaking the send/receive signals loop in the main coroutine.

For example code, see: nirs@ecefe4f

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.