commit f9c282b16384f950a178a78724b89d8e93669c49
parent 8d1b5ac736b370590abfd70bd5c58c8175e94c32
Author: Tomas Hlavaty <tom@logand.com>
Date: Tue, 27 Aug 2019 23:01:14 +0200
content added
Diffstat:
A | chat.l | | | 57 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | nb-server.l | | | 63 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | nb.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);
+}
+/**/