commit 2ee5e1aa28992bf2a135bc59af74e65124342488
parent f896fda3da61c27e4ac643b49e7edcec485d1903
Author: Kris Maglione <jg@suckless.org>
Date: Sun, 1 Jul 2007 07:35:51 -0400
Add threading support.
Diffstat:
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=$?