[hackers] [libixp] Add threading support.

From: Kris Maglione <jg_AT_suckless.org>
Date: Sun Jul 01 13:36:08 2007

changeset: 65:763e9c96f726
tag: tip
user: Kris Maglione <jg_AT_suckless.org>
date: Sun Jul 01 07:35:51 2007 -0400
summary: Add threading support.

diff -r 8773cc4aefd3 -r 763e9c96f726 Makefile
--- a/Makefile Sun Jun 17 17:01:24 2007 -0400
+++ b/Makefile Sun Jul 01 07:35:51 2007 -0400
@@ -1,7 +1,7 @@ ROOT=.
 ROOT=.
 include ${ROOT}/mk/hdr.mk
 
-DIRS = libixp \
+DIRS = ${COMPONENTS} \
         cmd \
         include \
         man
diff -r 8773cc4aefd3 -r 763e9c96f726 cmd/ixpc.c
--- a/cmd/ixpc.c Sun Jun 17 17:01:24 2007 -0400
+++ b/cmd/ixpc.c Sun Jul 01 07:35:51 2007 -0400
@@ -1,6 +1,8 @@
 /* Copyright ©2007 Kris Maglione <fbsdaemon_AT_gmail.com>
  * See LICENSE file for license details.
  */
+#define IXP_NO_P9_
+#define IXP_P9_STRUCTS
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -9,7 +11,7 @@
 #include "ixp.h"
 
 /* Temporary */
-#define fatal(...) ixp_eprint("ixpc: fatal: " __VA_ARGS__)
+#define fatal(...) ixp_eprint("ixpc: fatal: " __VA_ARGS__); \
 
 char *argv0;
 #define ARGBEGIN int _argi, _argtmp, _inargv=0; char *_argv; \
@@ -26,6 +28,7 @@ char *argv0;
                 : ((argc > 0) ? (argc--, *argv++) : ((f), (char*)0)))
 #define USED(x) if(x){}else
 #define SET(x) ((x)=0)
+#define nil ((void*)0)
 
 static IxpClient *client;
 
