diff --git a/GNUmakefile b/GNUmakefile index 7bcf902..6225b6d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -10,7 +10,7 @@ INCLUDEDIR=${prefix}/include MAN3DIR=${prefix}/man/man3 LIBS=byte.a fmt.a scan.a str.a uint.a open.a stralloc.a unix.a socket.a \ -buffer.a mmap.a taia.a tai.a dns.a case.a mult.a +buffer.a mmap.a taia.a tai.a dns.a case.a mult.a array.a io.a all: t $(LIBS) libowfat.a @@ -18,11 +18,11 @@ all: t $(LIBS) libowfat.a # diet libc (http://www.fefe.de/dietlibc/). DIET=/opt/diet/bin/diet -Os CC=gcc -CFLAGS=-I. -pipe -Wall -O2 -fomit-frame-pointer +CFLAGS=-pipe -Wall -O2 -fomit-frame-pointer #CFLAGS=-pipe -Os -march=pentiumpro -mcpu=pentiumpro -fomit-frame-pointer -fschedule-insns2 -Wall # startrip -VPATH=str:byte:fmt:scan:uint:open:stralloc:unix:socket:buffer:mmap:textcode:taia:tai:dns:case:array:mult +VPATH=str:byte:fmt:scan:uint:open:stralloc:unix:socket:buffer:mmap:textcode:taia:tai:dns:case:array:mult:io BYTE_OBJS=$(patsubst byte/%.c,%.o,$(wildcard byte/*.c)) FMT_OBJS=$(patsubst fmt/%.c,%.o,$(wildcard fmt/*.c)) @@ -42,6 +42,7 @@ DNS_OBJS=$(patsubst dns/%.c,%.o,$(wildcard dns/*.c)) CASE_OBJS=$(patsubst case/%.c,%.o,$(wildcard case/*.c)) ARRAY_OBJS=$(patsubst array/%.c,%.o,$(wildcard array/*.c)) MULT_OBJS=$(patsubst mult/%.c,%.o,$(wildcard mult/*.c)) +IO_OBJS=$(patsubst io/%.c,%.o,$(wildcard io/*.c)) $(BYTE_OBJS): byte.h $(FMT_OBJS): fmt.h @@ -59,6 +60,7 @@ $(DNS_OBJS): dns.h stralloc.h taia.h tai.h uint64.h iopause.h $(CASE_OBJS): case.h $(ARRAY_OBJS): uint64.h array.h $(MULT_OBJS): uint64.h uint32.h uint16.h safemult.h +$(IO_OBJS): uint64.h array.h io.h iopause.o: select.h openreadclose.o readclose.o: readclose.h @@ -83,14 +85,16 @@ dns.a: $(DNS_OBJS) case.a: $(CASE_OBJS) array.a: $(ARRAY_OBJS) mult.a: $(MULT_OBJS) +io.a: $(IO_OBJS) libowfat.a: $(DNS_OBJS) $(BYTE_OBJS) $(FMT_OBJS) $(SCAN_OBJS) \ $(STR_OBJS) $(UINT_OBJS) $(OPEN_OBJS) $(STRA_OBJS) $(UNIX_OBJS) \ $(SOCKET_OBJS) $(BUFFER_OBJS) $(MMAP_OBJS) $(TEXTCODE_OBJS) \ -$(TAIA_OBJS) $(TAI_OBJS) $(CASE_OBJS) $(ARRAY_OBJS) $(MULT_OBJS) +$(TAIA_OBJS) $(TAI_OBJS) $(CASE_OBJS) $(ARRAY_OBJS) $(MULT_OBJS) \ +$(IO_OBJS) %.o: %.c - $(DIET) $(CC) -c $< -o $@ $(CFLAGS) + $(DIET) $(CC) -c $< -o $@ -I. $(CFLAGS) %.a: ar cr $@ $^ diff --git a/array.h b/array.h index 0889f23..0afbdc9 100644 --- a/array.h +++ b/array.h @@ -31,4 +31,7 @@ void array_cats0(array* to,const char* from); void array_cat0(array* to); void array_cate(array* to,const array* const from,int64 pos,int64 stop); +#define array_failed(x) (array_bytes(x)==-1) +#define array_allocated(x) (array_bytes(x)==0) + #endif diff --git a/array/array.3 b/array/array.3 new file mode 100644 index 0000000..762b925 --- /dev/null +++ b/array/array.3 @@ -0,0 +1,92 @@ +.TH array 3 +.SH NAME +array \- The array library interface +.SH SYNTAX +.B #include + +.SH DESCRIPTION +An \fBallocated\fR array variable keeps track of + +.sp 1 +.IP \(bu +a (nonzero) pointer to a dynamically allocated region of memory; +.IP \(bu +the number of bytes allocated (always positive); and +.IP \(bu +the number of bytes initialized (between 0 and the number of bytes +allocated). +.PP + +There are two other possibilities for the state of an array variable: +\fBunallocated\fR and \fIfailed\fR. In both cases, there is no +dynamically allocated region of memory. + +A new array variable is normally created as a static variable: + + #include "array.h" + + static array x; + +At this point it is unallocated. The array library provides various +allocation and inspection functions. + +A new array variable can also be created dynamically. It must be +initialized to all-0, meaning unallocated, before it is given to any of +the array functions. It must be returned to the unallocated (or failed) +state, for example with array_reset, before it is destroyed. These rules +prevent all memory leaks. +.SH "Expansion and inspection" + + array x; + + t* p1 = array_allocate(&x,sizeof(t),pos); + + t* p2 = array_get(&x,sizeof(t),pos); + + t* p3 = array_start(&x); + + int64 len = array_length(&x,sizeof(t)); + + int64 bytes = array_bytes(&x); + +.SH "Truncation and deallocation" + + array x; + + array_truncate(&x,sizeof(t),len); + + array_trunc(&x); + + array_reset(&x); + + array_fail(&x); + +.SH "Comparison" + + array x; + array y; + + if (array_equal(&x,&y)) + /* arrays are equal... */ + +.SH "Concatenation" + + array x; + array y; + + array_cat(&x,&y); + + array_catb(&x,"fnord",5); + + array_cats(&x,"fnord"); + + array_cats0(&x,"fnord"); /* also append the \\0 */ + + array_cat0(&x); /* append \\0 */ + + array_cate(&x,"fnord",1,4); /* append "nor" */ + +.SH "ORIGINAL API DEFINITION" +http://cr.yp.to/lib/array.html +.SH "SEE ALSO" +array_get(3), array_start(3), array_fail(3) diff --git a/io.h b/io.h index 71ae38b..327fe8a 100644 --- a/io.h +++ b/io.h @@ -4,7 +4,7 @@ /* http://cr.yp.to/lib/io.html */ #include "uint64.h" -#include "tai.h" +#include "taia.h" /* like open(s,O_RDONLY) */ int io_readfile(int64* d,const char* s); @@ -58,4 +58,6 @@ void io_nonblock(int64 d); /* put descriptor in close-on-exec mode */ void io_closeonexec(int64 d); +void io_close(int64 d); + #endif diff --git a/io/io_close.c b/io/io_close.c new file mode 100644 index 0000000..b00a211 --- /dev/null +++ b/io/io_close.c @@ -0,0 +1,8 @@ +#include +#include "io_internal.h" + +void io_close(int64 d) { + close(d); + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + if (e) e->inuse=0; +} diff --git a/io/io_closeonexec.c b/io/io_closeonexec.c new file mode 100644 index 0000000..a305993 --- /dev/null +++ b/io/io_closeonexec.c @@ -0,0 +1,8 @@ +#include +#include +#include +#include "io_internal.h" + +void io_closeonexec(int64 d) { + fcntl(d,F_SETFL,fcntl(d,F_GETFL,0) | FD_CLOEXEC); +} diff --git a/io/io_createfile.c b/io/io_createfile.c new file mode 100644 index 0000000..4344849 --- /dev/null +++ b/io/io_createfile.c @@ -0,0 +1,15 @@ +#include +#include +#include "io_internal.h" + +int io_createfile(int64* d,const char* s) { + long fd=open(s,O_WRONLY|O_CREAT|O_TRUNC,0600); + if (fd != -1) { + if (io_fd(fd)) { + *d=fd; + return 1; + } + close(fd); + } + return 0; +} diff --git a/io/io_dontwantread.c b/io/io_dontwantread.c new file mode 100644 index 0000000..db8d91c --- /dev/null +++ b/io/io_dontwantread.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include "io_internal.h" + +void io_dontwantread(int64 d) { + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + if (!e) return; + if (e->wantread && !e->wantwrite) --io_wanted_fds; + e->wantread=0; +} diff --git a/io/io_dontwantwrite.c b/io/io_dontwantwrite.c new file mode 100644 index 0000000..a0e4716 --- /dev/null +++ b/io/io_dontwantwrite.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include "io_internal.h" + +void io_dontwantwrite(int64 d) { + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + if (!e) return; + if (!e->wantread && e->wantwrite) --io_wanted_fds; + e->wantwrite=0; +} diff --git a/io/io_fd.c b/io/io_fd.c new file mode 100644 index 0000000..cfc4e11 --- /dev/null +++ b/io/io_fd.c @@ -0,0 +1,16 @@ +#include +#include + +#include "io_internal.h" + +/* put d on internal data structure, return 1 on success, 0 on error */ +int io_fd(int64 d) { + long r; + io_entry* e; + if ((r=fcntl(d,F_GETFL,0) & O_NDELAY) == -1) + return 0; /* file descriptor not open */ + if (!(e=array_allocate(&io_fds,sizeof(io_entry),d))) return 0; + e->inuse=1; + if (r&O_NDELAY) e->nonblock=1; + return 1; +} diff --git a/io/io_nonblock.c b/io/io_nonblock.c new file mode 100644 index 0000000..ac26c24 --- /dev/null +++ b/io/io_nonblock.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include "io_internal.h" + +void io_nonblock(int64 d) { + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + if (e && e->nonblock) return; + fcntl(d,F_SETFL,fcntl(d,F_GETFL,0) | O_NDELAY); + if (e) e->nonblock=1; +} diff --git a/io/io_pipe.c b/io/io_pipe.c new file mode 100644 index 0000000..6f40413 --- /dev/null +++ b/io/io_pipe.c @@ -0,0 +1,18 @@ +#include +#include "io_internal.h" + +int io_pipe(int64* d) { + int fds[2]; + if (pipe(fds)==-1) + return 0; + if (io_fd(fds[1])) { + if (io_fd(fds[0])) { + d[0]=fds[0]; + d[1]=fds[1]; + return 1; + } + io_close(fds[1]); + } + close(fds[0]); + return 0; +} diff --git a/io/io_readfile.c b/io/io_readfile.c new file mode 100644 index 0000000..99261f5 --- /dev/null +++ b/io/io_readfile.c @@ -0,0 +1,15 @@ +#include +#include +#include "io_internal.h" + +int io_readfile(int64* d,const char* s) { + long fd=open(s,O_RDONLY); + if (fd != -1) { + if (io_fd(fd)) { + *d=fd; + return 1; + } + close(fd); + } + return 0; +} diff --git a/io/io_tryread.c b/io/io_tryread.c new file mode 100644 index 0000000..4cd922b --- /dev/null +++ b/io/io_tryread.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include "io_internal.h" + +int64 io_tryread(int64 d,char* buf,int64 len) { + long r; + struct itimerval old,new; + struct pollfd p; + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + if (!e) { errno=EBADF; return -3; } + if (!e->nonblock) { + p.fd=d; + if (p.fd != d) { errno=EBADF; return -3; } /* catch overflow */ + p.events=POLLIN; + switch (poll(&p,1,0)) { + case -1: return -3; + case 0: errno=EAGAIN; return -1; + } + new.it_interval.tv_usec=0; + new.it_interval.tv_sec=0; + new.it_value.tv_usec=10000; + new.it_value.tv_sec=0; + setitimer(ITIMER_REAL,&new,&old); + } + r=read(d,buf,len); + if (!e->nonblock) { + new.it_interval.tv_usec=0; + new.it_interval.tv_sec=0; + new.it_value.tv_usec=0; + new.it_value.tv_sec=0; + setitimer(ITIMER_REAL,&new,&old); + } + if (r==-1) { + if (errno==EINTR) errno=EAGAIN; + if (errno!=EAGAIN) + r=-3; + } + return r; +} diff --git a/io/io_trywrite.c b/io/io_trywrite.c new file mode 100644 index 0000000..21bd2d9 --- /dev/null +++ b/io/io_trywrite.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include "io_internal.h" + +int64 io_trywrite(int64 d,const char* buf,int64 len) { + long r; + struct itimerval old,new; + struct pollfd p; + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + if (!e) { errno=EBADF; return -3; } + if (!e->nonblock) { + p.fd=d; + if (p.fd != d) { errno=EBADF; return -3; } /* catch overflow */ + p.events=POLLOUT; + switch (poll(&p,1,0)) { + case -1: return -3; + case 0: errno=EAGAIN; return -1; + } + new.it_interval.tv_usec=0; + new.it_interval.tv_sec=0; + new.it_value.tv_usec=10000; + new.it_value.tv_sec=0; + setitimer(ITIMER_REAL,&new,&old); + } + r=write(d,buf,len); + if (!e->nonblock) { + new.it_interval.tv_usec=0; + new.it_interval.tv_sec=0; + new.it_value.tv_usec=0; + new.it_value.tv_sec=0; + setitimer(ITIMER_REAL,&new,&old); + } + if (r==-1) + if (errno!=EAGAIN) + r=-3; + return r; +} diff --git a/io/io_wait.c b/io/io_wait.c new file mode 100644 index 0000000..7ea4d8c --- /dev/null +++ b/io/io_wait.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include "io_internal.h" + +void io_wait() { + struct pollfd* p; + long i,r; + if (!io_wanted_fds) return; + for (i=r=0; icanread=e->canwrite=0; + if (e->wantread || e->wantwrite) { + struct pollfd* p; + if ((p=array_allocate(&io_pollfds,sizeof(struct pollfd),r))) { + p->fd=i; + p->events=(e->wantread?POLLIN:0) + (e->wantwrite?POLLOUT:0); + ++r; + } else + return; + } + } + p=array_start(&io_pollfds); + while ((i=poll(array_start(&io_pollfds),r,99999999))==0); + if (i==-1) return; + for (i=0; ifd); + if (p->revents&POLLIN) e->canread=1; + if (p->revents&POLLOUT) e->canwrite=1; + p++; + } +} diff --git a/io/io_wantread.c b/io/io_wantread.c new file mode 100644 index 0000000..c136514 --- /dev/null +++ b/io/io_wantread.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include "io_internal.h" + +void io_wantread(int64 d) { + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + if (!e) return; + if (!e->wantread && !e->wantwrite) ++io_wanted_fds; + e->wantread=1; +} diff --git a/io/io_wantwrite.c b/io/io_wantwrite.c new file mode 100644 index 0000000..127b4c5 --- /dev/null +++ b/io/io_wantwrite.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include "io_internal.h" + +void io_wantwrite(int64 d) { + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + if (!e) return; + if (!e->wantread && !e->wantwrite) ++io_wanted_fds; + e->wantwrite=1; +} diff --git a/io_internal.h b/io_internal.h new file mode 100644 index 0000000..768e97e --- /dev/null +++ b/io_internal.h @@ -0,0 +1,15 @@ +#include "io.h" +#include "array.h" + +typedef struct { + unsigned int wantread:1; + unsigned int wantwrite:1; + unsigned int canread:1; + unsigned int canwrite:1; + unsigned int nonblock:1; + unsigned int inuse:1; +} io_entry; + +array io_fds; +uint64 io_wanted_fds; +array io_pollfds; diff --git a/test/array.c b/test/array.c index e198bbd..c3217c3 100644 --- a/test/array.c +++ b/test/array.c @@ -9,5 +9,10 @@ main() { array_cat(&x,&y); array_fail(&y); array_cat(&y,&x); + assert(array_failed(&y)); + array_reset(&y); + array_cats(&y,"fnord"); assert(byte_equal(x.p,11,"fnordfoobar")); + array_cate(&x,&y,1,4); + assert(x.initialized=14 && byte_equal(x.p,14,"fnordfoobarnor")); }