sustrik / libmill Goto Github PK
View Code? Open in Web Editor NEWGo-style concurrency in C
License: MIT License
Go-style concurrency in C
License: MIT License
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.
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(...
Any though on this? most pc are multi-core now.
Build step6 of the tutorial on Fedora 20:
gcc -o server step6.c -lmill
Run server
Connect two clients
Wait until server times out and close the connection
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.
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
cloned master this morning at 3f55497 and gisted the result of a make check
here: https://gist.github.com/reqshark/4ad9951010480fa5aa39
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix
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;
}
Try this:
/* foo */
coroutine foo()
See the comment in mill.c:
/* TODO: Pass the 'hints' parameter to the function. When testing in
on Linux/gcc I've seen a strage pointer there. A compiler bug? */
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.
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"}}
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.
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
...
[ 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.
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?
/home/constantine/Desktop/libmill/tests/signals.c:71:5: error: โforโ loop initial declarations are only allowed in C99 or C11 mode
for(int i = 0; i < COUNT; ++i) {
^
/home/constantine/Desktop/libmill/tests/signals.c:71:5: note: use option -std=c99, -std=gnu99, -std=c11 or -std=gnu11 to compile your code
Makefile was generated from CMake.
This is to ensure that deadlines work consistently even in face of daylight changes, timezone shifts and such.
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.
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?)
All the system provided DNS resolvers are lame.
May be worth playing with this one:
http://25thandclement.com/~william/projects/dns.c.html
License is compatible.
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
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
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
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:
mill_choose_out uses void* to point to value to send. Should be const void*.
#include "libmill.h"
void loop() {
while (1) {
yield();
}
}
void main() {
go(loop());
msleep(now() + 1000);
}
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.
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.
Try to compile with -O1. 'go' test fails while deallocating the coroutine stack.
[ 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.
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)
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 ?? ()
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.
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.
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.
At the moment the size is limited to MILL_MAXCHVALSIZE bytes.
Dynamically grow the in buffer to accommodate larger types.
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:
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?
Is there any interest in supporting unix sockets?
Hi,
Tarantool Core is already doing what you're trying to accomplish, plus there is multi-threading support.
Just take it out (or most parts of it).
Same semantics a static functions.
Found this project while looking for a c goroutine implementation. It looks wonderful! Are there any benchmarks available?
A sample implementation of the Chinese whisper benchmark would be useful to compare it against go, libtask, etc.
https://cxwangyi.wordpress.com/2012/07/29/chinese-whispers-in-racket-and-go/
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);
In tcpattach() and unixattach(), SO_ACCEPTCONN should be checked to find out whether socket is listening. If so, listener socket should be created.
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).
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.