@@ -48,7 +51,7 @@ write_data(IxpCFid *fid, char *name) {
         do {
                 len = read(0, buf, fid->iounit);
                 if(len >= 0 && ixp_write(fid, buf, len) != len)
- fatal("cannot write file '%s': %s\n", name, errstr);
+ fatal("cannot write file '%s': %s\n", name, ixp_errbuf());
         } while(len > 0);
 
         free(buf);
@@ -124,7 +127,7 @@ xwrite(int argc, char *argv[]) {
         file = EARGF(usage());
         fid = ixp_open(client, file, P9_OWRITE);
         if(fid == nil)
- fatal("Can't open file '%s': %s\n", file, errstr);
+ fatal("Can't open file '%s': %s\n", file, ixp_errbuf());
 
         write_data(fid, file);
         return 0;
@@ -144,7 +147,7 @@ xawrite(int argc, char *argv[]) {
         file = EARGF(usage());
         fid = ixp_open(client, file, P9_OWRITE);
         if(fid == nil)
- fatal("Can't open file '%s': %s\n", file, errstr);
+ fatal("Can't open file '%s': %s\n", file, ixp_errbuf());
 
         nbuf = 0;
         mbuf = 128;
@@ -163,7 +166,7 @@ xawrite(int argc, char *argv[]) {
         }
 
         if(ixp_write(fid, buf, nbuf) == -1)
- fatal("cannot write file '%s': %s\n", file, errstr);
+ fatal("cannot write file '%s': %s\n", file, ixp_errbuf());
         return 0;
 }
 
@@ -180,7 +183,7 @@ xcreate(int argc, char *argv[]) {
         file = EARGF(usage());
         fid = ixp_create(client, file, 0777, P9_OWRITE);
         if(fid == nil)
- fatal("Can't create file '%s': %s\n", file, errstr);
+ fatal("Can't create file '%s': %s\n", file, ixp_errbuf());
 
         if((fid->qid.type&P9_DMDIR) == 0)
                 write_data(fid, file);
@@ -199,7 +202,7 @@ xremove(int argc, char *argv[]) {
 
         file = EARGF(usage());
         if(ixp_remove(client, file) == 0)
- fatal("Can't remove file '%s': %s\n", file, errstr);
+ fatal("Can't remove file '%s': %s\n", file, ixp_errbuf());
         return 0;
 }
 
@@ -217,21 +220,21 @@ xread(int argc, char *argv[]) {
         file = EARGF(usage());
         fid = ixp_open(client, file, P9_OREAD);
         if(fid == nil)
- fatal("Can't open file '%s': %s\n", file, errstr);
+ fatal("Can't open file '%s': %s\n", file, ixp_errbuf());
 
         buf = ixp_emalloc(fid->iounit);
         while((count = ixp_read(fid, buf, fid->iounit)) > 0)
                 write(1, buf, count);
 
         if(count == -1)
- fatal("cannot read file/directory '%s': %s\n", file, errstr);
+ fatal("cannot read file/directory '%s': %s\n", file, ixp_errbuf());
 
         return 0;
 }
 
 static int
 xls(int argc, char *argv[]) {
- Message m;
+ IxpMsg m;
         Stat *stat;
         IxpCFid *fid;
         char *file, *buf;
@@ -254,7 +257,7 @@ xls(int argc, char *argv[]) {
 
         stat = ixp_stat(client, file);
         if(stat == nil)
- fatal("cannot stat file '%s': %s\n", file, errstr);
+ fatal("cannot stat file '%s': %s\n", file, ixp_errbuf());
 
         if(dflag || (stat->mode&P9_DMDIR) == 0) {
                 print_stat(stat, lflag);
@@ -265,7 +268,7 @@ xls(int argc, char *argv[]) {
 
         fid = ixp_open(client, file, P9_OREAD);
         if(fid == nil)
- fatal("Can't open file '%s': %s\n", file, errstr);
+ fatal("Can't open file '%s': %s\n", file, ixp_errbuf());
 
         nstat = 0;
         mstat = 16;
@@ -276,7 +279,7 @@ xls(int argc, char *argv[]) {
                 while(m.pos < m.end) {
                         if(nstat == mstat) {
                                 mstat <<= 1;
- stat = ixp_erealloc(stat, mstat);
+ stat = ixp_erealloc(stat, sizeof(*stat) * mstat);
                         }
                         ixp_pstat(&m, &stat[nstat++]);
                 }
@@ -290,7 +293,7 @@ xls(int argc, char *argv[]) {
         free(stat);
 
         if(count == -1)
- fatal("cannot read directory '%s': %s\n", file, errstr);
+ fatal("cannot read directory '%s': %s\n", file, ixp_errbuf());
         return 0;
 }
 
@@ -334,7 +337,7 @@ main(int argc, char *argv[]) {
 
         client = ixp_mount(address);
         if(client == nil)
- fatal("%s\n", errstr);
+ fatal("%s\n", ixp_errbuf());
 
         for(tab = etab; tab->cmd; tab++)
                 if(strcmp(cmd, tab->cmd) == 0) break;
diff -r 8773cc4aefd3 -r 763e9c96f726 config.mk
--- a/config.mk Sun Jun 17 17:01:24 2007 -0400
+++ b/config.mk Sun Jul 01 07:35:51 2007 -0400
@@ -1,4 +1,13 @@
 # Customize below to fit your system
+
+COMPONENTS = \
+ libixp \
+ libixp_pthread \
+ libixp_task \
+ libixp_rubythread
+
+RUBYINC = -I/usr/local/lib/ruby/1.8/i386-freebsd6
+TASKINC = -I${HOME}/libtask
 
 # paths
 PREFIX = /usr/local
@@ -9,7 +18,7 @@ INCLUDE = ${PREFIX}/include
 INCLUDE = ${PREFIX}/include
 
 # Includes and libs
-INCS = -I. -I${ROOT}/include -I${INCLUDE} -I/usr/include
+INCPATH = .:${ROOT}/include:${INCLUDE}:/usr/include
 LIBS = -L/usr/lib -lc
 
 # Flags
@@ -30,4 +39,5 @@ AR = ar crs
 #LDFLAGS = ${LIBS} -R${PREFIX}/lib
 #LDFLAGS += -lsocket -lnsl
 #CFLAGS += -xtarget=ultra
-#FCALL_H_VERSION=.nounion
+FCALL_H_VERSION=.nounion
+
diff -r 8773cc4aefd3 -r 763e9c96f726 include/ixp.h
--- a/include/ixp.h Sun Jun 17 17:01:24 2007 -0400
+++ b/include/ixp.h Sun Jul 01 07:35:51 2007 -0400
@@ -5,18 +5,18 @@
 
 #include <sys/types.h>
 
-#undef uchar
-#undef ushort
-#undef uint
-#undef ulong
-#undef vlong
-#undef uvlong
-#define uchar _ixpuchar
-#define ushort _ixpushort
-#define uint _ixpuint
-#define ulong _ixpulong
-#define vlong _ixpvlong
-#define uvlong _ixpuvlong
+#undef uchar
+#define uchar _ixpuchar
+#undef ushort
+#define ushort _ixpushort
+#undef uint
+#define uint _ixpuint
+#undef ulong
+#define ulong _ixpulong
+#undef vlong
+#define vlong _ixpvlong
+#undef uvlong
+#define uvlong _ixpuvlong
 typedef unsigned char uchar;
 typedef unsigned short ushort;
 typedef unsigned int uint;
@@ -24,18 +24,13 @@ typedef long long vlong;
 typedef long long vlong;
 typedef unsigned long long uvlong;
 
-char *errstr;
-
-#undef nil
-#define nil ((void*)0)
-
 #define IXP_VERSION "9P2000"
 #define IXP_NOTAG ((ushort)~0) /* Dummy tag */
-#define IXP_NOFID (~0U)
+#define IXP_NOFID (~0U)
 
 enum {
         IXP_MAX_VERSION = 32,
- IXP_MAX_MSG = 65535,
+ IXP_MAX_MSG = 8192,
         IXP_MAX_ERROR = 128,
         IXP_MAX_CACHE = 32,
         IXP_MAX_FLEN = 128,
@@ -44,34 +39,34 @@ enum {
 };
 
 /* 9P message types */
-enum { TVersion = 100,
- RVersion,
- TAuth = 102,
- RAuth,
- TAttach = 104,
- RAttach,
- TError = 106, /* illegal */
- RError,
- TFlush = 108,
- RFlush,
- TWalk = 110,
- RWalk,
- TOpen = 112,
- ROpen,
- TCreate = 114,
- RCreate,
- TRead = 116,
- RRead,
- TWrite = 118,
- RWrite,
- TClunk = 120,
- RClunk,
- TRemove = 122,
- RRemove,
- TStat = 124,
- RStat,
- TWStat = 126,
- RWStat,
+enum { P9_TVersion = 100,
+ P9_RVersion,
+ P9_TAuth = 102,
+ P9_RAuth,
+ P9_TAttach = 104,
+ P9_RAttach,
+ P9_TError = 106, /* illegal */
+ P9_RError,
+ P9_TFlush = 108,
+ P9_RFlush,
+ P9_TWalk = 110,
+ P9_RWalk,
+ P9_TOpen = 112,
+ P9_ROpen,
+ P9_TCreate = 114,
+ P9_RCreate,
+ P9_TRead = 116,
+ P9_RRead,
+ P9_TWrite = 118,
+ P9_RWrite,
+ P9_TClunk = 120,
+ P9_RClunk,
+ P9_TRemove = 122,
+ P9_RRemove,
+ P9_TStat = 124,
+ P9_RStat,
+ P9_TWStat = 126,
+ P9_RWStat,
 };
 
 /* from libc.h in p9p */
@@ -90,22 +85,24 @@ enum { P9_OREAD = 0, /* open for read */
 };
 
 /* bits in Qid.type */
-enum { QTDIR = 0x80, /* type bit for directories */
- QTAPPEND = 0x40, /* type bit for append only files */
- QTEXCL = 0x20, /* type bit for exclusive use files */
- QTMOUNT = 0x10, /* type bit for mounted channel */
- QTAUTH = 0x08, /* type bit for authentication file */
- QTTMP = 0x04, /* type bit for non-backed-up file */
- QTSYMLINK = 0x02, /* type bit for symbolic link */
- QTFILE = 0x00 /* type bits for plain file */
+enum { P9_QTDIR = 0x80, /* type bit for directories */
+ P9_QTAPPEND = 0x40, /* type bit for append only files */
+ P9_QTEXCL = 0x20, /* type bit for exclusive use files */
+ P9_QTMOUNT = 0x10, /* type bit for mounted channel */
+ P9_QTAUTH = 0x08, /* type bit for authentication file */
+ P9_QTTMP = 0x04, /* type bit for non-backed-up file */
+ P9_QTSYMLINK = 0x02, /* type bit for symbolic link */
+ P9_QTFILE = 0x00 /* type bits for plain file */
 };
 
 /* bits in Dir.mode */
 enum {
+ P9_DMEXEC = 0x1, /* mode bit for execute permission */
         P9_DMWRITE = 0x2, /* mode bit for write permission */
         P9_DMREAD = 0x4, /* mode bit for read permission */
- P9_DMEXEC = 0x1, /* mode bit for execute permission */
-};
+};
+
+/* Larger than int, can't be enum */
 #define P9_DMDIR 0x80000000 /* mode bit for directories */
 #define P9_DMAPPEND 0x40000000 /* mode bit for append only files */
 #define P9_DMEXCL 0x20000000 /* mode bit for exclusive use files */
@@ -119,9 +116,116 @@ enum {
 #define P9_DMSETUID 0x00080000 /* mode bit for setuid (Unix, 9P2000.u) */
 #define P9_DMSETGID 0x00040000 /* mode bit for setgid (Unix, 9P2000.u) */
 
+#ifdef IXP_NO_P9_
+# define TVersion P9_TVersion
+# define RVersion P9_RVersion
+# define TAuth P9_TAuth
+# define RAuth P9_RAuth
+# define TAttach P9_TAttach
+# define RAttach P9_RAttach
+# define TError P9_TError
+# define RError P9_RError
+# define TFlush P9_TFlush
+# define RFlush P9_RFlush
+# define TWalk P9_TWalk
+# define RWalk P9_RWalk
+# define TOpen P9_TOpen
+# define ROpen P9_ROpen
+# define TCreate P9_TCreate
+# define RCreate P9_RCreate
+# define TRead P9_TRead
+# define RRead P9_RRead
+# define TWrite P9_TWrite
+# define RWrite P9_RWrite
+# define TClunk P9_TClunk
+# define RClunk P9_RClunk
+# define TRemove P9_TRemove
+# define RRemove P9_RRemove
+# define TStat P9_TStat
+# define RStat P9_RStat
+# define TWStat P9_TWStat
+# define RWStat P9_RWStat
+# define OREAD P9_OREAD
+# define OWRITE P9_OWRITE
+# define ORDWR P9_ORDWR
+# define OEXEC P9_OEXEC
+# define OTRUNC P9_OTRUNC
+# define OCEXEC P9_OCEXEC
+# define ORCLOSE P9_ORCLOSE
+# define ODIRECT P9_ODIRECT
+# define ONONBLOCK P9_ONONBLOCK
+# define OEXCL P9_OEXCL
+# define OLOCK P9_OLOCK
+# define OAPPEND P9_OAPPEND
+# define QTDIR P9_QTDIR
+# define QTAPPEND P9_QTAPPEND
+# define QTEXCL P9_QTEXCL
+# define QTMOUNT P9_QTMOUNT
+# define QTAUTH P9_QTAUTH
+# define QTTMP P9_QTTMP
+# define QTSYMLINK P9_QTSYMLINK
+# define QTFILE P9_QTFILE
+# define DMDIR P9_DMDIR
+# define DMAPPEND P9_DMAPPEND
+# define DMEXCL P9_DMEXCL
+# define DMMOUNT P9_DMMOUNT
+# define DMAUTH P9_DMAUTH
+# define DMTMP P9_DMTMP
+# define DMSYMLINK P9_DMSYMLINK
+# define DMDEVICE P9_DMDEVICE
+# define DMNAMEDPIPE P9_DMNAMEDPIPE
+# define DMSOCKET P9_DMSOCKET
+# define DMSETUID P9_DMSETUID
+# define DMSETGID P9_DMSETGID
+#endif
+
+#ifdef IXP_P9_STRUCTS
+# define IxpFcall Fcall
+# define IxpFid Fid
+# define IxpQid Qid
+# define IxpStat Stat
+#endif
+
+typedef struct Intmap Intmap;
+typedef struct Ixp9Conn Ixp9Conn;
+typedef struct Ixp9Req Ixp9Req;
+typedef struct Ixp9Srv Ixp9Srv;
+typedef struct IxpCFid IxpCFid;
+typedef struct IxpClient IxpClient;
+typedef struct IxpConn IxpConn;
+typedef struct IxpFcall IxpFcall;
+typedef struct IxpFid IxpFid;
+typedef struct IxpMsg IxpMsg;
+typedef struct IxpQid IxpQid;
+typedef struct IxpRpc IxpRpc;
+typedef struct IxpServer IxpServer;
+typedef struct IxpStat IxpStat;
+
+typedef struct IxpMutex IxpMutex;
+typedef struct IxpRWLock IxpRWLock;
+typedef struct IxpRendez IxpRendez;
+typedef struct IxpThread IxpThread;
+
+/* Threading */
+enum {
+ IXP_ERRMAX = IXP_MAX_ERROR,
+};
+
+struct IxpMutex {
+ void *aux;
+};
+
+struct IxpRWLock {
+ void *aux;
+};
+
+struct IxpRendez {
+ IxpMutex *mutex;
+ void *aux;
+};
+
 enum { MsgPack, MsgUnpack, };
-typedef struct Message Message;
-struct Message {
+struct IxpMsg {
         uchar *data;
         uchar *pos;
         uchar *end;
@@ -129,8 +233,7 @@ struct Message {
         uint mode;
 };
 
-typedef struct Qid Qid;
-struct Qid {
+struct IxpQid {
         uchar type;
         uint version;
         uvlong path;
@@ -141,10 +244,10 @@ struct Qid {
 #include <ixp_fcall.h>
 
 /* stat structure */
-typedef struct Stat {
+struct IxpStat {
         ushort type;
         uint dev;
- Qid qid;
+ IxpQid qid;
         uint mode;
         uint atime;
         uint mtime;
@@ -153,28 +256,17 @@ typedef struct Stat {
         char *uid;
         char *gid;
         char *muid;
-} Stat;
-
-typedef struct IxpServer IxpServer;
-typedef struct IxpConn IxpConn;
-typedef struct Intmap Intmap;
-
-typedef struct Intlist Intlist;
-struct Intmap {
- ulong nhash;
- Intlist **hash;
 };
 
 struct IxpConn {
         IxpServer *srv;
         void *aux;
         int fd;
- void (*read) (IxpConn *);
- void (*close) (IxpConn *);
+ void (*read)(IxpConn *);
+ void (*close)(IxpConn *);
         char closed;
 
- /* Implementation details */
- /* do not use */
+ /* Implementation details, do not use */
         IxpConn *next;
 };
 
@@ -187,54 +279,80 @@ struct IxpServer {
         fd_set rd;
 };
 
-
-typedef struct IxpClient IxpClient;
-typedef struct IxpCFid IxpCFid;
+struct IxpRpc {
+ IxpClient *mux;
+ IxpRpc *next;
+ IxpRpc *prev;
+ IxpRendez r;
+ uint tag;
+ IxpFcall *p;
+ int waiting;
+ int async;
+};
 
 struct IxpClient {
         int fd;
         uint msize;
         uint lastfid;
 
+ /* Implementation details */
+ uint nwait;
+ uint mwait;
+ uint freetag;
         IxpCFid *freefid;
- Message msg;
+ IxpMsg rmsg;
+ IxpMsg wmsg;
+ IxpMutex lk;
+ IxpMutex rlock;
+ IxpMutex wlock;
+ IxpRendez tagrend;
+ IxpRpc **wait;
+ IxpRpc *muxer;
+ IxpRpc sleep;
+ int mintag;
+ int maxtag;
 };
 
 struct IxpCFid {
         uint fid;
- Qid qid;
+ IxpQid qid;
         uchar mode;
         uint open;
         uint iounit;
         uvlong offset;
+ IxpClient *client;
         /* internal use only */
- IxpClient *client;
         IxpCFid *next;
-};
-
-typedef struct Ixp9Conn Ixp9Conn;
-typedef struct Fid {
- Ixp9Conn *conn;
- Intmap *map;
+ IxpMutex iolock;
+};
+
+struct IxpFid {
         char *uid;
         void *aux;
- ulong fid;
- Qid qid;
+ ulong fid;
+ IxpQid qid;
         signed char omode;
-} Fid;
-
-typedef struct Ixp9Req Ixp9Req;
+
+ /* Implementation details */
+ Ixp9Conn *conn;
+ Intmap *map;
+};
+
 struct Ixp9Req {
- Ixp9Conn *conn;
- Fid *fid;
- Fid *newfid;
+ Ixp9Srv *srv;
+ IxpFid *fid;
+ IxpFid *newfid;
         Ixp9Req *oldreq;
- Fcall ifcall;
- Fcall ofcall;
+ IxpFcall ifcall;
+ IxpFcall ofcall;
         void *aux;
-};
-
-typedef struct Ixp9Srv {
+
+ /* Implementation details */
+ Ixp9Conn *conn;
+};
+
+struct Ixp9Srv {
+ void *aux;
         void (*attach)(Ixp9Req *r);
         void (*clunk)(Ixp9Req *r);
         void (*create)(Ixp9Req *r);
@@ -245,8 +363,43 @@ typedef struct Ixp9Srv {
         void (*stat)(Ixp9Req *r);
         void (*walk)(Ixp9Req *r);
         void (*write)(Ixp9Req *r);
- void (*freefid)(Fid *f);
-} Ixp9Srv;
+ void (*freefid)(IxpFid *f);
+};
+
+struct IxpThread {
+ /* RWLock */
+ int (*initrwlock)(IxpRWLock*);
+ void (*rlock)(IxpRWLock*);
+ int (*canrlock)(IxpRWLock*);
+ void (*runlock)(IxpRWLock*);
+ void (*wlock)(IxpRWLock*);
+ int (*canwlock)(IxpRWLock*);
+ void (*wunlock)(IxpRWLock*);
+ void (*rwdestroy)(IxpRWLock*);
+ /* Mutex */
+ int (*initmutex)(IxpMutex*);
+ void (*lock)(IxpMutex*);
+ int (*canlock)(IxpMutex*);
+ void (*unlock)(IxpMutex*);
+ void (*mdestroy)(IxpMutex*);
+ /* Rendez */
+ int (*initrendez)(IxpRendez*);
+ void (*sleep)(IxpRendez*);
+ int (*wake)(IxpRendez*);
+ int (*wakeall)(IxpRendez*);
+ void (*rdestroy)(IxpRendez*);
+ /* Other */
+ char *(*errbuf)(void);
+ ssize_t (*read)(int, void*, size_t);
+ ssize_t (*write)(int, const void*, size_t);
+};
+
+extern IxpThread *ixp_thread;
+
+/* thread_*.c */
+int ixp_taskinit(void);
+int ixp_rubyinit(void);
+int ixp_pthread_init(void);
 
 /* client.c */
 IxpClient *ixp_mount(char *address);
@@ -255,52 +408,49 @@ IxpCFid *ixp_create(IxpClient *c, char *
 IxpCFid *ixp_create(IxpClient *c, char *name, uint perm, uchar mode);
 IxpCFid *ixp_open(IxpClient *c, char *name, uchar mode);
 int ixp_remove(IxpClient *c, char *path);
-Stat *ixp_stat(IxpClient *c, char *path);
-int ixp_read(IxpCFid *f, void *buf, uint count);
-int ixp_write(IxpCFid *f, void *buf, uint count);
+IxpStat *ixp_stat(IxpClient *c, char *path);
+long ixp_read(IxpCFid *f, void *buf, long count);
+long ixp_write(IxpCFid *f, void *buf, long count);
+long ixp_pread(IxpCFid *f, void *buf, long count, vlong offset);
+long ixp_pwrite(IxpCFid *f, void *buf, long count, vlong offset);
 int ixp_close(IxpCFid *f);
 
 /* convert.c */
-void ixp_pu8(Message *msg, uchar *val);
-void ixp_pu16(Message *msg, ushort *val);
-void ixp_pu32(Message *msg, uint *val);
-void ixp_pu64(Message *msg, uvlong *val);
-void ixp_pdata(Message *msg, char **data, uint len);
-void ixp_pstring(Message *msg, char **s);
-void ixp_pstrings(Message *msg, ushort *num, char *strings[]);
-void ixp_pqid(Message *msg, Qid *qid);
-void ixp_pqids(Message *msg, ushort *num, Qid qid[]);
-void ixp_pstat(Message *msg, Stat *stat);
+void ixp_pu8(IxpMsg *msg, uchar *val);
+void ixp_pu16(IxpMsg *msg, ushort *val);
+void ixp_pu32(IxpMsg *msg, uint *val);
+void ixp_pu64(IxpMsg *msg, uvlong *val);
+void ixp_pdata(IxpMsg *msg, char **data, uint len);
+void ixp_pstring(IxpMsg *msg, char **s);
+void ixp_pstrings(IxpMsg *msg, ushort *num, char *strings[]);
+void ixp_pqid(IxpMsg *msg, IxpQid *qid);
+void ixp_pqids(IxpMsg *msg, ushort *num, IxpQid qid[]);
+void ixp_pstat(IxpMsg *msg, IxpStat *stat);
+
+/* error.h */
+char *ixp_errbuf(void);
+void ixp_errstr(char*, int);
+void ixp_rerrstr(char*, int);
+void ixp_werrstr(char*, ...);
 
 /* request.c */
 void respond(Ixp9Req *r, char *error);
 void serve_9pcon(IxpConn *c);
 
-/* intmap.c */
-void initmap(Intmap *m, ulong nhash, void *hash);
-void incref_map(Intmap *m);
-void decref_map(Intmap *m);
-void freemap(Intmap *map, void (*destroy)(void*));
-void execmap(Intmap *map, void (*destroy)(void*));
-void *lookupkey(Intmap *map, ulong id);
-void *insertkey(Intmap *map, ulong id, void *v);
-void *deletekey(Intmap *map, ulong id);
-int caninsertkey(Intmap *map, ulong id, void *v);
-
 /* message.c */
-ushort ixp_sizeof_stat(Stat *stat);
-Message ixp_message(uchar *data, uint length, uint mode);
-void ixp_freestat(Stat *s);
-void ixp_freefcall(Fcall *fcall);
-uint ixp_msg2fcall(Message *msg, Fcall *fcall);
-uint ixp_fcall2msg(Message *msg, Fcall *fcall);
+ushort ixp_sizeof_stat(IxpStat *stat);
+IxpMsg ixp_message(uchar *data, uint length, uint mode);
+void ixp_freestat(IxpStat *s);
+void ixp_freefcall(IxpFcall *fcall);
+uint ixp_msg2fcall(IxpMsg *msg, IxpFcall *fcall);
+uint ixp_fcall2msg(IxpMsg *msg, IxpFcall *fcall);
 
 /* server.c */
 IxpConn *ixp_listen(IxpServer *s, int fd, void *aux,
                 void (*read)(IxpConn *c),
                 void (*close)(IxpConn *c));
 void ixp_hangup(IxpConn *c);
-char *ixp_serverloop(IxpServer *s);
+int ixp_serverloop(IxpServer *s);
 void ixp_server_close(IxpServer *s);
 
 /* socket.c */
@@ -308,8 +458,8 @@ int ixp_announce(char *address);
 int ixp_announce(char *address);
 
 /* transport.c */
-uint ixp_sendmsg(int fd, Message *msg);
-uint ixp_recvmsg(int fd, Message *msg);
+uint ixp_sendmsg(int fd, IxpMsg *msg);
+uint ixp_recvmsg(int fd, IxpMsg *msg);
 
 /* util.c */
 void *ixp_emalloc(uint size);
@@ -319,3 +469,4 @@ void ixp_eprint(const char *fmt, ...);
 void ixp_eprint(const char *fmt, ...);
 uint ixp_tokenize(char **result, uint reslen, char *str, char delim);
 uint ixp_strlcat(char *dst, const char *src, uint siz);
+
diff -r 8773cc4aefd3 -r 763e9c96f726 include/ixp_local.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/include/ixp_local.h Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,58 @@
+#define IXP_NO_P9_
+#define IXP_P9_STRUCTS
+#include <ixp.h>
+
+#define thread ixp_thread
+
+#define eprint ixp_eprint
+#define emalloc ixp_emalloc
+#define emallocz ixp_emallocz
+#define estrdup ixp_estrdup
+#define erealloc ixp_erealloc
+#define strlcat ixp_strlcat
+#define tokenize ixp_tokenize
+
+#define muxinit ixp_muxinit
+#define muxfree ixp_muxfree
+#define muxrpc ixp_muxrpc
+
+void muxinit(IxpClient*);
+void muxfree(IxpClient*);
+Fcall *muxrpc(IxpClient*, Fcall*);
+
+#define errstr ixp_errstr
+#define rerrstr ixp_rerrstr
+#define werrstr ixp_werrstr
+
+typedef struct Intlist Intlist;
+struct Intmap {
+ ulong nhash;
+ Intlist **hash;
+ IxpRWLock lk;
+};
+
+#define initmap ixp_initmap
+#define incref ixp_incref
+#define decref ixp_decref
+#define freemap ixp_freemap
+#define execmap ixp_execmap
+#define lookupkey ixp_lookupkey
+#define insertkey ixp_insertkey
+#define deletekey ixp_deletekey
+#define caninsertkey ixp_caninsertkey
+
+/* intmap.c */
+void initmap(Intmap *m, ulong nhash, void *hash);
+void incref_map(Intmap *m);
+void decref_map(Intmap *m);
+void freemap(Intmap *map, void (*destroy)(void*));
+void execmap(Intmap *map, void (*destroy)(void*));
+void *lookupkey(Intmap *map, ulong id);
+void *insertkey(Intmap *map, ulong id, void *v);
+void *deletekey(Intmap *map, ulong id);
+int caninsertkey(Intmap *map, ulong id, void *v);
+
+#undef nil
+#define nil ((void*)0)
+#define USED(v) if(v){}else{}
+
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/Makefile
--- a/libixp/Makefile Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/Makefile Sun Jul 01 07:35:51 2007 -0400
@@ -7,11 +7,14 @@ HFILES = ixp_fcall.h
 
 OBJ = client \
         convert \
+ error \
         intmap \
         message \
         request \
+ rpc \
         server \
         socket \
+ thread \
         transport \
         util
 
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/client.c
--- a/libixp/client.c Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/client.c Sun Jul 01 07:35:51 2007 -0400
@@ -2,20 +2,19 @@
  * See LICENSE file for license details.
  */
 #include <assert.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include "ixp.h"
+#include "ixp_local.h"
 
 #define nelem(ary) (sizeof(ary) / sizeof(*ary))
-static char errbuf[1024];
 
 enum {
         RootFid = 1,
- Tag = 1,
 };
 
 static int
@@ -29,16 +28,19 @@ getfid(IxpClient *c) {
 getfid(IxpClient *c) {
         IxpCFid *f;
 
+ thread->lock(&c->lk);
         f = c->freefid;
         if(f != nil)
                 c->freefid = f->next;
         else {
- f = ixp_emallocz(sizeof *f);
+ f = emallocz(sizeof *f);
                 f->client = c;
                 f->fid = ++c->lastfid;
+ thread->initmutex(&f->iolock);
         }
         f->next = nil;
         f->open = 0;
+ thread->unlock(&c->lk);
         return f;
 }
 
@@ -47,44 +49,40 @@ putfid(IxpCFid *f) {
         IxpClient *c;
 
         c = f->client;
+ thread->lock(&c->lk);
         if(f->fid == c->lastfid) {
                 c->lastfid--;
+ thread->mdestroy(&f->iolock);
                 free(f);
         }else {
                 f->next = c->freefid;
                 c->freefid = f;
         }
+ thread->unlock(&c->lk);
 }
 
 static int
 dofcall(IxpClient *c, Fcall *fcall) {
- int type;
-
- type = fcall->type;
- if(ixp_fcall2msg(&c->msg, fcall) == 0) {
- errstr = "failed to pack message";
+ Fcall *ret;
+
+ ret = muxrpc(c, fcall);
+ if(ret == nil)
                 return 0;
- }
- if(ixp_sendmsg(c->fd, &c->msg) == 0)
- return 0;
- if(ixp_recvmsg(c->fd, &c->msg) == 0)
- return 0;
- if(ixp_msg2fcall(&c->msg, fcall) == 0) {
- errstr = "received bad message";
- return 0;
- }
- if(fcall->type == RError) {
- strncpy(errbuf, fcall->ename, sizeof errbuf);
- ixp_freefcall(fcall);
- errstr = errbuf;
- return 0;
- }
- if(fcall->type != (type^1)) {
- ixp_freefcall(fcall);
- errstr = "received mismatched fcall";
- return 0;
- }
+ if(ret->type == RError) {
+ werrstr("%s", ret->ename);
+ goto fail;
+ }
+ if(ret->type != (fcall->type^1)) {
+ werrstr("received mismatched fcall");
+ goto fail;
+ }
+ memcpy(fcall, ret, sizeof(*fcall));
+ free(ret);
         return 1;
+fail:
+ ixp_freefcall(fcall);
+ free(ret);
+ return 0;
 }
 
 void
@@ -94,12 +92,24 @@ ixp_unmount(IxpClient *c) {
         shutdown(c->fd, SHUT_RDWR);
         close(c->fd);
 
+ muxfree(c);
+
         while((f = c->freefid)) {
                 c->freefid = f->next;
+ thread->mdestroy(&f->iolock);
                 free(f);
         }
- free(c->msg.data);
+ free(c->rmsg.data);
+ free(c->wmsg.data);
         free(c);
+}
+
+static void
+allocmsg(IxpClient *c, int n) {
+ c->rmsg.size = n;
+ c->wmsg.size = n;
+ c->rmsg.data = erealloc(c->rmsg.data, n);
+ c->wmsg.data = erealloc(c->wmsg.data, n);
 }
 
 IxpClient *
@@ -107,15 +117,18 @@ ixp_mountfd(int fd) {
         IxpClient *c;
         Fcall fcall;
 
- c = ixp_emallocz(sizeof(*c));
+ c = emallocz(sizeof(*c));
         c->fd = fd;
 
- c->msg.size = 64;
- c->msg.data = ixp_emalloc(c->msg.size);
+ muxinit(c);
+
+ allocmsg(c, 256);
         c->lastfid = RootFid;
+ /* Override tag matching on TVersion */
+ c->mintag = IXP_NOTAG;
+ c->maxtag = IXP_NOTAG+1;
 
         fcall.type = TVersion;
- fcall.tag = IXP_NOTAG;
         fcall.msize = IXP_MAX_MSG;
         fcall.version = IXP_VERSION;
 
@@ -124,18 +137,19 @@ ixp_mountfd(int fd) {
                 return nil;
         }
 
- if(strcmp(fcall.version, IXP_VERSION) != 0) {
- errstr = "bad 9P version response";
+ if(strcmp(fcall.version, IXP_VERSION) || fcall.msize > IXP_MAX_MSG) {
+ werrstr("bad 9P version response");
                 ixp_unmount(c);
                 return nil;
         }
 
- c->msg.size = fcall.msize;
- c->msg.data = ixp_erealloc(c->msg.data, c->msg.size);
+ c->mintag = 0;
+ c->maxtag = 255;
+
+ allocmsg(c, fcall.msize);
         ixp_freefcall(&fcall);
 
         fcall.type = TAttach;
- fcall.tag = Tag;
         fcall.fid = RootFid;
         fcall.afid = IXP_NOFID;
         fcall.uname = getenv("USER");
@@ -164,8 +178,8 @@ walk(IxpClient *c, char *path) {
         Fcall fcall;
         int n;
 
- path = ixp_estrdup(path);
- n = ixp_tokenize(fcall.wname, nelem(fcall.wname), path, '/');
+ path = estrdup(path);
+ n = tokenize(fcall.wname, nelem(fcall.wname), path, '/');
         f = getfid(c);
 
         fcall.type = TWalk;
@@ -199,7 +213,7 @@ walkdir(IxpClient *c, char *path, char *
         while((p > path) && (*p != '/'))
                 p--;
         if(*p != '/') {
- errstr = "bad path";
+ werrstr("bad path");
                 return nil;
         }
 
@@ -217,7 +231,6 @@ clunk(IxpCFid *f) {
         c = f->client;
 
         fcall.type = TClunk;
- fcall.tag = Tag;
         fcall.fid = f->fid;
         ret = dofcall(c, &fcall);
         if(ret)
@@ -236,7 +249,6 @@ ixp_remove(IxpClient *c, char *path) {
                 return 0;
 
         fcall.type = TRemove;
- fcall.tag = Tag;
         fcall.fid = f->fid;;
         ret = dofcall(c, &fcall);
         ixp_freefcall(&fcall);
@@ -249,24 +261,25 @@ initfid(IxpCFid *f, Fcall *fcall) {
 initfid(IxpCFid *f, Fcall *fcall) {
         f->open = 1;
         f->offset = 0;
- f->iounit = min(fcall->iounit, IXP_MAX_MSG-32);
+ f->iounit = fcall->iounit;
+ if(f->iounit == 0 || fcall->iounit > f->client->msize-24)
+ f->iounit = f->client->msize-24;
         f->qid = fcall->qid;
 }
 
-IxpCFid *
+IxpCFid*
 ixp_create(IxpClient *c, char *name, uint perm, uchar mode) {
         Fcall fcall;
         IxpCFid *f;
         char *path;;
 
- path = ixp_estrdup(name);
+ path = estrdup(name);
 
         f = walkdir(c, path, &name);
         if(f == nil)
                 goto done;
 
         fcall.type = TCreate;
- fcall.tag = Tag;
         fcall.fid = f->fid;
         fcall.name = name;
         fcall.perm = perm;
@@ -288,7 +301,7 @@ done:
         return f;
 }
 
-IxpCFid *
+IxpCFid*
 ixp_open(IxpClient *c, char *name, uchar mode) {
         Fcall fcall;
         IxpCFid *f;
@@ -298,7 +311,6 @@ ixp_open(IxpClient *c, char *name, uchar
                 return nil;
 
         fcall.type = TOpen;
- fcall.tag = Tag;
         fcall.fid = f->fid;
         fcall.mode = mode;
 
@@ -321,7 +333,7 @@ ixp_close(IxpCFid *f) {
 
 Stat *
 ixp_stat(IxpClient *c, char *path) {
- Message msg;
+ IxpMsg msg;
         Fcall fcall;
         Stat *stat;
         IxpCFid *f;
@@ -332,14 +344,13 @@ ixp_stat(IxpClient *c, char *path) {
                 return nil;
 
         fcall.type = TStat;
- fcall.tag = Tag;
         fcall.fid = f->fid;
         if(dofcall(c, &fcall) == 0)
                 goto done;
 
         msg = ixp_message(fcall.stat, fcall.nstat, MsgUnpack);
 
- stat = ixp_emalloc(sizeof(*stat));
+ stat = emalloc(sizeof(*stat));
         ixp_pstat(&msg, stat);
         ixp_freefcall(&fcall);
         if(msg.pos > msg.end) {
@@ -352,8 +363,8 @@ done:
         return stat;
 }
 
-int
-ixp_read(IxpCFid *f, void *buf, uint count) {
+static long
+_pread(IxpCFid *f, void *buf, long count, vlong offset) {
         Fcall fcall;
         int n, len;
 
@@ -362,9 +373,8 @@ ixp_read(IxpCFid *f, void *buf, uint cou
                 n = min(count-len, f->iounit);
 
                 fcall.type = TRead;
- fcall.tag = IXP_NOTAG;
                 fcall.fid = f->fid;
- fcall.offset = f->offset;
+ fcall.offset = offset;
                 fcall.count = n;
                 if(dofcall(f->client, &fcall) == 0)
                         return -1;
@@ -372,7 +382,7 @@ ixp_read(IxpCFid *f, void *buf, uint cou
                         return -1;
 
                 memcpy(buf+len, fcall.data, fcall.count);
- f->offset += fcall.count;
+ offset += fcall.count;
                 len += fcall.count;
 
                 ixp_freefcall(&fcall);
@@ -382,8 +392,30 @@ ixp_read(IxpCFid *f, void *buf, uint cou
         return len;
 }
 
-int
-ixp_write(IxpCFid *f, void *buf, uint count) {
+long
+ixp_read(IxpCFid *f, void *buf, long count) {
+ int n;
+
+ thread->lock(&f->iolock);
+ n = _pread(f, buf, count, f->offset);
+ if(n > 0)
+ f->offset += n;
+ thread->unlock(&f->iolock);
+ return n;
+}
+
+long
+ixp_pread(IxpCFid *f, void *buf, long count, vlong offset) {
+ int n;
+
+ thread->lock(&f->iolock);
+ n = _pread(f, buf, count, offset);
+ thread->unlock(&f->iolock);
+ return n;
+}
+
+static long
+_pwrite(IxpCFid *f, void *buf, long count, vlong offset) {
         Fcall fcall;
         int n, len;
 
@@ -391,7 +423,6 @@ ixp_write(IxpCFid *f, void *buf, uint co
         do {
                 n = min(count-len, f->iounit);
                 fcall.type = TWrite;
- fcall.tag = IXP_NOTAG;
                 fcall.fid = f->fid;
                 fcall.offset = f->offset;
                 fcall.data = (uchar*)buf + len;
@@ -408,3 +439,26 @@ ixp_write(IxpCFid *f, void *buf, uint co
         } while(len < count);
         return len;
 }
+
+long
+ixp_write(IxpCFid *f, void *buf, long count) {
+ int n;
+
+ thread->lock(&f->iolock);
+ n = _pwrite(f, buf, count, f->offset);
+ if(n > 0)
+ f->offset += n;
+ thread->unlock(&f->iolock);
+ return n;
+}
+
+long
+ixp_pwrite(IxpCFid *f, void *buf, long count, vlong offset) {
+ int n;
+
+ thread->lock(&f->iolock);
+ n = _pwrite(f, buf, count, offset);
+ thread->unlock(&f->iolock);
+ return n;
+}
+
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/convert.c
--- a/libixp/convert.c Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/convert.c Sun Jul 01 07:35:51 2007 -0400
@@ -4,7 +4,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include "ixp.h"
+#include "ixp_local.h"
 
 enum {
         SByte = 1,
@@ -14,7 +14,7 @@ enum {
 };
 
 void
-ixp_puint(Message *msg, uint size, uint *val) {
+ixp_puint(IxpMsg *msg, uint size, uint *val) {
         int v;
 
         if(msg->pos + size <= msg->end) {
@@ -50,11 +50,11 @@ ixp_puint(Message *msg, uint size, uint
 }
 
 void
-ixp_pu32(Message *msg, uint *val) {
+ixp_pu32(IxpMsg *msg, uint *val) {
         ixp_puint(msg, SDWord, val);
 }
 void
-ixp_pu8(Message *msg, uchar *val) {
+ixp_pu8(IxpMsg *msg, uchar *val) {
         uint v;
 
         v = *val;
@@ -62,7 +62,7 @@ ixp_pu8(Message *msg, uchar *val) {
         *val = (uchar)v;
 }
 void
-ixp_pu16(Message *msg, ushort *val) {
+ixp_pu16(IxpMsg *msg, ushort *val) {
         uint v;
 
         v = *val;
@@ -70,7 +70,7 @@ ixp_pu16(Message *msg, ushort *val) {
         *val = (ushort)v;
 }
 void
-ixp_pu64(Message *msg, uvlong *val) {
+ixp_pu64(IxpMsg *msg, uvlong *val) {
         uint vl, vb;
 
         vl = (uint)*val;
@@ -81,7 +81,7 @@ ixp_pu64(Message *msg, uvlong *val) {
 }
 
 void
-ixp_pstring(Message *msg, char **s) {
+ixp_pstring(IxpMsg *msg, char **s) {
         ushort len;
 
         if(msg->mode == MsgPack)
@@ -90,7 +90,7 @@ ixp_pstring(Message *msg, char **s) {
 
         if(msg->pos + len <= msg->end) {
                 if(msg->mode == MsgUnpack) {
- *s = ixp_emalloc(len + 1);
+ *s = emalloc(len + 1);
                         memcpy(*s, msg->pos, len);
                         (*s)[len] = '\0';
                 }else
@@ -100,7 +100,7 @@ ixp_pstring(Message *msg, char **s) {
 }
 
 void
-ixp_pstrings(Message *msg, ushort *num, char *strings[]) {
+ixp_pstrings(IxpMsg *msg, ushort *num, char *strings[]) {
         uchar *s;
         uint i, size;
         ushort len;
@@ -123,7 +123,7 @@ ixp_pstrings(Message *msg, ushort *num,
                 }
                 msg->pos = s;
                 size += *num;
- s = ixp_emalloc(size);
+ s = emalloc(size);
         }
 
         for(i=0; i < *num; i++) {
@@ -143,10 +143,10 @@ ixp_pstrings(Message *msg, ushort *num,
 }
 
 void
-ixp_pdata(Message *msg, char **data, uint len) {
+ixp_pdata(IxpMsg *msg, char **data, uint len) {
         if(msg->pos + len <= msg->end) {
                 if(msg->mode == MsgUnpack) {
- *data = ixp_emalloc(len);
+ *data = emalloc(len);
                         memcpy(*data, msg->pos, len);
                 }else
                         memcpy(msg->pos, *data, len);
@@ -155,14 +155,14 @@ ixp_pdata(Message *msg, char **data, uin
 }
 
 void
-ixp_pqid(Message *msg, Qid *qid) {
+ixp_pqid(IxpMsg *msg, Qid *qid) {
         ixp_pu8(msg, &qid->type);
         ixp_pu32(msg, &qid->version);
         ixp_pu64(msg, &qid->path);
 }
 
 void
-ixp_pqids(Message *msg, ushort *num, Qid qid[]) {
+ixp_pqids(IxpMsg *msg, ushort *num, Qid qid[]) {
         int i;
 
         ixp_pu16(msg, num);
@@ -176,7 +176,7 @@ ixp_pqids(Message *msg, ushort *num, Qid
 }
 
 void
-ixp_pstat(Message *msg, Stat *stat) {
+ixp_pstat(IxpMsg *msg, Stat *stat) {
         ushort size;
 
         if(msg->mode == MsgPack)
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/error.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libixp/error.c Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,50 @@
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include "ixp_local.h"
+
+/* Approach to errno handling taken from Plan 9 Port. */
+enum {
+ EPLAN9 = 0x19283745,
+};
+
+char*
+ixp_errbuf() {
+ char *errbuf;
+
+ errbuf = thread->errbuf();
+ if(errno == EINTR)
+ strncpy(errbuf, "interrupted", IXP_ERRMAX);
+ else if(errno != EPLAN9)
+ strncpy(errbuf, strerror(errno), IXP_ERRMAX);
+ return errbuf;
+}
+
+void
+errstr(char *buf, int n) {
+ char tmp[IXP_ERRMAX];
+
+ strncpy(tmp, buf, sizeof(tmp));
+ rerrstr(buf, n);
+ strncpy(thread->errbuf(), tmp, IXP_ERRMAX);
+ errno = EPLAN9;
+}
+
+void
+rerrstr(char *buf, int n) {
+ strncpy(buf, ixp_errbuf(), n);
+}
+
+void
+werrstr(char *fmt, ...) {
+ char tmp[IXP_ERRMAX];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(tmp, sizeof(tmp), fmt, ap);
+ va_end(ap);
+ strncpy(thread->errbuf(), tmp, IXP_ERRMAX);
+ errno = EPLAN9;
+}
+
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/fcall.h
--- a/libixp/fcall.h Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/fcall.h Sun Jul 01 07:35:51 2007 -0400
@@ -1,5 +1,5 @@
 /* from fcall(3) in plan9port */
-typedef struct Fcall {
+struct IxpFcall {
         uchar type;
         ushort tag;
         uint fid;
@@ -15,11 +15,11 @@ typedef struct Fcall {
                         char *ename;
                 };
                 struct { /* Ropen, Rcreate */
- Qid qid; /* +Rattach */
+ IxpQid qid; /* +Rattach */
                         uint iounit;
                 };
                 struct { /* Rauth */
- Qid aqid;
+ IxpQid aqid;
                 };
                 struct { /* Tauth, Tattach */
                         uint afid;
@@ -38,7 +38,7 @@ typedef struct Fcall {
                 };
                 struct { /* Rwalk */
                         ushort nwqid;
- Qid wqid[IXP_MAX_WELEM];
+ IxpQid wqid[IXP_MAX_WELEM];
                 };
                 struct { /* Twrite */
                         uvlong offset; /* +Tread */
@@ -51,4 +51,4 @@ typedef struct Fcall {
                         uchar *stat;
                 };
         };
-} Fcall;
+};
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/fcall.h.nounion
--- a/libixp/fcall.h.nounion Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/fcall.h.nounion Sun Jul 01 07:35:51 2007 -0400
@@ -1,5 +1,5 @@
 /* from fcall(3) in plan9port */
-typedef struct Fcall {
+struct IxpFcall {
         uchar type;
         ushort tag;
         uint fid;
@@ -15,11 +15,11 @@ typedef struct Fcall {
         char *ename;
 
         /* Ropen, Rcreate */
- Qid qid; /* +Rattach */
+ IxpQid qid; /* +Rattach */
         uint iounit;
 
         /* Rauth */
- Qid aqid;
+ IxpQid aqid;
 
         /* Tauth, Tattach */
         uint afid;
@@ -38,7 +38,7 @@ typedef struct Fcall {
 
         /* Rwalk */
         ushort nwqid;
- Qid wqid[IXP_MAX_WELEM];
+ IxpQid wqid[IXP_MAX_WELEM];
 
         /* Twrite */
         uvlong offset; /* +Tread */
@@ -50,4 +50,4 @@ typedef struct Fcall {
         /* Twstat, Rstat */
         ushort nstat;
         uchar *stat;
-} Fcall;
+};
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/intmap.c
--- a/libixp/intmap.c Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/intmap.c Sun Jul 01 07:35:51 2007 -0400
@@ -2,9 +2,7 @@
 /* See LICENCE.p9p for terms of use */
 
 #include <stdlib.h>
-#include "ixp.h"
-
-#define USED(v) if(v){}else{}
+#include "ixp_local.h"
 
 struct Intlist {
         ulong id;
@@ -27,6 +25,8 @@ initmap(Intmap *m, ulong nhash, void *ha
 initmap(Intmap *m, ulong nhash, void *hash) {
         m->nhash = nhash;
         m->hash = hash;
+
+ thread->initrwlock(&m->lk);
 }
 
 static Intlist**
@@ -53,18 +53,25 @@ freemap(Intmap *map, void (*destroy)(voi
                         free(p);
                 }
         }
+
+ thread->rwdestroy(&map->lk);
 }
+
 void
 execmap(Intmap *map, void (*run)(void*)) {
         int i;
         Intlist *p, *nlink;
 
+ thread->rlock(&map->lk);
         for(i=0; i<map->nhash; i++){
                 for(p=map->hash[i]; p; p=nlink){
+ thread->runlock(&map->lk);
                         nlink = p->link;
                         run(p->aux);
+ thread->rlock(&map->lk);
                 }
         }
+ thread->runlock(&map->lk);
 }
 
 void *
@@ -72,10 +79,12 @@ lookupkey(Intmap *map, ulong id) {
         Intlist *f;
         void *v;
 
+ thread->rlock(&map->lk);
         if((f = *llookup(map, id)))
                 v = f->aux;
         else
                 v = nil;
+ thread->runlock(&map->lk);
         return v;
 }
 
@@ -85,12 +94,13 @@ insertkey(Intmap *map, ulong id, void *v
         void *ov;
         ulong h;
 
+ thread->wlock(&map->lk);
         if((f = *llookup(map, id))){
                 /* no decrement for ov because we're returning it */
                 ov = f->aux;
                 f->aux = v;
         }else{
- f = ixp_emallocz(sizeof(*f));
+ f = emallocz(sizeof(*f));
                 f->id = id;
                 f->aux = v;
                 h = hashid(map, id);
@@ -98,6 +108,7 @@ insertkey(Intmap *map, ulong id, void *v
                 map->hash[h] = f;
                 ov = nil;
         }
+ thread->wunlock(&map->lk);
         return ov;
 }
 
@@ -107,10 +118,11 @@ caninsertkey(Intmap *map, ulong id, void
         int rv;
         ulong h;
 
+ thread->wlock(&map->lk);
         if(*llookup(map, id))
                 rv = 0;
         else{
- f = ixp_emallocz(sizeof *f);
+ f = emallocz(sizeof *f);
                 f->id = id;
                 f->aux = v;
                 h = hashid(map, id);
@@ -118,6 +130,7 @@ caninsertkey(Intmap *map, ulong id, void
                 map->hash[h] = f;
                 rv = 1;
         }
+ thread->wunlock(&map->lk);
         return rv;
 }
 
@@ -126,11 +139,13 @@ deletekey(Intmap *map, ulong id) {
         Intlist **lf, *f;
         void *ov;
 
+ thread->wlock(&map->lk);
         if((f = *(lf = llookup(map, id)))){
                 ov = f->aux;
                 *lf = f->link;
                 free(f);
         }else
                 ov = nil;
+ thread->wunlock(&map->lk);
         return ov;
 }
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/ixp_fcall.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libixp/ixp_fcall.h Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,53 @@
+/* from fcall(3) in plan9port */
+struct IxpFcall {
+ uchar type;
+ ushort tag;
+ uint fid;
+
+ /* Tversion, Rversion */
+ uint msize;
+ char *version;
+
+ /* Tflush */
+ ushort oldtag;
+
+ /* Rerror */
+ char *ename;
+
+ /* Ropen, Rcreate */
+ IxpQid qid; /* +Rattach */
+ uint iounit;
+
+ /* Rauth */
+ IxpQid aqid;
+
+ /* Tauth, Tattach */
+ uint afid;
+ char *uname;
+ char *aname;
+
+ /* Tcreate */
+ uint perm;
+ char *name;
+ uchar mode; /* +Topen */
+
+ /* Twalk */
+ uint newfid;
+ ushort nwname;
+ char *wname[IXP_MAX_WELEM];
+
+ /* Rwalk */
+ ushort nwqid;
+ IxpQid wqid[IXP_MAX_WELEM];
+
+ /* Twrite */
+ uvlong offset; /* +Tread */
+
+ /* +Rread */
+ uint count; /* +Tread */
+ char *data;
+
+ /* Twstat, Rstat */
+ ushort nstat;
+ uchar *stat;
+};
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/message.c
--- a/libixp/message.c Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/message.c Sun Jul 01 07:35:51 2007 -0400
@@ -4,7 +4,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include "ixp.h"
+#include "ixp_local.h"
 
 enum {
         SByte = 1,
@@ -18,9 +18,9 @@ enum {
         SQid = SByte + SDWord + SQWord,
 };
 
-Message
+IxpMsg
 ixp_message(uchar *data, uint length, uint mode) {
- Message m;
+ IxpMsg m;
 
         m.data = data;
         m.pos = data;
@@ -76,7 +76,7 @@ ixp_sizeof_stat(Stat * stat) {
 }
 
 void
-ixp_pfcall(Message *msg, Fcall *fcall) {
+ixp_pfcall(IxpMsg *msg, Fcall *fcall) {
         ixp_pu8(msg, &fcall->type);
         ixp_pu16(msg, &fcall->tag);
 
@@ -168,7 +168,7 @@ ixp_pfcall(Message *msg, Fcall *fcall) {
 }
 
 uint
-ixp_fcall2msg(Message *msg, Fcall *fcall) {
+ixp_fcall2msg(IxpMsg *msg, Fcall *fcall) {
         int size;
 
         msg->end = msg->data + msg->size;
@@ -190,7 +190,7 @@ ixp_fcall2msg(Message *msg, Fcall *fcall
 }
 
 uint
-ixp_msg2fcall(Message *msg, Fcall *fcall) {
+ixp_msg2fcall(IxpMsg *msg, Fcall *fcall) {
         msg->pos = msg->data + SDWord;
         msg->mode = MsgUnpack;
         ixp_pfcall(msg, fcall);
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/request.c
--- a/libixp/request.c Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/request.c Sun Jul 01 07:35:51 2007 -0400
@@ -6,7 +6,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/socket.h>
-#include "ixp.h"
+#include "ixp_local.h"
 
 static void handlereq(Ixp9Req *r);
 
@@ -30,24 +30,42 @@ static char
         Eisdir[] = "cannot perform operation on a directory";
 
 enum {
- TAG_BUCKETS = 64,
- FID_BUCKETS = 64,
+ TAG_BUCKETS = 61,
+ FID_BUCKETS = 61,
 };
 
 struct Ixp9Conn {
- Intmap tagmap;
- void *taghash[TAG_BUCKETS];
- Intmap fidmap;
- void *fidhash[FID_BUCKETS];
- Ixp9Srv *srv;
- IxpConn *conn;
- Message msg;
- uint ref;
+ Intmap tagmap;
+ Intmap fidmap;
+ void *taghash[TAG_BUCKETS];
+ void *fidhash[FID_BUCKETS];
+ Ixp9Srv *srv;
+ IxpConn *conn;
+ IxpMutex rlock, wlock;
+ IxpMsg rmsg;
+ IxpMsg wmsg;
+ int ref;
 };
 
 static void
-free_p9conn(Ixp9Conn *pc) {
- free(pc->msg.data);
+decref_p9conn(Ixp9Conn *pc) {
+ thread->lock(&pc->wlock);
+ if(--pc->ref > 0) {
+ thread->unlock(&pc->wlock);
+ return;
+ }
+ thread->unlock(&pc->wlock);
+
+ assert(pc->conn == nil);
+
+ thread->mdestroy(&pc->rlock);
+ thread->mdestroy(&pc->wlock);
+
+ freemap(&pc->tagmap, nil);
+ freemap(&pc->fidmap, nil);
+
+ free(pc->rmsg.data);
+ free(pc->wmsg.data);
         free(pc);
 }
 
@@ -55,12 +73,12 @@ createfid(Intmap *map, int fid, Ixp9Conn
 createfid(Intmap *map, int fid, Ixp9Conn *pc) {
         Fid *f;
 
- pc->ref++;
- f = ixp_emallocz(sizeof(Fid));
+ f = emallocz(sizeof(Fid));
+ pc->ref++;
+ f->conn = pc;
         f->fid = fid;
         f->omode = -1;
         f->map = map;
- f->conn = pc;
         if(caninsertkey(map, fid, f))
                 return f;
         free(f);
@@ -78,7 +96,7 @@ destroyfid(Ixp9Conn *pc, ulong fid) {
         if(pc->srv->freefid)
                 pc->srv->freefid(f);
 
- pc->ref--;
+ decref_p9conn(pc);
         free(f);
         return 1;
 }
@@ -90,26 +108,31 @@ handlefcall(IxpConn *c) {
         Ixp9Req *req;
 
         pc = c->aux;
- errstr = nil;
-
- if(ixp_recvmsg(c->fd, &pc->msg) == 0)
+
+ thread->lock(&pc->rlock);
+ if(ixp_recvmsg(c->fd, &pc->rmsg) == 0)
                 goto Fail;
- if(ixp_msg2fcall(&pc->msg, &fcall) == 0)
+ if(ixp_msg2fcall(&pc->rmsg, &fcall) == 0)
                 goto Fail;
-
- req = ixp_emallocz(sizeof(Ixp9Req));
+ thread->unlock(&pc->rlock);
+
+ req = emallocz(sizeof(Ixp9Req));
+ pc->ref++;
         req->conn = pc;
+ req->srv = pc->srv;
         req->ifcall = fcall;
- pc->ref++;
         pc->conn = c;
+
         if(caninsertkey(&pc->tagmap, fcall.tag, req) == 0) {
                 respond(req, Eduptag);
                 return;
         }
+
         handlereq(req);
         return;
 
 Fail:
+ thread->unlock(&pc->rlock);
         ixp_hangup(c);
         return;
 }
@@ -279,7 +302,7 @@ handlereq(Ixp9Req *r) {
                 }
                 pc->srv->write(r);
                 break;
- /* Still to be implemented: flush, wstat, auth */
+ /* Still to be implemented: wstat, auth */
         }
 }
 
@@ -299,9 +322,16 @@ respond(Ixp9Req *r, char *error) {
                 assert(error == nil);
                 free(r->ifcall.version);
 
- pc->msg.size = min(r->ofcall.msize, IXP_MAX_MSG);
- pc->msg.data = ixp_erealloc(pc->msg.data, pc->msg.size);
- r->ofcall.msize = pc->msg.size;
+ thread->lock(&pc->rlock);
+ thread->lock(&pc->wlock);
+ msize = min(r->ofcall.msize, IXP_MAX_MSG);
+ pc->rmsg.data = erealloc(pc->rmsg.data, msize);
+ pc->wmsg.data = erealloc(pc->wmsg.data, msize);
+ pc->rmsg.size = msize;
+ pc->wmsg.size = msize;
+ thread->unlock(&pc->wlock);
+ thread->unlock(&pc->rlock);
+ r->ofcall.msize = msize;
                 break;
         case TAttach:
                 if(error)
@@ -316,7 +346,7 @@ respond(Ixp9Req *r, char *error) {
                         r->fid->qid = r->ofcall.qid;
                 }
                 free(r->ifcall.name);
- r->ofcall.iounit = pc->msg.size - sizeof(ulong);
+ r->ofcall.iounit = pc->rmsg.size - 24;
                 break;
         case TWalk:
                 if(error || r->ofcall.nwqid < r->ifcall.nwname) {
@@ -350,7 +380,7 @@ respond(Ixp9Req *r, char *error) {
         case TRead:
         case TStat:
                 break;
- /* Still to be implemented: flush, wstat, auth */
+ /* Still to be implemented: wstat, auth */
         }
 
         r->ofcall.tag = r->ifcall.tag;
@@ -365,9 +395,11 @@ respond(Ixp9Req *r, char *error) {
         deletekey(&pc->tagmap, r->ifcall.tag);;
 
         if(pc->conn) {
- msize = ixp_fcall2msg(&pc->msg, &r->ofcall);
- if(ixp_sendmsg(pc->conn->fd, &pc->msg) != msize)
+ thread->lock(&pc->wlock);
+ msize = ixp_fcall2msg(&pc->wmsg, &r->ofcall);
+ if(ixp_sendmsg(pc->conn->fd, &pc->wmsg) != msize)
                         ixp_hangup(pc->conn);
+ thread->unlock(&pc->wlock);
         }
 
         switch(r->ofcall.type) {
@@ -379,10 +411,7 @@ respond(Ixp9Req *r, char *error) {
                 break;
         }
         free(r);
-
- pc->ref--;
- if(!pc->conn && pc->ref == 0)
- free_p9conn(pc);
+ decref_p9conn(pc);
 }
 
 /* Flush a pending request */
@@ -395,7 +424,7 @@ voidrequest(void *t) {
         pc = r->conn;
         pc->ref++;
 
- tr = ixp_emallocz(sizeof(Ixp9Req));
+ tr = emallocz(sizeof(Ixp9Req));
         tr->ifcall.type = TFlush;
         tr->ifcall.tag = IXP_NOTAG;
         tr->ifcall.oldtag = r->ifcall.tag;
@@ -414,7 +443,7 @@ voidfid(void *t) {
         pc = f->conn;
         pc->ref++;
 
- tr = ixp_emallocz(sizeof(Ixp9Req));
+ tr = emallocz(sizeof(Ixp9Req));
         tr->ifcall.type = TClunk;
         tr->ifcall.tag = IXP_NOTAG;
         tr->ifcall.fid = f->fid;
@@ -423,29 +452,17 @@ voidfid(void *t) {
         handlereq(tr);
 }
 
-#if 0
-static void
-p9conn_incref(void *r) {
- Ixp9Conn *pc;
-
- pc = *(Ixp9Conn **)r;
- pc->ref++;
-}
-#endif
-
 static void
 cleanupconn(IxpConn *c) {
         Ixp9Conn *pc;
 
         pc = c->aux;
         pc->conn = nil;
- pc->ref++;
         if(pc->ref > 1) {
                 execmap(&pc->tagmap, voidrequest);
                 execmap(&pc->fidmap, voidfid);
         }
- if(--pc->ref == 0)
- free_p9conn(pc);
+ decref_p9conn(pc);
 }
 
 /* Handle incoming 9P connections */
@@ -458,12 +475,18 @@ serve_9pcon(IxpConn *c) {
         if(fd < 0)
                 return;
 
- pc = ixp_emallocz(sizeof(Ixp9Conn));
+ pc = emallocz(sizeof(Ixp9Conn));
+ pc->ref++;
         pc->srv = c->aux;
- pc->msg.size = 1024;
- pc->msg.data = ixp_emalloc(pc->msg.size);
+ pc->rmsg.size = 1024;
+ pc->wmsg.size = 1024;
+ pc->rmsg.data = emalloc(pc->rmsg.size);
+ pc->wmsg.data = emalloc(pc->wmsg.size);
+
         initmap(&pc->tagmap, TAG_BUCKETS, &pc->taghash);
         initmap(&pc->fidmap, FID_BUCKETS, &pc->fidhash);
+ thread->initmutex(&pc->rlock);
+ thread->initmutex(&pc->wlock);
 
         ixp_listen(c->srv, fd, pc, handlefcall, cleanupconn);
 }
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/rpc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libixp/rpc.c Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,262 @@
+/* From Plan 9's libmux.
+ * Copyright (c) 2003 Russ Cox, Massachusetts Institute of Technology
+ * Distributed under the same terms as libixp.
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "ixp_local.h"
+
+static int gettag(IxpClient*, IxpRpc*);
+static void puttag(IxpClient*, IxpRpc*);
+static void enqueue(IxpClient*, IxpRpc*);
+static void dequeue(IxpClient*, IxpRpc*);
+
+void
+muxinit(IxpClient *mux)
+{
+ mux->tagrend.mutex = &mux->lk;
+ mux->sleep.next = &mux->sleep;
+ mux->sleep.prev = &mux->sleep;
+ thread->initmutex(&mux->lk);
+ thread->initmutex(&mux->rlock);
+ thread->initmutex(&mux->wlock);
+ thread->initrendez(&mux->tagrend);
+}
+
+void
+muxfree(IxpClient *mux)
+{
+ thread->mdestroy(&mux->lk);
+ thread->mdestroy(&mux->rlock);
+ thread->mdestroy(&mux->wlock);
+ thread->rdestroy(&mux->tagrend);
+ free(mux->wait);
+}
+
+static void
+initrpc(IxpClient *mux, IxpRpc *r)
+{
+ r->mux = mux;
+ r->waiting = 1;
+ r->r.mutex = &mux->lk;
+ r->p = nil;
+ thread->initrendez(&r->r);
+}
+
+static void
+freemuxrpc(IxpRpc *r)
+{
+ thread->rdestroy(&r->r);
+}
+
+static int
+sendrpc(IxpRpc *r, Fcall *f)
+{
+ int ret;
+ IxpClient *mux;
+
+ ret = 0;
+ mux = r->mux;
+ /* assign the tag, add selves to response queue */
+ thread->lock(&mux->lk);
+ r->tag = gettag(mux, r);
+ f->tag = r->tag;
+ enqueue(mux, r);
+ thread->unlock(&mux->lk);
+
+ thread->lock(&mux->wlock);
+ if(!ixp_fcall2msg(&mux->wmsg, f) || !ixp_sendmsg(mux->fd, &mux->wmsg)) {
+ /* werrstr("settag/send tag %d: %r", tag); fprint(2, "%r\n"); */
+ thread->lock(&mux->lk);
+ dequeue(mux, r);
+ puttag(mux, r);
+ thread->unlock(&mux->lk);
+ ret = -1;
+ }
+ thread->unlock(&mux->wlock);
+ return ret;
+}
+
+static Fcall*
+muxrecv(IxpClient *mux)
+{
+ Fcall *f;
+
+ f = nil;
+ thread->lock(&mux->rlock);
+ if(ixp_recvmsg(mux->fd, &mux->rmsg) == 0)
+ goto fail;
+ f = emallocz(sizeof(Fcall));
+ if(ixp_msg2fcall(&mux->rmsg, f) == 0) {
+ free(f);
+ f = nil;
+ }
+fail:
+ thread->unlock(&mux->rlock);
+ return f;
+}
+
+static void
+dispatchandqlock(IxpClient *mux, Fcall *f)
+{
+ int tag;
+ IxpRpc *r2;
+
+ tag = f->tag - mux->mintag;
+ thread->lock(&mux->lk);
+ /* hand packet to correct sleeper */
+ if(tag < 0 || tag >= mux->mwait) {
+ fprintf(stderr, "libixp: recieved unfeasible tag: %d (min: %d, max: %d)\n", f->tag, mux->mintag, mux->mintag+mux->mwait);
+ goto fail;
+ }
+ r2 = mux->wait[tag];
+ if(r2 == nil || r2->prev == nil) {
+ fprintf(stderr, "libixp: recieved message with bad tag\n");
+ goto fail;
+ }
+ r2->p = f;
+ dequeue(mux, r2);
+ thread->wake(&r2->r);
+ return;
+fail:
+ ixp_freefcall(f);
+ free(f);
+}
+
+static void
+electmuxer(IxpClient *mux)
+{
+ IxpRpc *rpc;
+
+ /* if there is anyone else sleeping, wake them to mux */
+ for(rpc=mux->sleep.next; rpc != &mux->sleep; rpc = rpc->next){
+ if(!rpc->async){
+ mux->muxer = rpc;
+ thread->wake(&rpc->r);
+ return;
+ }
+ }
+ mux->muxer = nil;
+}
+
+Fcall*
+muxrpc(IxpClient *mux, Fcall *tx)
+{
+ IxpRpc r;
+ Fcall *p;
+
+ initrpc(mux, &r);
+ if(sendrpc(&r, tx) < 0)
+ return nil;
+
+ thread->lock(&mux->lk);
+ /* wait for our packet */
+ while(mux->muxer && mux->muxer != &r && !r.p)
+ thread->sleep(&r.r);
+
+ /* if not done, there's no muxer; start muxing */
+ if(!r.p){
+ assert(mux->muxer == nil || mux->muxer == &r);
+ mux->muxer = &r;
+ while(!r.p){
+ thread->unlock(&mux->lk);
+ p = muxrecv(mux);
+ if(p == nil){
+ /* eof -- just give up and pass the buck */
+ thread->lock(&mux->lk);
+ dequeue(mux, &r);
+ break;
+ }
+ dispatchandqlock(mux, p);
+ }
+ electmuxer(mux);
+ }
+ p = r.p;
+ puttag(mux, &r);
+ thread->unlock(&mux->lk);
+ if(p == nil)
+ werrstr("unexpected eof");
+ return p;
+}
+
+static void
+enqueue(IxpClient *mux, IxpRpc *r)
+{
+ r->next = mux->sleep.next;
+ r->prev = &mux->sleep;
+ r->next->prev = r;
+ r->prev->next = r;
+}
+
+static void
+dequeue(IxpClient *mux, IxpRpc *r)
+{
+ r->next->prev = r->prev;
+ r->prev->next = r->next;
+ r->prev = nil;
+ r->next = nil;
+}
+
+static int
+gettag(IxpClient *mux, IxpRpc *r)
+{
+ int i, mw;
+ IxpRpc **w;
+
+ for(;;){
+ /* wait for a free tag */
+ while(mux->nwait == mux->mwait){
+ if(mux->mwait < mux->maxtag-mux->mintag){
+ mw = mux->mwait;
+ if(mw == 0)
+ mw = 1;
+ else
+ mw <<= 1;
+ w = realloc(mux->wait, mw*sizeof(w[0]));
+ if(w == nil)
+ return -1;
+ memset(w+mux->mwait, 0, (mw-mux->mwait)*sizeof(w[0]));
+ mux->wait = w;
+ mux->freetag = mux->mwait;
+ mux->mwait = mw;
+ break;
+ }
+ thread->sleep(&mux->tagrend);
+ }
+
+ i=mux->freetag;
+ if(mux->wait[i] == 0)
+ goto Found;
+ for(; i<mux->mwait; i++)
+ if(mux->wait[i] == 0)
+ goto Found;
+ for(i=0; i<mux->freetag; i++)
+ if(mux->wait[i] == 0)
+ goto Found;
+ /* should not fall out of while without free tag */
+ abort();
+ }
+
+Found:
+ mux->nwait++;
+ mux->wait[i] = r;
+ r->tag = i+mux->mintag;
+ return r->tag;
+}
+
+static void
+puttag(IxpClient *mux, IxpRpc *r)
+{
+ int i;
+
+ i = r->tag - mux->mintag;
+ assert(mux->wait[i] == r);
+ mux->wait[i] = nil;
+ mux->nwait--;
+ mux->freetag = i;
+ thread->wake(&mux->tagrend);
+ freemuxrpc(r);
+}
+
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/server.c
--- a/libixp/server.c Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/server.c Sun Jul 01 07:35:51 2007 -0400
@@ -6,7 +6,7 @@
 #include <stdlib.h>
 #include <sys/socket.h>
 #include <unistd.h>
-#include "ixp.h"
+#include "ixp_local.h"
 
 IxpConn *
 ixp_listen(IxpServer *s, int fd, void *aux,
@@ -15,7 +15,7 @@ ixp_listen(IxpServer *s, int fd, void *a
                 ) {
         IxpConn *c;
 
- c = ixp_emallocz(sizeof(IxpConn));
+ c = emallocz(sizeof(IxpConn));
         c->fd = fd;
         c->aux = aux;
         c->srv = s;
@@ -70,7 +70,7 @@ handle_conns(IxpServer *s) {
         }
 }
 
-char *
+int
 ixp_serverloop(IxpServer *s) {
         int r;
 
@@ -83,11 +83,11 @@ ixp_serverloop(IxpServer *s) {
                 if(r < 0) {
                         if(errno == EINTR)
                                 continue;
- return "fatal select error";
+ return 1;
                 }
                 handle_conns(s);
         }
- return nil;
+ return 0;
 }
 
 void
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/socket.c
--- a/libixp/socket.c Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/socket.c Sun Jul 01 07:35:51 2007 -0400
@@ -13,7 +13,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <unistd.h>
-#include "ixp.h"
+#include "ixp_local.h"
 
 /* Note: These functions modify the strings that they are passed.
  * The lookup function duplicates the original string, so it is
@@ -31,14 +31,14 @@ get_port(char *addr) {
 
         s = strchr(addr, '!');
         if(s == nil) {
- errstr = "no port provided";
+ werrstr("no port provided");
                 return -1;
         }
 
         *s++ = '\0';
         port = strtol(s, &end, 10);
         if(*s == '\0' && *end != '\0') {
- errstr = "invalid port number";
+ werrstr("invalid port number");
                 return -1;
         }
         return port;
@@ -55,10 +55,8 @@ sock_unix(char *address, sockaddr_un *sa
         *salen = SUN_LEN(sa);
 
         fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if(fd < 0) {
- errstr = strerror(errno);
- return -1;
- }
+ if(fd < 0)
+ return -1;
         return fd;
 }
 
@@ -75,7 +73,7 @@ sock_tcp(char *host, sockaddr_in *sa) {
         signal(SIGPIPE, SIG_IGN);
         fd = socket(AF_INET, SOCK_STREAM, 0);
         if(fd < 0)
- goto fail;
+ return -1;
 
         memset(sa, 0, sizeof(sa));
         sa->sin_family = AF_INET;
@@ -86,13 +84,8 @@ sock_tcp(char *host, sockaddr_in *sa) {
         else if((he = gethostbyname(host)))
                 memcpy(&sa->sin_addr, he->h_addr, he->h_length);
         else
- goto fail;
-
- return fd;
-
-fail:
- errstr = strerror(errno);
- return -1;
+ return -1;
+ return fd;
 }
 
 static int
@@ -106,7 +99,6 @@ dial_unix(char *address) {
                 return fd;
 
         if(connect(fd, (sockaddr*) &sa, salen)) {
- errstr = strerror(errno);
                 close(fd);
                 return -1;
         }
@@ -140,7 +132,6 @@ announce_unix(char *file) {
         return fd;
 
 fail:
- errstr = strerror(errno);
         close(fd);
         return -1;
 }
@@ -155,7 +146,6 @@ dial_tcp(char *host) {
                 return fd;
 
         if(connect(fd, (sockaddr*)&sa, sizeof(sa))) {
- errstr = strerror(errno);
                 close(fd);
                 return -1;
         }
@@ -181,7 +171,6 @@ announce_tcp(char *host) {
         return fd;
 
 fail:
- errstr = strerror(errno);
         close(fd);
         return -1;
 }
@@ -206,17 +195,17 @@ lookup(char *address, addrtab *tab) {
         int ret;
 
         ret = -1;
- type = ixp_estrdup(address);
+ type = estrdup(address);
 
         addr = strchr(type, '!');
         if(addr == nil)
- errstr = "no address type defined";
+ werrstr("no address type defined");
         else {
                 *addr++ = '\0';
                 for(; tab->type; tab++)
                         if(strcmp(tab->type, type) == 0) break;
                 if(tab->type == nil)
- errstr = "unsupported address type";
+ werrstr("unsupported address type");
                 else
                         ret = tab->fn(addr);
         }
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/thread.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libixp/thread.c Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,95 @@
+#include <unistd.h>
+#include "ixp_local.h"
+
+static IxpThread ixp_nothread;
+IxpThread *ixp_thread = &ixp_nothread;
+
+static char*
+errbuf() {
+ static char errbuf[IXP_ERRMAX];
+
+ return errbuf;
+}
+
+static void
+mvoid(IxpMutex *m) {
+ USED(m);
+ return;
+}
+
+static int
+mtrue(IxpMutex *m) {
+ USED(m);
+ return 1;
+}
+
+static int
+mfalse(IxpMutex *m) {
+ USED(m);
+ return 0;
+}
+
+static void
+rwvoid(IxpRWLock *rw) {
+ USED(rw);
+ return;
+}
+
+static int
+rwtrue(IxpRWLock *rw) {
+ USED(rw);
+ return 1;
+}
+
+static int
+rwfalse(IxpRWLock *m) {
+ USED(m);
+ return 0;
+}
+
+static void
+rvoid(IxpRendez *r) {
+ USED(r);
+ return;
+}
+
+static int
+rfalse(IxpRendez *r) {
+ USED(r);
+ return 0;
+}
+
+static void
+rsleep(IxpRendez *r) {
+ USED(r);
+ eprint("rsleep called when not implemented\n");
+}
+
+static IxpThread ixp_nothread = {
+ /* RWLock */
+ .initrwlock = rwfalse,
+ .rlock = rwvoid,
+ .runlock = rwvoid,
+ .canrlock = rwtrue,
+ .wlock = rwvoid,
+ .wunlock = rwvoid,
+ .canwlock = rwtrue,
+ .rwdestroy = rwvoid,
+ /* Mutex */
+ .initmutex = mfalse,
+ .lock = mvoid,
+ .unlock = mvoid,
+ .canlock = mtrue,
+ .mdestroy = mvoid,
+ /* Rendez */
+ .initrendez = rfalse,
+ .sleep = rsleep,
+ .wake = rfalse,
+ .wakeall = rfalse,
+ .rdestroy = rvoid,
+ /* Other */
+ .errbuf = errbuf,
+ .read = read,
+ .write = write,
+};
+
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/transport.c
--- a/libixp/transport.c Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/transport.c Sun Jul 01 07:35:51 2007 -0400
@@ -1,7 +1,6 @@
 /* Copyright ©2007 Kris Maglione <fbsdaemon_AT_gmail.com>
  * See LICENSE file for license details.
  */
-#include "ixp.h"
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
@@ -11,39 +10,38 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <unistd.h>
+#include "ixp_local.h"
 
 static int
-mread(int fd, Message *msg, uint count) {
+mread(int fd, IxpMsg *msg, uint count) {
         int r, n;
 
         n = msg->end - msg->pos;
         if(n <= 0) {
- errstr = "buffer full";
+ werrstr("buffer full");
                 return -1;
         }
         if(n > count)
                 n = count;
 
- r = read(fd, msg->pos, n);
+ r = ixp_thread->read(fd, msg->pos, n);
         if(r > 0)
                 msg->pos += r;
         return r;
 }
 
 static int
-readn(int fd, Message *msg, uint count) {
+readn(int fd, IxpMsg *msg, uint count) {
         uint num;
         int r;
 
- errstr = nil;
         num = count;
         while(num > 0) {
                 r = mread(fd, msg, num);
- if(r < 1) {
- if(errstr == nil)
- errstr = "broken pipe";
- else if(errno == EINTR)
- continue;
+ if(r == -1 && errno == EINTR)
+ continue;
+ if(r == 0) {
+ werrstr("broken pipe");
                         return count - num;
                 }
                 num -= r;
@@ -52,16 +50,16 @@ readn(int fd, Message *msg, uint count)
 }
 
 uint
-ixp_sendmsg(int fd, Message *msg) {
+ixp_sendmsg(int fd, IxpMsg *msg) {
         int r;
 
         msg->pos = msg->data;
         while(msg->pos < msg->end) {
- r = write(fd, msg->pos, msg->end - msg->pos);
+ r = ixp_thread->write(fd, msg->pos, msg->end - msg->pos);
                 if(r < 1) {
                         if(errno == EINTR)
                                 continue;
- errstr = "broken pipe";
+ werrstr("broken pipe");
                         return 0;
                 }
                 msg->pos += r;
@@ -70,7 +68,7 @@ ixp_sendmsg(int fd, Message *msg) {
 }
 
 uint
-ixp_recvmsg(int fd, Message *msg) {
+ixp_recvmsg(int fd, IxpMsg *msg) {
         enum { SSize = 4 };
         uint msize, size;
 
@@ -85,11 +83,11 @@ ixp_recvmsg(int fd, Message *msg) {
 
         size = msize - SSize;
         if(msg->pos + size >= msg->end) {
- errstr = "message too large";
+ werrstr("message too large");
                 return 0;
         }
         if(readn(fd, msg, size) != size) {
- errstr = "message incomplete";
+ werrstr("message incomplete");
                 return 0;
         }
 
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp/util.c
--- a/libixp/util.c Sun Jun 17 17:01:24 2007 -0400
+++ b/libixp/util.c Sun Jul 01 07:35:51 2007 -0400
@@ -6,10 +6,10 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include "ixp.h"
+#include "ixp_local.h"
 
 void
-ixp_eprint(const char *fmt, ...) {
+eprint(const char *fmt, ...) {
         va_list ap;
         int err;
 
@@ -54,7 +54,7 @@ mfatal(char *name, uint size) {
 }
 
 void *
-ixp_emalloc(uint size) {
+emalloc(uint size) {
         void *ret = malloc(size);
         if(!ret)
                 mfatal("malloc", size);
@@ -62,14 +62,14 @@ ixp_emalloc(uint size) {
 }
 
 void *
-ixp_emallocz(uint size) {
- void *ret = ixp_emalloc(size);
+emallocz(uint size) {
+ void *ret = emalloc(size);
         memset(ret, 0, size);
         return ret;
 }
 
 void *
-ixp_erealloc(void *ptr, uint size) {
+erealloc(void *ptr, uint size) {
         void *ret = realloc(ptr, size);
         if(!ret)
                 mfatal("realloc", size);
@@ -77,7 +77,7 @@ ixp_erealloc(void *ptr, uint size) {
 }
 
 char *
-ixp_estrdup(const char *str) {
+estrdup(const char *str) {
         void *ret = strdup(str);
         if(!ret)
                 mfatal("strdup", strlen(str));
@@ -85,7 +85,7 @@ ixp_estrdup(const char *str) {
 }
 
 uint
-ixp_tokenize(char *res[], uint reslen, char *str, char delim) {
+tokenize(char *res[], uint reslen, char *str, char delim) {
         char *s;
         uint i;
 
@@ -103,7 +103,7 @@ ixp_tokenize(char *res[], uint reslen, c
 }
 
 uint
-ixp_strlcat(char *dst, const char *src, uint size) {
+strlcat(char *dst, const char *src, uint size) {
         const char *s;
         char *d;
         int n, len;
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp_pthread/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libixp_pthread/Makefile Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,10 @@
+ROOT= ..
+include ${ROOT}/mk/hdr.mk
+include ${ROOT}/mk/ixp.mk
+
+TARG = libixp_pthread
+
+OBJ = thread_pthread
+
+include ${ROOT}/mk/lib.mk
+
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp_pthread/thread_pthread.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libixp_pthread/thread_pthread.c Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,181 @@
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "ixp_local.h"
+#include "ixp_pthread.h"
+
+static IxpThread ixp_pthread;
+static pthread_key_t errstr_k;
+
+int
+ixp_pthread_init() {
+ int ret;
+
+ ret = pthread_key_create(&errstr_k, free);
+ if(ret) {
+ werrstr("can't create TLS value: %s", ixp_errbuf());
+ return 1;
+ }
+
+ ixp_thread = &ixp_pthread;
+ return 0;
+}
+
+static char*
+errbuf(void) {
+ char *ret;
+
+ ret = pthread_getspecific(errstr_k);
+ if(ret == nil) {
+ ret = emallocz(IXP_ERRMAX);
+ pthread_setspecific(errstr_k, (void*)ret);
+ }
+ return ret;
+}
+
+static void
+mlock(IxpMutex *m) {
+ pthread_mutex_lock(m->aux);
+}
+
+static int
+mcanlock(IxpMutex *m) {
+ return !pthread_mutex_trylock(m->aux);
+}
+
+static void
+munlock(IxpMutex *m) {
+ pthread_mutex_unlock(m->aux);
+}
+
+static void
+mdestroy(IxpMutex *m) {
+ pthread_mutex_destroy(m->aux);
+ free(m->aux);
+}
+
+static int
+initmutex(IxpMutex *m) {
+ pthread_mutex_t *mutex;
+
+ mutex = emalloc(sizeof *mutex);
+ if(pthread_mutex_init(mutex, nil)) {
+ free(mutex);
+ return 1;
+ }
+
+ m->aux = mutex;
+ return 0;
+}
+
+static void
+rlock(IxpRWLock *rw) {
+ pthread_rwlock_rdlock(rw->aux);
+}
+
+static int
+canrlock(IxpRWLock *rw) {
+ return !pthread_rwlock_tryrdlock(rw->aux);
+}
+
+static void
+wlock(IxpRWLock *rw) {
+ pthread_rwlock_rdlock(rw->aux);
+}
+
+static int
+canwlock(IxpRWLock *rw) {
+ return !pthread_rwlock_tryrdlock(rw->aux);
+}
+
+static void
+rwunlock(IxpRWLock *rw) {
+ pthread_rwlock_unlock(rw->aux);
+}
+
+static void
+rwdestroy(IxpRWLock *rw) {
+ pthread_rwlock_destroy(rw->aux);
+ free(rw->aux);
+}
+
+static int
+initrwlock(IxpRWLock *rw) {
+ pthread_rwlock_t *rwlock;
+
+ rwlock = emalloc(sizeof *rwlock);
+ if(pthread_rwlock_init(rwlock, nil)) {
+ free(rwlock);
+ return 1;
+ }
+
+ rw->aux = rwlock;
+ return 0;
+}
+
+static void
+rsleep(IxpRendez *r) {
+ pthread_cond_wait(r->aux, r->mutex->aux);
+}
+
+static int
+rwake(IxpRendez *r) {
+ pthread_cond_signal(r->aux);
+ return 0;
+}
+
+static int
+rwakeall(IxpRendez *r) {
+ pthread_cond_broadcast(r->aux);
+ return 0;
+}
+
+static void
+rdestroy(IxpRendez *r) {
+ pthread_cond_destroy(r->aux);
+ free(r->aux);
+}
+
+static int
+initrendez(IxpRendez *r) {
+ pthread_cond_t *cond;
+
+ cond = emalloc(sizeof *cond);
+ if(pthread_cond_init(cond, nil)) {
+ free(cond);
+ return 1;
+ }
+
+ r->aux = cond;
+ return 0;
+}
+
+static IxpThread ixp_pthread = {
+ /* Mutex */
+ .initmutex = initmutex,
+ .lock = mlock,
+ .canlock = mcanlock,
+ .unlock = munlock,
+ .mdestroy = mdestroy,
+ /* RWLock */
+ .initrwlock = initrwlock,
+ .rlock = rlock,
+ .canrlock = canrlock,
+ .wlock = wlock,
+ .canwlock = canwlock,
+ .runlock = rwunlock,
+ .wunlock = rwunlock,
+ .rwdestroy = rwdestroy,
+ /* Rendez */
+ .initrendez = initrendez,
+ .sleep = rsleep,
+ .wake = rwake,
+ .wakeall = rwakeall,
+ .rdestroy = rdestroy,
+ /* Other */
+ .errbuf = errbuf,
+ .read = read,
+ .write = write,
+};
+
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp_rubythread/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libixp_rubythread/Makefile Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,11 @@
+ROOT= ..
+include ${ROOT}/mk/hdr.mk
+include ${ROOT}/mk/ixp.mk
+
+CFLAGS += ${RUBYINC}
+
+TARG = libixp_rubythread
+OBJ = thread_ruby
+
+include ${ROOT}/mk/lib.mk
+
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp_rubythread/thread_ruby.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libixp_rubythread/thread_ruby.c Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,266 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ruby.h>
+#include "ixp_local.h"
+#include "ixp_rubythread.h"
+
+static IxpThread ixp_rthread;
+static char RWLock[];
+
+int
+ixp_rubyinit(void) {
+ if(rb_require("thread.rb") != Qtrue)
+ return 1;
+ rb_eval_string(RWLock);
+ ixp_thread = &ixp_rthread;
+ return 0;
+}
+
+static char*
+errbuf(void) {
+ static ID key;
+ volatile VALUE val;
+
+ if(key == 0L)
+ key = rb_intern("_ixp_errbuf");
+
+ val = rb_thread_local_aref(rb_thread_current(), key);
+ if(NIL_P(val)) {
+ val = rb_str_new(nil, IXP_ERRMAX);
+ rb_thread_local_aset(rb_thread_current(), key, val);
+ }
+
+ Check_Type(val, T_STRING);
+ return RSTRING(val)->ptr;
+}
+
+static void
+save(char *eval, void **place) {
+ *place = (void*)rb_eval_string(eval);
+ rb_gc_register_address((VALUE*)place);
+}
+
+static void
+unsave(void **place) {
+ rb_gc_unregister_address((VALUE*)place);
+}
+
+#define call(obj, meth, ...) rb_funcall((VALUE)obj, rb_intern(meth), __VA_ARGS__)
+
+/* Mutex */
+static int
+initmutex(IxpMutex *m) {
+ save("Mutex.new", &m->aux);
+ return 0;
+}
+
+static void
+mdestroy(IxpMutex *m) {
+ unsave(&m->aux);
+}
+
+static void
+mlock(IxpMutex *m) {
+ call(m->aux, "lock", 0);
+}
+
+static int
+mcanlock(IxpMutex *m) {
+ return call(m->aux, "trylock", 0);
+}
+
+static void
+munlock(IxpMutex *m) {
+ call(m->aux, "unlock", 0);
+}
+
+/* RWLock */
+static int
+initrwlock(IxpRWLock *rw) {
+ save("RWLock.new", &rw->aux);
+ return 0;
+}
+
+static void
+rwdestroy(IxpRWLock *rw) {
+ unsave(&rw->aux);
+}
+
+static void
+rlock(IxpRWLock *rw) {
+ call(rw->aux, "rdlock", 0);
+}
+
+static int
+canrlock(IxpRWLock *rw) {
+ return call(rw->aux, "tryrdlock", 0) == Qtrue;
+}
+
+static void
+wlock(IxpRWLock *rw) {
+ call(rw->aux, "wrlock", 0);
+}
+
+static int
+canwlock(IxpRWLock *rw) {
+ return call(rw->aux, "trywrlock", 0) == Qtrue;
+}
+
+static void
+rwunlock(IxpRWLock *rw) {
+ call(rw->aux, "unlock", 0);
+}
+
+/* Rendez */
+static int
+initrendez(IxpRendez *r) {
+ save("ConditionVariable.new", &r->aux);
+ return 0;
+}
+
+static void
+rdestroy(IxpRendez *r) {
+ unsave(&r->aux);
+}
+
+static void
+rsleep(IxpRendez *r) {
+ call(r->aux, "wait", 1, (VALUE)r->mutex->aux);
+}
+
+static int
+rwake(IxpRendez *r) {
+ call(r->aux, "signal", 0);
+ return 0;
+}
+
+static int
+rwakeall(IxpRendez *r) {
+ call(r->aux, "broadcast", 0);
+ return 0;
+}
+
+/* Yielding IO */
+static ssize_t
+_read(int fd, void *buf, size_t size) {
+ rb_thread_wait_fd(fd);
+ return read(fd, buf, size);
+}
+
+static ssize_t
+_write(int fd, const void *buf, size_t size) {
+ rb_thread_fd_writable(fd);
+ return write(fd, buf, size);
+}
+
+static IxpThread ixp_rthread = {
+ /* Mutex */
+ .initmutex = initmutex,
+ .lock = mlock,
+ .canlock = mcanlock,
+ .unlock = munlock,
+ .mdestroy = mdestroy,
+ /* RWLock */
+ .initrwlock = initrwlock,
+ .rlock = rlock,
+ .canrlock = canrlock,
+ .wlock = wlock,
+ .canwlock = canwlock,
+ .runlock = rwunlock,
+ .wunlock = rwunlock,
+ .rwdestroy = rwdestroy,
+ /* Rendez */
+ .initrendez = initrendez,
+ .sleep = rsleep,
+ .wake = rwake,
+ .wakeall = rwakeall,
+ .rdestroy = rdestroy,
+ /* Other */
+ .errbuf = errbuf,
+ .read = _read,
+ .write = _write,
+};
+
+static char RWLock[] =
+ "class RWLock \n"
+ " def initialize \n"
+ " @rdqueue = [] \n"
+ " @wrqueue = [] \n"
+ " @wrheld = nil \n"
+ " @rdheld = [] \n"
+ " end \n"
+ " \n"
+ " def rdlock \n"
+ " cr = Thread.critical \n"
+ " while (Thread.critical = true; @wrheld != nil && @rwheld != Thread.current)\n"
+ " @rdqueue.push Thread.current \n"
+ " Thread.stop \n"
+ " end \n"
+ " @wrheld = nil \n"
+ " @rdheld.push Thread.current \n"
+ " \n"
+ " @rdqueue.each {|t| t.wakeup} \n"
+ " Thread.critical = cr \n"
+ " self \n"
+ " end \n"
+ " \n"
+ " def wrlock \n"
+ " cr = Thread.critical \n"
+ " while (Thread.critical = true; \n"
+ " !@rdheld.empty? || (@wrheld != Thread.current && @wrheld != nil)) \n"
+ " @wrqueue.push Thread.current \n"
+ " Thread.stop \n"
+ " end \n"
+ " @wrheld = Thread.current \n"
+ " Thread.critical = cr \n"
+ " self \n"
+ " end \n"
+ " \n"
+ " \n"
+ " def tryrdlock \n"
+ " cr = Thread.critical \n"
+ " if @wrheld == nil \n"
+ " rdlock \n"
+ " true \n"
+ " else \n"
+ " false \n"
+ " end \n"
+ " ensure \n"
+ " Thread.critical = cr \n"
+ " end \n"
+ " \n"
+ " def trywrlock \n"
+ " cr = Thread.critical \n"
+ " if @wrheld == nil && @rdheld.empty? \n"
+ " wrlock \n"
+ " true \n"
+ " else \n"
+ " false \n"
+ " end \n"
+ " ensure \n"
+ " Thread.critical = cr \n"
+ " end \n"
+ " \n"
+ " def unlock \n"
+ " cr = Thread.critical \n"
+ " Thread.critical = true \n"
+ " \n"
+ " if @rdheld.include?(Thread.current) \n"
+ " @rdheld.remove!(Thread.current) \n"
+ " raise if @wrheld \n"
+ " elsif @rwheld != Thread.current \n"
+ " raise \n"
+ " end \n"
+ " \n"
+ " @wrheld = nil \n"
+ " if !@rwqueue.empty? && @rdheld.empty? \n"
+ " @wrheld = @wrqueue.shift \n"
+ " elsif !@rdqueue.empty \n"
+ " @wrheld = @rdqueue.shift \n"
+ " end \n"
+ " @wrheld.wakeup if @wrheld \n"
+ " ensure \n"
+ " Thread.critical = cr \n"
+ " end \n"
+ "end \n";
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp_task/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libixp_task/Makefile Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,11 @@
+ROOT= ..
+include ${ROOT}/mk/hdr.mk
+include ${ROOT}/mk/ixp.mk
+
+CFLAGS += ${TASKINC}
+
+TARG = libixp_task
+OBJ = thread_task
+
+include ${ROOT}/mk/lib.mk
+
diff -r 8773cc4aefd3 -r 763e9c96f726 libixp_task/thread_task.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libixp_task/thread_task.c Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,177 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <task.h>
+#include "ixp_local.h"
+#include "ixp_task.h"
+
+static IxpThread ixp_task;
+
+int
+ixp_taskinit() {
+ ixp_thread = &ixp_task;
+ return 0;
+}
+
+static char*
+errbuf(void) {
+ void **p;
+
+ p = taskdata();
+ if(*p == nil)
+ *p = emallocz(IXP_ERRMAX);
+ return *p;
+}
+
+/* Mutex */
+static int
+initmutex(IxpMutex *m) {
+ m->aux = emallocz(sizeof(QLock));
+ return 0;
+}
+
+static void
+mdestroy(IxpMutex *m) {
+ free(m->aux);
+ m->aux = nil;
+}
+
+static void
+mlock(IxpMutex *m) {
+ qlock(m->aux);
+}
+
+static int
+mcanlock(IxpMutex *m) {
+ return canqlock(m->aux);
+}
+
+static void
+munlock(IxpMutex *m) {
+ qunlock(m->aux);
+}
+
+/* RWLock */
+static int
+initrwlock(IxpRWLock *rw) {
+ rw->aux = emallocz(sizeof(RWLock));
+ return 0;
+}
+
+static void
+rwdestroy(IxpRWLock *rw) {
+ free(rw->aux);
+ rw->aux = nil;
+}
+
+static void
+_rlock(IxpRWLock *rw) {
+ rlock(rw->aux);
+}
+
+static int
+_canrlock(IxpRWLock *rw) {
+ return canrlock(rw->aux);
+}
+
+static void
+_wlock(IxpRWLock *rw) {
+ wlock(rw->aux);
+}
+
+static int
+_canwlock(IxpRWLock *rw) {
+ return canwlock(rw->aux);
+}
+
+static void
+_runlock(IxpRWLock *rw) {
+ runlock(rw->aux);
+}
+
+static void
+_wunlock(IxpRWLock *rw) {
+ wunlock(rw->aux);
+}
+
+/* Rendez */
+static int
+initrendez(IxpRendez *r) {
+ r->aux = emallocz(sizeof(Rendez));
+ return 0;
+}
+
+static void
+rdestroy(IxpRendez *r) {
+ free(r->aux);
+ r->aux = nil;
+}
+
+static void
+rsleep(IxpRendez *r) {
+ Rendez *rz;
+
+ rz = r->aux;
+ rz->l = r->mutex->aux;
+ tasksleep(rz);
+}
+
+static int
+rwake(IxpRendez *r) {
+ Rendez *rz;
+
+ rz = r->aux;
+ rz->l = r->mutex->aux;
+ return taskwakeup(rz);
+}
+
+static int
+rwakeall(IxpRendez *r) {
+ Rendez *rz;
+
+ rz = r->aux;
+ rz->l = r->mutex->aux;
+ return taskwakeupall(rz);
+}
+
+/* Yielding IO */
+static ssize_t
+_read(int fd, void *buf, size_t size) {
+ fdnoblock(fd);
+ return fdread(fd, buf, size);
+}
+
+static ssize_t
+_write(int fd, const void *buf, size_t size) {
+ fdnoblock(fd);
+ return fdwrite(fd, (void*)buf, size);
+}
+
+static IxpThread ixp_task = {
+ /* Mutex */
+ .initmutex = initmutex,
+ .lock = mlock,
+ .canlock = mcanlock,
+ .unlock = munlock,
+ .mdestroy = mdestroy,
+ /* RWLock */
+ .initrwlock = initrwlock,
+ .rlock = _rlock,
+ .canrlock = _canrlock,
+ .wlock = _wlock,
+ .canwlock = _canwlock,
+ .runlock = _runlock,
+ .wunlock = _wunlock,
+ .rwdestroy = rwdestroy,
+ /* Rendez */
+ .initrendez = initrendez,
+ .sleep = rsleep,
+ .wake = rwake,
+ .wakeall = rwakeall,
+ .rdestroy = rdestroy,
+ /* Other */
+ .errbuf = errbuf,
+ .read = _read,
+ .write = _write,
+};
+
diff -r 8773cc4aefd3 -r 763e9c96f726 mk/common.mk
--- a/mk/common.mk Sun Jun 17 17:01:24 2007 -0400
+++ b/mk/common.mk Sun Jul 01 07:35:51 2007 -0400
@@ -1,7 +1,6 @@ all:
 all:
 
 install: all
-depend: cleandep
 
 MANDIRS=${MAN}/man1
 mkdirs:
@@ -10,10 +9,12 @@ mkdirs:
                 mkdir -pm 0755 $$i; \
         done
 
-install: ${HFILES:.h=.install}
-uninstall: ${HFILES:.h=.uninstall}
-
 cleandep:
+ echo CLEANDEP
         rm .depend 2>/dev/null || true
 
+DEP:=${shell if test -f .depend;then echo .depend;else echo /dev/null; fi}
+DEP!=echo /dev/null
+include ${DEP}
+
 .PHONY: all options clean dist install uninstall depend cleandep
diff -r 8773cc4aefd3 -r 763e9c96f726 mk/dir.mk
--- a/mk/dir.mk Sun Jun 17 17:01:24 2007 -0400
+++ b/mk/dir.mk Sun Jul 01 07:35:51 2007 -0400
@@ -1,5 +1,5 @@ MKSUBDIR = targ=$@; \
 MKSUBDIR = targ=$@; \
- for i in ${DIRS}; do \
+ for i in $$dirs; do \
                 if [ ! -d $$i ]; then \
                         echo Skipping nonexistent directory: $$i 1>&2; \
                 else \
@@ -7,19 +7,23 @@ MKSUBDIR = targ=$@; \
                         (cd $$i && ${MAKE} BASE="${BASE}$$i/" $${targ\#d}) || exit $?; \
                 fi; \
         done
+
 dall:
- ${MKSUBDIR}
+ dirs="${DIRS}"; ${MKSUBDIR}
 dclean:
- ${MKSUBDIR}
+ dirs="${DIRS}"; ${MKSUBDIR}
 dinstall:
- ${MKSUBDIR}
+ dirs="${INSTDIRS}"; ${MKSUBDIR}
 duninstall:
- ${MKSUBDIR}
+ dirs="${INSTDIRS}"; ${MKSUBDIR}
 ddepend:
- ${MKSUBDIR}
+ dirs="${DIRS}"; ${MKSUBDIR}
 
 all: dall
 clean: dclean
 install: dinstall
 uninstall: duninstall
 depend: ddepend
+
+INSTDIRS = ${DIRS}
+
diff -r 8773cc4aefd3 -r 763e9c96f726 mk/hdr.mk
--- a/mk/hdr.mk Sun Jun 17 17:01:24 2007 -0400
+++ b/mk/hdr.mk Sun Jul 01 07:35:51 2007 -0400
@@ -3,7 +3,8 @@ all:
 all:
 
 .c.depend:
- ${DEPEND} $< >>.depend
+ echo MKDEP $<
+ ${MKDEP} ${CFLAGS} $< >>.depend
 
 .c.o:
         ${COMPILE} $@ $<
@@ -63,18 +64,21 @@ all:
         rm -f ${MAN}/man1/$<
 
 .O.clean:
- rm $< || true 2>/dev/null
- rm $*.o || true 2>/dev/null
+ rm -f $< || true 2>/dev/null
+ rm -f $*.o || true 2>/dev/null
 .o.clean:
- rm $< || true 2>/dev/null
+ rm -f $< || true 2>/dev/null
 
 printinstall:
 mkdirs:
 clean:
 install: printinstall mkdirs
+depend: cleandep
 
 FILTER = cat
-COMPILE= CC="${CC}" CFLAGS="${CFLAGS} ${EXCFLAGS}" ${ROOT}/util/compile
-LINK= LD="${LD}" LDFLAGS="${LDFLAGS} ${EXLDFLAGS}" ${ROOT}/util/link
+COMPILE= CC="${CC}" CFLAGS="${CFLAGS}" ${ROOT}/util/compile
+LINK= LD="${LD}" LDFLAGS="${LDFLAGS}" ${ROOT}/util/link
 
 include ${ROOT}/config.mk
+CFLAGS += -I$$(echo ${INCPATH}|sed 's/:/ -I/g')
+
diff -r 8773cc4aefd3 -r 763e9c96f726 mk/lib.mk
--- a/mk/lib.mk Sun Jun 17 17:01:24 2007 -0400
+++ b/mk/lib.mk Sun Jul 01 07:35:51 2007 -0400
@@ -1,4 +1,4 @@ LIB = ${TARG}.a
-LIB = ${TARG}.a
+LIB = ${ROOT}/lib/${TARG}.a
 OFILES = ${OBJ:=.o}
 
 all: ${HFILES} ${LIB}
@@ -10,7 +10,7 @@ depend: ${OBJ:=.depend}
 
 libclean:
         for i in ${LIB} ${OFILES}; do \
- rm $$i; \
+ rm -f $$i; \
         done 2>/dev/null || true
 
 printinstall:
@@ -18,7 +18,8 @@ printinstall:
         echo ' Lib: ${LIBDIR}'
 
 ${LIB}: ${OFILES}
- @echo AR $@
+ @echo AR $$($(ROOT)/util/cleanname $(BASE)/$@)
         @${AR} $@ ${OFILES}
+ @${RANLIB} $@
 
 include ${ROOT}/mk/common.mk
diff -r 8773cc4aefd3 -r 763e9c96f726 mk/many.mk
--- a/mk/many.mk Sun Jun 17 17:01:24 2007 -0400
+++ b/mk/many.mk Sun Jul 01 07:35:51 2007 -0400
@@ -12,7 +12,7 @@ printinstall:
 
 manyclean:
         for i in ${TARG:=.o} ${TARG:=.O} ${OFILES}; do \
- rm $$i; \
+ rm -f $$i; \
         done 2>/dev/null || true
 
 include ${ROOT}/mk/common.mk
diff -r 8773cc4aefd3 -r 763e9c96f726 mk/one.mk
--- a/mk/one.mk Sun Jun 17 17:01:24 2007 -0400
+++ b/mk/one.mk Sun Jul 01 07:35:51 2007 -0400
@@ -14,8 +14,10 @@ printinstall:
 
 oneclean:
         for i in ${PROG} ${OFILES}; do \
- rm $$i; \
+ rm -f $$i; \
         done 2>/dev/null || true
+
+${OFILES}: ${HFILES}
 
 ${PROG}: ${OFILES} ${LIB}
         ${LINK} $@ ${OFILES} ${LIB}
diff -r 8773cc4aefd3 -r 763e9c96f726 test/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/README Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,2 @@
+These tests require plan9port.
+
diff -r 8773cc4aefd3 -r 763e9c96f726 test/client.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/client.c Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,149 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <thread.h>
+#include <ixp.h>
+#include <ixp_pthread.h>
+
+extern char *(*_syserrstr)(void);
+char *path;
+
+typedef struct arg arg;
+typedef struct arg2 arg2;
+struct arg {
+ Rendez r;
+ IxpCFid *f;
+ Channel *ch;
+ int j, k;
+};
+
+struct arg2 {
+ Rendez r;
+ IxpClient *c;
+ Channel *ch;
+ int j;
+};
+
+void
+readfile(IxpCFid *f, int j, int k) {
+ Biobuf *b;
+ char *buf, *p, *end;
+ int n;
+
+ fprint(2, "readfile(%p, %d, %d) iounit: %d\n", f, j, k, f->iounit);
+
+ b = Bfdopen(1, OWRITE);
+ Bprint(b, ":: %d %d: ", j, k);
+
+ buf = ixp_emalloc(f->iounit);
+ while((n = ixp_read(f, buf, f->iounit)) > 0) {
+ fprint(2, "+readfile(%p, %d, %d) n=%d\n", f, j, k, n);
+ end = buf+n;
+ p = buf;
+ for(p = buf; p < end; p++) {
+ Bputc(b, *p);
+ if(*p == '\n') {
+ Bflush(b);
+ Bprint(b, ":: %d %d: ", j, k);
+ }
+ }
+ }
+
+ fprint(2, "-readfile(%p, %d, %d) iounit: %d\n", f, j, k, f->iounit);
+ Bputc(b, '\n');
+ Bterm(b);
+}
+
+static void
+_read(void *p) {
+ arg *a;
+ int i, k;
+
+ a = p;
+ k = a->k;
+ print("Start _read: %d\n", a->j, k);
+
+ qlock(a->r.l);
+ sendul(a->ch, 0);
+ rsleep(&a->r);
+ print("Wake _read: %d\n", a->j, k);
+ qunlock(a->r.l);
+
+ for(i = 0; i < 15; i++)
+ readfile(a->f, a->j, k);
+}
+
+static void
+_open(void *p) {
+ arg2 *a2;
+ arg a;
+
+ a2 = p;
+ a.j = a2->j;
+ memset(&a.r, 0, sizeof(a.r));
+ a.r.l = mallocz(sizeof(QLock), 1);
+ a.ch = chancreate(sizeof(ulong), 0);
+
+ print("Start _open: %d\n", a2->j);
+
+ qlock(a2->r.l);
+ sendul(a2->ch, 0);
+ rsleep(&a2->r);
+ print("Wake _open: %d\n", a2->j);
+ qunlock(a2->r.l);
+
+ a.f = ixp_open(a2->c, path, OREAD);
+ if(a.f == nil)
+ sysfatal("can't open %q: %r\n", path);
+
+ for(a.k = 0; a.k < 5; a.k++) {
+ proccreate(_read, &a, mainstacksize);
+ recvul(a.ch);
+ }
+
+ qlock(a.r.l);
+ rwakeupall(&a.r);
+ qunlock(a.r.l);
+ recvul(chancreate(sizeof(ulong),0));
+}
+
+const char *_malloc_options = "A";
+
+void
+threadmain(int argc, char *argv[]) {
+ arg2 a;
+ char *address;
+
+ USED(argc);
+ USED(argv);
+ address = "unix!/tmp/ns.kris.:0/wmii";
+ address = "tcp!localhost!6663";
+ path = "/n/local/var/log/messages";
+
+ quotefmtinstall();
+
+ _syserrstr = ixp_errbuf;
+ if(ixp_pthread_init())
+ sysfatal("can't init pthread: %r\n");
+
+ a.c = ixp_mount(address);
+ if(a.c == nil)
+ sysfatal("can't mount: %r\n");
+
+ memset(&a.r, 0, sizeof(a.r));
+ a.r.l = mallocz(sizeof(QLock), 1);
+ a.ch = chancreate(sizeof(ulong), 0);
+ for(a.j = 0; a.j < 5; a.j++) {
+ proccreate(_open, &a, mainstacksize);
+ recvul(a.ch);
+ }
+
+ qlock(a.r.l);
+ fprint(2, "qlock()\n");
+ rwakeupall(&a.r);
+ fprint(2, "wokeup\n");
+ qunlock(a.r.l);
+ fprint(2, "unlocked\n");
+ recvul(chancreate(sizeof(ulong),0));
+}
+
diff -r 8773cc4aefd3 -r 763e9c96f726 test/mkfile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mkfile Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,12 @@
+<$PLAN9/src/mkhdr
+
+default:V: all
+
+CFLAGS=-I../include -O0
+LDFLAGS=-L../libixp -L../libixp_pthread -lixp -lixp_pthread
+
+TARG=\
+ client\
+
+<$PLAN9/src/mkmany
+
diff -r 8773cc4aefd3 -r 763e9c96f726 test/o.client
Binary file test/o.client has changed
diff -r 8773cc4aefd3 -r 763e9c96f726 util/cleanname
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/util/cleanname Sun Jul 01 07:35:51 2007 -0400
@@ -0,0 +1,18 @@
+#!/bin/sh -f
+
+echo "$@" |
+ awk -F'/+' '{
+ delete a
+ n = 0
+ for(i = 1; i <= NF; i++) {
+ if($i == ".." && n > 0 && a[n] != "..")
+ n--
+ else if($i != "" && $i != ".")
+ a[++n] = $i
+ }
+ s = ""
+ for(i = 1; i <= n; i++)
+ s = s "/" a[i]
+ print substr(s, 2)
+ }'
+
diff -r 8773cc4aefd3 -r 763e9c96f726 util/compile
--- a/util/compile Sun Jun 17 17:01:24 2007 -0400
+++ b/util/compile Sun Jul 01 07:35:51 2007 -0400
@@ -1,20 +1,23 @@
 #!/bin/sh -f
 
 outfile="$1"; shift
+bin="$(echo $0 | sed 's,/[^/]*$,,')"
 
 # Derived from Russ Cox's 9c in plan9port.
 
 xtmp=/tmp/cc.$$.$USER.out
 
-echo CC ${BASE}$outfile
+echo CC $($bin/cleanname ${BASE}$outfile)
 $CC -o $outfile $CFLAGS $@ 2>$xtmp
 status=$?
 
-cat $xtmp \
-| egrep -v ': error: .Each undeclared identifier|: error: for each function it appears|is dangerous, better use|is almost always misused|: In function |: At top level:|support .long long.|use of C99 long long|ISO C forbids conversion' \
-| sed 's/ .first use in this function.$//; s/\"\([^\"][^\"]*\)\", line \([0-9][0-9]*\)/\1:\2/g' \
-| uniq 1>&2
+base=$(echo $BASE | sed 's/,/\\,/g')
 
-rm -f $xtmp $xtmp.status
+cat $xtmp | sed "s,^[^/][^:]*\.c:,$base&,g" |
+ egrep -v ': error: .Each undeclared identifier|: error: for each function it appears|is dangerous, better use|is almost always misused|: In function |: At top level:|support .long long.|use of C99 long long|ISO C forbids conversion' |
+ sed 's/ .first use in this function.$//; s/\"\([^\"][^\"]*\)\", line \([0-9][0-9]*\)/\1:\2/g' |
+ uniq 1>&2
+
+rm -f $xtmp
 exit $status
 
diff -r 8773cc4aefd3 -r 763e9c96f726 util/link
--- a/util/link Sun Jun 17 17:01:24 2007 -0400
+++ b/util/link Sun Jul 01 07:35:51 2007 -0400
@@ -1,6 +1,7 @@
 #!/bin/sh -f
 
 outfile="$1"; shift
+bin="$(echo $0 | sed 's,/[^/]*$,,')"
 
 # Derived from Russ Cox's 9l in plan9port.
 ofiles=""
@@ -19,7 +20,7 @@ done
 
 xtmp=/tmp/ld.$$.$USER.out
 
-echo LD ${BASE}$outfile
+echo LD "$($bin/cleanname ${BASE}$outfile)"
 $LD -o $outfile $ofiles $LDFLAGS $args >$xtmp 2>&1
 status=$?
 
Received on Sun Jul 01 2007 - 13:36:08 UTC

This archive was generated by hypermail 2.2.0 : Sun Jul 13 2008 - 15:57:26 UTC