nb

Non-blocking I/O for picoLisp
git clone https://logand.com/git/nb.git/
Log | Files | Refs | README

commit f9c282b16384f950a178a78724b89d8e93669c49
parent 8d1b5ac736b370590abfd70bd5c58c8175e94c32
Author: Tomas Hlavaty <tom@logand.com>
Date:   Tue, 27 Aug 2019 23:01:14 +0200

content added

Diffstat:
Achat.l | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anb-server.l | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anb.l | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 174 insertions(+), 0 deletions(-)

diff --git a/chat.l b/chat.l @@ -0,0 +1,57 @@ +# non-blocking chat server +# +# server: picolisp$ (chat 4444) +# clients: $ telnet localhost 4444 + +(load "nb.l") + +(off *H) # handlers + +(class +Handler) +# s [w] + +(dm T (S) + (=: s S) + (=: w (new)) + (push '*H (cons S This)) ) + +(dm rm> () + (prinl "q " (: s)) + (task (: s)) + (close (: s)) + (setq *H (delq (assoc (: s) *H) *H)) ) + +(dm wr> (Who Msg) + (fifo (: w) (cons Who Msg)) ) + +(setq *N 1024 *B (need *N)) # read buffer + +(dm cb> () + (block (: s) NIL) + (let N (in (: s) (rdx *B *N)) + (prinl "r " (: s) " " N) + (cond + ((gt0 N) (for H *H (wr> (cdr H) S (head N *B)))) + ((= N (eagain))) + (T (rm> This)) ) ) + (for H *H (fl> (cdr H))) ) + +(dm fl> () + (use X + (while + (and (setq X (cadr (val (: w)))) # peek head + (let (S (cdr X) + M (length S) + N (out (: s) (wrx S M))) + (prinl "w " (: s) " " N "/" M) + (when (gt0 N) + (if (<= M N) + (fifo (: w)) + (set (cdr (val (: w))) (tail (- M N) S)) ) ) ) ) ) ) ) + +(de chat (Port) + (task (port Port) + (when (accept @) + (task @ + This (new '(+Handler) @) + (cb> This) ) ) ) ) diff --git a/nb-server.l b/nb-server.l @@ -0,0 +1,63 @@ +(cd (pack (sys "HOME") "/picolisp")) +(load (pack (sys "HOME") "/src/picolisp/nb.l")) + +# (out "/tmp/a" (wrx '(1 2 3 4) 4)) +# (out "/tmp/a" (wrx '(1 2 3 4) 3 1)) + +# (setq *B (need 5)) +# (in "/tmp/a" (rdx *B 3)) +# (in "/tmp/a" (rdx *B 2 3)) +# *B + +# non-blocking echo server + +(setq *N 5) # try bigger buffer;-) +(setq *B (need *N)) +(setq *I 0) +(setq *J 0) + +(set 'EAGAIN (eagain)) + +(de _rdx (Sock) + (in Sock + (let? N (rdx *B (- *N *I) *I) + (when (gt0 N) + (inc '*I N)) + N))) + +(de _wrx (Sock) + (out Sock + (let? N (wrx *B (- *I *J) *J) + (when (gt0 N) + (inc '*J N)) + N))) + +(de callback (Sock) + (let End NIL + (prinl "callback " Sock " J=" *J " I=" *I " N=" *N) + (block Sock NIL) # first time would be enough + (unless End + (let N (_rdx Sock) + (prinl " read " N) + (unless (or (gt0 N) (= N 'EAGAIN)) + (setq End (cons rd N))))) + (unless End + (let N (_wrx Sock) + (prinl " written " N) + (unless (or (gt0 N) (= N 'EAGAIN)) + (setq End (cons wr N))))) + (when End + (prinl " finish") + (task Sock) + (close Sock)) + (when (<= *I *J) + (prinl " rotate J=" *J " I=" *I " N=" *N) + (setq *I 0) + (setq *J 0)) + (prinl "end " Sock " J=" *J " I=" *I " N=" *N))) + +(task (port 4444) # Listen on port 4444 + (when (accept @) # A connect arrived + (task @ # Install another task on this socket + Sock @ # Keep the socket in the task's env + (callback Sock) ) ) ) diff --git a/nb.l b/nb.l @@ -0,0 +1,54 @@ +(load "lib/gcc.l") + +(gcc "nb" NIL 'eagain 'block 'rdx 'wrx) + +//(eagain) -> 'cnt +any eagain(any ex __attribute__((unused))) { + return boxCnt(-EAGAIN); +} + +//(block 'any 'flg) -> 'flg +any block(any ex) { + int sd = (int)evCnt(ex,cdr(ex)); + any y = EVAL(caddr(ex)); + bool flg = isNil(y) ? NO : YES; + blocking(flg, ex, sd); + return y; +} + +//(rdx 'lst 'cnt ['cnt]) -> 'cnt|NIL +any rdx(any ex) { + any lst = EVAL(cadr(ex)); + int cnt = (int)evCnt(ex,cddr(ex)); + int off = isNil(cadddr(ex)) ? 0 : (int)evCnt(ex,cdddr(ex)); + int i = 0; + int j = 0; + NeedLst(ex,lst); + byte buf[cnt]; + int n = read(InFile->fd, buf, cnt); + if (0 < n) { + for (; j < off && isCell(lst); lst = cdr(lst), j++); + for (; i < n && i < cnt && isCell(lst); lst = cdr(lst), i++) { + lst->car = boxCnt(buf[i]); + } + } + return n == 0 ? Nil : boxCnt(n < 0 ? -errno : i); +} + +//(wrx 'lst 'cnt ['cnt]) -> 'cnt|NIL +any wrx(any ex) { + any lst = EVAL(cadr(ex)); + int cnt = (int)evCnt(ex,cddr(ex)); + int off = isNil(cadddr(ex)) ? 0 : (int)evCnt(ex,cdddr(ex)); + int i = 0; + int j = 0; + NeedLst(ex,lst); + byte buf[cnt]; + for (; j < off && isCell(lst); lst = cdr(lst), j++); + for (; i < cnt && isCell(lst); lst = cdr(lst), i++) { + buf[i] = (byte)evCnt(ex,lst); + } + int n = write(OutFile->fd, buf, i); + return n == 0 ? Nil : boxCnt(n < 0 ? -errno : n); +} +/**/