libixp

git clone git://oldgit.suckless.org/libixp/
Log | Files | Refs | LICENSE

commit 2ee5e1aa28992bf2a135bc59af74e65124342488
parent f896fda3da61c27e4ac643b49e7edcec485d1903
Author: Kris Maglione <jg@suckless.org>
Date:   Sun,  1 Jul 2007 07:35:51 -0400

Add threading support.

Diffstat:
Makefile | 2+-
cmd/ixpc.c | 33++++++++++++++++++---------------
config.mk | 14++++++++++++--
include/ixp.h | 413++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
include/ixp_local.h | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/Makefile | 3+++
libixp/client.c | 170++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
libixp/convert.c | 30+++++++++++++++---------------
libixp/error.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/fcall.h | 10+++++-----
libixp/fcall.h.nounion | 10+++++-----
libixp/intmap.c | 25++++++++++++++++++++-----
libixp/ixp_fcall.h | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/message.c | 12++++++------
libixp/request.c | 125+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
libixp/rpc.c | 262+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/server.c | 10+++++-----
libixp/socket.c | 29+++++++++--------------------
libixp/thread.c | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp/transport.c | 32+++++++++++++++-----------------
libixp/util.c | 18+++++++++---------
libixp_pthread/Makefile | 10++++++++++
libixp_pthread/thread_pthread.c | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp_rubythread/Makefile | 11+++++++++++
libixp_rubythread/thread_ruby.c | 266+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libixp_task/Makefile | 11+++++++++++
libixp_task/thread_task.c | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mk/common.mk | 9+++++----
mk/dir.mk | 16++++++++++------
mk/hdr.mk | 16++++++++++------
mk/lib.mk | 7++++---
mk/many.mk | 2+-
mk/one.mk | 4+++-
test/README | 2++
test/client.c | 149+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
test/mkfile | 12++++++++++++
test/o.client | 0
util/cleanname | 18++++++++++++++++++
util/compile | 15+++++++++------
util/link | 3++-
40 files changed, 1990 insertions(+), 373 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ ROOT=. include ${ROOT}/mk/hdr.mk -DIRS = libixp \ +DIRS = ${COMPONENTS} \ cmd \ include \ man diff --git a/cmd/ixpc.c b/cmd/ixpc.c @@ -1,6 +1,8 @@ /* Copyright ©2007 Kris Maglione <fbsdaemon@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 --git a/config.mk b/config.mk @@ -1,5 +1,14 @@ # 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 BIN = ${PREFIX}/bin @@ -9,7 +18,7 @@ LIBDIR = ${PREFIX}/lib 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 --git a/include/ixp.h b/include/ixp.h @@ -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 unsigned long ulong; 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; - /* internal use only */ IxpClient *client; + /* internal use only */ IxpCFid *next; + IxpMutex iolock; }; -typedef struct Ixp9Conn Ixp9Conn; -typedef struct Fid { - Ixp9Conn *conn; - Intmap *map; +struct IxpFid { char *uid; void *aux; - ulong fid; - Qid qid; + ulong fid; + IxpQid qid; signed char omode; -} Fid; -typedef struct Ixp9Req Ixp9Req; -struct Ixp9Req { + /* Implementation details */ Ixp9Conn *conn; - Fid *fid; - Fid *newfid; + Intmap *map; +}; + +struct Ixp9Req { + Ixp9Srv *srv; + IxpFid *fid; + IxpFid *newfid; Ixp9Req *oldreq; - Fcall ifcall; - Fcall ofcall; + IxpFcall ifcall; + IxpFcall ofcall; void *aux; + + /* Implementation details */ + Ixp9Conn *conn; }; -typedef struct Ixp9Srv { +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 @@ void ixp_unmount(IxpClient *c); 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_dial(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 @@ char *ixp_estrdup(const char *str); 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 --git a/include/ixp_local.h b/include/ixp_local.h @@ -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 --git a/libixp/Makefile b/libixp/Makefile @@ -7,11 +7,14 @@ HFILES = ixp_fcall.h OBJ = client \ convert \ + error \ intmap \ message \ request \ + rpc \ server \ socket \ + thread \ transport \ util diff --git a/libixp/client.c b/libixp/client.c @@ -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 @@ static IxpCFid * 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; + Fcall *ret; - type = fcall->type; - if(ixp_fcall2msg(&c->msg, fcall) == 0) { - errstr = "failed to pack message"; - 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; + ret = muxrpc(c, fcall); + if(ret == nil) return 0; + if(ret->type == RError) { + werrstr("%s", ret->ename); + goto fail; } - if(fcall->type != (type^1)) { - ixp_freefcall(fcall); - errstr = "received mismatched fcall"; - return 0; + 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,28 +92,43 @@ 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 * 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 **rest) { 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 @@ static void 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 mode) { 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 count) { 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 count) { 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 count) { 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 count) { 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 count) { } 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 --git a/libixp/convert.c b/libixp/convert.c @@ -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 *val) { } 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, char *strings[]) { } 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, char *strings[]) { } 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, uint len) { } 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 qid[]) { } void -ixp_pstat(Message *msg, Stat *stat) { +ixp_pstat(IxpMsg *msg, Stat *stat) { ushort size; if(msg->mode == MsgPack) diff --git a/libixp/error.c b/libixp/error.c @@ -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 --git a/libixp/fcall.h b/libixp/fcall.h @@ -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 --git a/libixp/fcall.h.nounion b/libixp/fcall.h.nounion @@ -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 --git a/libixp/intmap.c b/libixp/intmap.c @@ -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 @@ void 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)(void*)) { 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 *v) { 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 *v) { 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 --git a/libixp/ixp_fcall.h b/libixp/ixp_fcall.h @@ -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 --git a/libixp/message.c b/libixp/message.c @@ -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 --git a/libixp/request.c b/libixp/request.c @@ -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 @@ static void * createfid(Intmap *map, int fid, Ixp9Conn *pc) { Fid *f; + f = emallocz(sizeof(Fid)); pc->ref++; - f = ixp_emallocz(sizeof(Fid)); + 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; + thread->unlock(&pc->rlock); - req = ixp_emallocz(sizeof(Ixp9Req)); + 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 --git a/libixp/rpc.c b/libixp/rpc.c @@ -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 --git a/libixp/server.c b/libixp/server.c @@ -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 *aux, ) { 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 --git a/libixp/socket.c b/libixp/socket.c @@ -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, socklen_t *salen) { *salen = SUN_LEN(sa); fd = socket(AF_UNIX, SOCK_STREAM, 0); - if(fd < 0) { - errstr = strerror(errno); + 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 -1; return fd; - -fail: - errstr = strerror(errno); - return -1; } 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 --git a/libixp/thread.c b/libixp/thread.c @@ -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 --git a/libixp/transport.c b/libixp/transport.c @@ -1,7 +1,6 @@ /* Copyright ©2007 Kris Maglione <fbsdaemon@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 --git a/libixp/util.c b/libixp/util.c @@ -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, char *str, char delim) { } 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 --git a/libixp_pthread/Makefile b/libixp_pthread/Makefile @@ -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 --git a/libixp_pthread/thread_pthread.c b/libixp_pthread/thread_pthread.c @@ -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 --git a/libixp_rubythread/Makefile b/libixp_rubythread/Makefile @@ -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 --git a/libixp_rubythread/thread_ruby.c b/libixp_rubythread/thread_ruby.c @@ -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 --git a/libixp_task/Makefile b/libixp_task/Makefile @@ -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 --git a/libixp_task/thread_task.c b/libixp_task/thread_task.c @@ -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 --git a/mk/common.mk b/mk/common.mk @@ -1,7 +1,6 @@ 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 --git a/mk/dir.mk b/mk/dir.mk @@ -1,5 +1,5 @@ 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 --git a/mk/hdr.mk b/mk/hdr.mk @@ -3,7 +3,8 @@ 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 --git a/mk/lib.mk b/mk/lib.mk @@ -1,4 +1,4 @@ -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 --git a/mk/many.mk b/mk/many.mk @@ -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 --git a/mk/one.mk b/mk/one.mk @@ -14,9 +14,11 @@ 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 --git a/test/README b/test/README @@ -0,0 +1,2 @@ +These tests require plan9port. + diff --git a/test/client.c b/test/client.c @@ -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 --git a/test/mkfile b/test/mkfile @@ -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 --git a/test/o.client b/test/o.client Binary files differ. diff --git a/util/cleanname b/util/cleanname @@ -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 --git a/util/compile b/util/compile @@ -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 --git a/util/link b/util/link @@ -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=$?