rcx

miscellaneous C library
git clone git://git.rr3.xyz/rcx
Log | Files | Refs | README | LICENSE

unix.c (2154B)


      1 #include <errno.h>
      2 #include <string.h>
      3 #include <sys/uio.h>
      4 #include <unistd.h>
      5 
      6 #include "debug.h"
      7 #include "rcx.h"
      8 #include "unix.h"
      9 
     10 typedef isize (*IoOp)(int, void *, usize);
     11 
     12 static int
     13 perform_io(usize *n, IoOp op, int fd, void *buf, usize len) {
     14 	usize i = 0;
     15 
     16 	while (i < len) {
     17 		isize ret = op(fd, (char *)buf + i, len - i);
     18 		if (ret < 0) {
     19 			if (errno == EINTR) continue;
     20 			break;
     21 		} else if (ret == 0) {
     22 			errno = 0;
     23 			break;
     24 		}
     25 		i += ret;
     26 	} 
     27 
     28 	if (n) *n = i;
     29 	return i == len ? 0 : -1;
     30 }
     31 
     32 int
     33 r_read_all(usize *n, int fd, void *buf, usize len) {
     34 	return perform_io(n, read, fd, buf, len);
     35 }
     36 
     37 int
     38 r_write_all(usize *n, int fd, void *buf, usize len) {
     39 	/* Cast off const-ness of buf argument from write. */
     40 	return perform_io(n, (IoOp)write, fd, buf, len);
     41 }
     42 
     43 void
     44 r_iovec_gather(void *dst, struct iovec **iov, usize *niov, usize n) {
     45 	for (usize i = 0; *niov > 0; ++*iov, --*niov) {
     46 		usize l = MIN((*iov)->iov_len, n);
     47 		memcpy((char *)dst + i, (*iov)->iov_base, l);
     48 		(*iov)->iov_base = (char *)(*iov)->iov_base + l;
     49 		(*iov)->iov_len -= l;
     50 		i += l;
     51 		n -= l;
     52 
     53 		if ((*iov)->iov_len > 0) break;
     54 	}
     55 
     56 	ASSERT(n == 0);
     57 }
     58 
     59 /* Note for future implementation of r_readv_all: Suppose readv completely
     60  * fills the first k buffers, and only partially fills the kth buffer. Then
     61  * we need to record the original base pointer and length of the kth buffer,
     62  * slice off the partially filled part of the kth buffer, and then call
     63  * readv again with all but the first k buffers. When the kth buffer eventually
     64  * becomes completely filled, restore its original base pointer and length.
     65  * (Of course, at this point, some other buffer now may only be partially
     66  * filled and we need to repeat this logic.) */
     67 
     68 int
     69 r_writev_all(int fd, struct iovec **iov, usize *niov) {
     70 	while (*niov > 0) {
     71 		isize nw = writev(fd, *iov, *niov);
     72 		if (nw < 0) {
     73 			if (errno == EINTR) continue;
     74 			return -1;
     75 		}
     76 
     77 		for (; *niov > 0; ++*iov, --*niov) {
     78 			usize l = MIN((*iov)->iov_len, nw);
     79 			(*iov)->iov_base = (char *)(*iov)->iov_base + l;
     80 			(*iov)->iov_len -= l;
     81 			nw -= l;
     82 
     83 			if ((*iov)->iov_len > 0) break;
     84 		}
     85 
     86 		ASSERT(nw == 0);
     87 	}
     88 
     89 	return 0;
     90 }
     91