ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/libeio/eio.c
(Generate patch)

Comparing cvsroot/libeio/eio.c (file contents):
Revision 1.42 by root, Mon Jun 15 05:34:49 2009 UTC vs.
Revision 1.55 by root, Wed Mar 31 00:46:18 2010 UTC

1/* 1/*
2 * libeio implementation 2 * libeio implementation
3 * 3 *
4 * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <libeio@schmorp.de> 4 * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann <libeio@schmorp.de>
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without modifica- 7 * Redistribution and use in source and binary forms, with or without modifica-
8 * tion, are permitted provided that the following conditions are met: 8 * tion, are permitted provided that the following conditions are met:
9 * 9 *
49#include <stdlib.h> 49#include <stdlib.h>
50#include <string.h> 50#include <string.h>
51#include <errno.h> 51#include <errno.h>
52#include <sys/types.h> 52#include <sys/types.h>
53#include <sys/stat.h> 53#include <sys/stat.h>
54#include <sys/statvfs.h>
54#include <limits.h> 55#include <limits.h>
55#include <fcntl.h> 56#include <fcntl.h>
56#include <assert.h> 57#include <assert.h>
57 58
58#ifndef EIO_FINISH 59#ifndef EIO_FINISH
80# include <utime.h> 81# include <utime.h>
81# include <signal.h> 82# include <signal.h>
82# include <dirent.h> 83# include <dirent.h>
83 84
84/* POSIX_SOURCE is useless on bsd's, and XOPEN_SOURCE is unreliable there, too */ 85/* POSIX_SOURCE is useless on bsd's, and XOPEN_SOURCE is unreliable there, too */
85# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 86# if __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
86# define _DIRENT_HAVE_D_TYPE /* sigh */ 87# define _DIRENT_HAVE_D_TYPE /* sigh */
87# define D_INO(de) (de)->d_fileno 88# define D_INO(de) (de)->d_fileno
88# define D_NAMLEN(de) (de)->d_namlen 89# define D_NAMLEN(de) (de)->d_namlen
89# elif defined(__linux) || defined(d_ino) || _XOPEN_SOURCE >= 600 90# elif __linux || defined d_ino || _XOPEN_SOURCE >= 600
90# define D_INO(de) (de)->d_ino 91# define D_INO(de) (de)->d_ino
91# endif 92# endif
92 93
93#ifdef _D_EXACT_NAMLEN 94#ifdef _D_EXACT_NAMLEN
94# undef D_NAMLEN 95# undef D_NAMLEN
106#endif 107#endif
107 108
108#if HAVE_SENDFILE 109#if HAVE_SENDFILE
109# if __linux 110# if __linux
110# include <sys/sendfile.h> 111# include <sys/sendfile.h>
111# elif __freebsd 112# elif __FreeBSD__ || defined __APPLE__
112# include <sys/socket.h> 113# include <sys/socket.h>
113# include <sys/uio.h> 114# include <sys/uio.h>
114# elif __hpux 115# elif __hpux
115# include <sys/socket.h> 116# include <sys/socket.h>
116# elif __solaris /* not yet */ 117# elif __solaris
117# include <sys/sendfile.h> 118# include <sys/sendfile.h>
118# else 119# else
119# error sendfile support requested but not available 120# error sendfile support requested but not available
120# endif 121# endif
121#endif 122#endif
134#define IDLE_TIMEOUT 10 135#define IDLE_TIMEOUT 10
135 136
136/* used for struct dirent, AIX doesn't provide it */ 137/* used for struct dirent, AIX doesn't provide it */
137#ifndef NAME_MAX 138#ifndef NAME_MAX
138# define NAME_MAX 4096 139# define NAME_MAX 4096
140#endif
141
142/* used for readlink etc. */
143#ifndef PATH_MAX
144# define PATH_MAX 4096
139#endif 145#endif
140 146
141/* buffer size for various temporary buffers */ 147/* buffer size for various temporary buffers */
142#define EIO_BUFSIZE 65536 148#define EIO_BUFSIZE 65536
143 149
196 202
197/*****************************************************************************/ 203/*****************************************************************************/
198 204
199#define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1) 205#define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1)
200 206
201/* calculcate time difference in ~1/EIO_TICKS of a second */ 207/* calculate time difference in ~1/EIO_TICKS of a second */
202static int tvdiff (struct timeval *tv1, struct timeval *tv2) 208static int tvdiff (struct timeval *tv1, struct timeval *tv2)
203{ 209{
204 return (tv2->tv_sec - tv1->tv_sec ) * EIO_TICKS 210 return (tv2->tv_sec - tv1->tv_sec ) * EIO_TICKS
205 + ((tv2->tv_usec - tv1->tv_usec) >> 10); 211 + ((tv2->tv_usec - tv1->tv_usec) >> 10);
206} 212}
216static volatile unsigned int nreqs; /* reqlock */ 222static volatile unsigned int nreqs; /* reqlock */
217static volatile unsigned int nready; /* reqlock */ 223static volatile unsigned int nready; /* reqlock */
218static volatile unsigned int npending; /* reqlock */ 224static volatile unsigned int npending; /* reqlock */
219static volatile unsigned int max_idle = 4; 225static volatile unsigned int max_idle = 4;
220 226
221static mutex_t wrklock = X_MUTEX_INIT; 227static xmutex_t wrklock = X_MUTEX_INIT;
222static mutex_t reslock = X_MUTEX_INIT; 228static xmutex_t reslock = X_MUTEX_INIT;
223static mutex_t reqlock = X_MUTEX_INIT; 229static xmutex_t reqlock = X_MUTEX_INIT;
224static cond_t reqwait = X_COND_INIT; 230static xcond_t reqwait = X_COND_INIT;
225 231
226#if !HAVE_PREADWRITE 232#if !HAVE_PREADWRITE
227/* 233/*
228 * make our pread/pwrite emulation safe against themselves, but not against 234 * make our pread/pwrite emulation safe against themselves, but not against
229 * normal read/write by using a mutex. slows down execution a lot, 235 * normal read/write by using a mutex. slows down execution a lot,
230 * but that's your problem, not mine. 236 * but that's your problem, not mine.
231 */ 237 */
232static mutex_t preadwritelock = X_MUTEX_INIT; 238static xmutex_t preadwritelock = X_MUTEX_INIT;
233#endif 239#endif
234 240
235typedef struct etp_worker 241typedef struct etp_worker
236{ 242{
237 /* locked by wrklock */ 243 /* locked by wrklock */
238 struct etp_worker *prev, *next; 244 struct etp_worker *prev, *next;
239 245
240 thread_t tid; 246 xthread_t tid;
241 247
242 /* locked by reslock, reqlock or wrklock */ 248 /* locked by reslock, reqlock or wrklock */
243 ETP_REQ *req; /* currently processed request */ 249 ETP_REQ *req; /* currently processed request */
244 250
245 ETP_WORKER_COMMON 251 ETP_WORKER_COMMON
598} 604}
599 605
600static void etp_set_max_poll_time (double nseconds) 606static void etp_set_max_poll_time (double nseconds)
601{ 607{
602 if (WORDACCESS_UNSAFE) X_LOCK (reslock); 608 if (WORDACCESS_UNSAFE) X_LOCK (reslock);
603 max_poll_time = nseconds; 609 max_poll_time = nseconds * EIO_TICKS;
604 if (WORDACCESS_UNSAFE) X_UNLOCK (reslock); 610 if (WORDACCESS_UNSAFE) X_UNLOCK (reslock);
605} 611}
606 612
607static void etp_set_max_poll_reqs (unsigned int maxreqs) 613static void etp_set_max_poll_reqs (unsigned int maxreqs)
608{ 614{
867 if (!res || errno != ENOSYS) 873 if (!res || errno != ENOSYS)
868 return res; 874 return res;
869#endif 875#endif
870 876
871 /* even though we could play tricks with the flags, it's better to always 877 /* even though we could play tricks with the flags, it's better to always
872 * call fdatasync, as thta matches the expectation of it's users best */ 878 * call fdatasync, as that matches the expectation of its users best */
873 return fdatasync (fd); 879 return fdatasync (fd);
874} 880}
875 881
876#if !HAVE_READAHEAD 882#if !HAVE_READAHEAD
877# undef readahead 883# undef readahead
909 915
910#if HAVE_SENDFILE 916#if HAVE_SENDFILE
911# if __linux 917# if __linux
912 res = sendfile (ofd, ifd, &offset, count); 918 res = sendfile (ofd, ifd, &offset, count);
913 919
914# elif __freebsd 920# elif __FreeBSD__
915 /* 921 /*
916 * Of course, the freebsd sendfile is a dire hack with no thoughts 922 * Of course, the freebsd sendfile is a dire hack with no thoughts
917 * wasted on making it similar to other I/O functions. 923 * wasted on making it similar to other I/O functions.
918 */ 924 */
919 { 925 {
920 off_t sbytes; 926 off_t sbytes;
921 res = sendfile (ifd, ofd, offset, count, 0, &sbytes, 0); 927 res = sendfile (ifd, ofd, offset, count, 0, &sbytes, 0);
922 928
923 if (res < 0 && sbytes) 929 #if 0 /* according to the manpage, this is correct, but broken behaviour */
924 /* maybe only on EAGAIN: as usual, the manpage leaves you guessing */ 930 /* freebsd' sendfile will return 0 on success */
931 /* freebsd 8 documents it as only setting *sbytes on EINTR and EAGAIN, but */
932 /* not on e.g. EIO or EPIPE - sounds broken */
933 if ((res < 0 && (errno == EAGAIN || errno == EINTR) && sbytes) || res == 0)
934 res = sbytes;
935 #endif
936
937 /* according to source inspection, this is correct, and useful behaviour */
938 if (sbytes)
939 res = sbytes;
940 }
941
942# elif defined (__APPLE__)
943
944 {
945 off_t sbytes = count;
946 res = sendfile (ifd, ofd, offset, &sbytes, 0, 0);
947
948 /* according to the manpage, sbytes is always valid */
949 if (sbytes)
925 res = sbytes; 950 res = sbytes;
926 } 951 }
927 952
928# elif __hpux 953# elif __hpux
929 res = sendfile (ofd, ifd, offset, count, 0, 0); 954 res = sendfile (ofd, ifd, offset, count, 0, 0);
943 if (res < 0 && sbytes) 968 if (res < 0 && sbytes)
944 res = sbytes; 969 res = sbytes;
945 } 970 }
946 971
947# endif 972# endif
973
974#elif defined (_WIN32)
975
976 /* does not work, just for documentation of what would need to be done */
977 {
978 HANDLE h = TO_SOCKET (ifd);
979 SetFilePointer (h, offset, 0, FILE_BEGIN);
980 res = TransmitFile (TO_SOCKET (ofd), h, count, 0, 0, 0, 0);
981 }
982
948#else 983#else
949 res = -1; 984 res = -1;
950 errno = ENOSYS; 985 errno = ENOSYS;
951#endif 986#endif
952 987
953 if (res < 0 988 if (res < 0
954 && (errno == ENOSYS || errno == EINVAL || errno == ENOTSOCK 989 && (errno == ENOSYS || errno == EINVAL || errno == ENOTSOCK
990 /* BSDs */
991#ifdef ENOTSUP /* sigh, if the steenking pile called openbsd would only try to at least compile posix code... */
992 || errno == ENOTSUP
993#endif
994 || errno == EOPNOTSUPP /* BSDs */
955#if __solaris 995#if __solaris
956 || errno == EAFNOSUPPORT || errno == EPROTOTYPE 996 || errno == EAFNOSUPPORT || errno == EPROTOTYPE
957#endif 997#endif
958 ) 998 )
959 ) 999 )
1353 } 1393 }
1354 } 1394 }
1355} 1395}
1356 1396
1357#if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO) 1397#if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO)
1358# undef msync
1359# define msync(a,b,c) ((errno = ENOSYS), -1) 1398# define eio__msync(a,b,c) ((errno = ENOSYS), -1)
1399#else
1400
1401int
1402eio__msync (void *mem, size_t len, int flags)
1403{
1404 if (EIO_MS_ASYNC != MS_SYNC
1405 || EIO_MS_INVALIDATE != MS_INVALIDATE
1406 || EIO_MS_SYNC != MS_SYNC)
1407 {
1408 flags = 0
1409 | (flags & EIO_MS_ASYNC ? MS_ASYNC : 0)
1410 | (flags & EIO_MS_INVALIDATE ? MS_INVALIDATE : 0)
1411 | (flags & EIO_MS_SYNC ? MS_SYNC : 0);
1412 }
1413
1414 return msync (mem, len, flags);
1415}
1416
1360#endif 1417#endif
1361 1418
1362int 1419int
1363eio__mtouch (void *mem, size_t len, int flags) 1420eio__mtouch (void *mem, size_t len, int flags)
1364{ 1421{
1371 1428
1372 if (!page) 1429 if (!page)
1373 page = sysconf (_SC_PAGESIZE); 1430 page = sysconf (_SC_PAGESIZE);
1374#endif 1431#endif
1375 1432
1433 /* round down to start of page, although this is probably useless */
1376 addr &= ~(page - 1); /* assume page size is always a power of two */ 1434 addr &= ~(page - 1); /* assume page size is always a power of two */
1377 1435
1378 if (addr < end) 1436 if (addr < end)
1379 if (flags) /* modify */ 1437 if (flags & EIO_MT_MODIFY) /* modify */
1380 do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len); 1438 do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len);
1381 else 1439 else
1382 do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len); 1440 do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len);
1383 1441
1384 return 0; 1442 return 0;
1532 case EIO_LSTAT: ALLOC (sizeof (EIO_STRUCT_STAT)); 1590 case EIO_LSTAT: ALLOC (sizeof (EIO_STRUCT_STAT));
1533 req->result = lstat (req->ptr1, (EIO_STRUCT_STAT *)req->ptr2); break; 1591 req->result = lstat (req->ptr1, (EIO_STRUCT_STAT *)req->ptr2); break;
1534 case EIO_FSTAT: ALLOC (sizeof (EIO_STRUCT_STAT)); 1592 case EIO_FSTAT: ALLOC (sizeof (EIO_STRUCT_STAT));
1535 req->result = fstat (req->int1, (EIO_STRUCT_STAT *)req->ptr2); break; 1593 req->result = fstat (req->int1, (EIO_STRUCT_STAT *)req->ptr2); break;
1536 1594
1595 case EIO_STATVFS: ALLOC (sizeof (EIO_STRUCT_STATVFS));
1596 req->result = statvfs (req->ptr1, (EIO_STRUCT_STATVFS *)req->ptr2); break;
1597 case EIO_FSTATVFS: ALLOC (sizeof (EIO_STRUCT_STATVFS));
1598 req->result = fstatvfs (req->int1, (EIO_STRUCT_STATVFS *)req->ptr2); break;
1599
1537 case EIO_CHOWN: req->result = chown (req->ptr1, req->int2, req->int3); break; 1600 case EIO_CHOWN: req->result = chown (req->ptr1, req->int2, req->int3); break;
1538 case EIO_FCHOWN: req->result = fchown (req->int1, req->int2, req->int3); break; 1601 case EIO_FCHOWN: req->result = fchown (req->int1, req->int2, req->int3); break;
1539 case EIO_CHMOD: req->result = chmod (req->ptr1, (mode_t)req->int2); break; 1602 case EIO_CHMOD: req->result = chmod (req->ptr1, (mode_t)req->int2); break;
1540 case EIO_FCHMOD: req->result = fchmod (req->int1, (mode_t)req->int2); break; 1603 case EIO_FCHMOD: req->result = fchmod (req->int1, (mode_t)req->int2); break;
1541 case EIO_TRUNCATE: req->result = truncate (req->ptr1, req->offs); break; 1604 case EIO_TRUNCATE: req->result = truncate (req->ptr1, req->offs); break;
1550 case EIO_RENAME: req->result = rename (req->ptr1, req->ptr2); break; 1613 case EIO_RENAME: req->result = rename (req->ptr1, req->ptr2); break;
1551 case EIO_LINK: req->result = link (req->ptr1, req->ptr2); break; 1614 case EIO_LINK: req->result = link (req->ptr1, req->ptr2); break;
1552 case EIO_SYMLINK: req->result = symlink (req->ptr1, req->ptr2); break; 1615 case EIO_SYMLINK: req->result = symlink (req->ptr1, req->ptr2); break;
1553 case EIO_MKNOD: req->result = mknod (req->ptr1, (mode_t)req->int2, (dev_t)req->int3); break; 1616 case EIO_MKNOD: req->result = mknod (req->ptr1, (mode_t)req->int2, (dev_t)req->int3); break;
1554 1617
1555 case EIO_READLINK: ALLOC (NAME_MAX); 1618 case EIO_READLINK: ALLOC (PATH_MAX);
1556 req->result = readlink (req->ptr1, req->ptr2, NAME_MAX); break; 1619 req->result = readlink (req->ptr1, req->ptr2, PATH_MAX); break;
1557 1620
1558 case EIO_SYNC: req->result = 0; sync (); break; 1621 case EIO_SYNC: req->result = 0; sync (); break;
1559 case EIO_FSYNC: req->result = fsync (req->int1); break; 1622 case EIO_FSYNC: req->result = fsync (req->int1); break;
1560 case EIO_FDATASYNC: req->result = fdatasync (req->int1); break; 1623 case EIO_FDATASYNC: req->result = fdatasync (req->int1); break;
1561 case EIO_MSYNC: req->result = msync (req->ptr2, req->size, req->int1); break; 1624 case EIO_MSYNC: req->result = eio__msync (req->ptr2, req->size, req->int1); break;
1562 case EIO_MTOUCH: req->result = eio__mtouch (req->ptr2, req->size, req->int1); break; 1625 case EIO_MTOUCH: req->result = eio__mtouch (req->ptr2, req->size, req->int1); break;
1563 case EIO_SYNC_FILE_RANGE: req->result = eio__sync_file_range (req->int1, req->offs, req->size, req->int2); break; 1626 case EIO_SYNC_FILE_RANGE: req->result = eio__sync_file_range (req->int1, req->offs, req->size, req->int2); break;
1564 1627
1565 case EIO_READDIR: eio__scandir (req, self); break; 1628 case EIO_READDIR: eio__scandir (req, self); break;
1566 1629
1688eio_req *eio_fstat (int fd, int pri, eio_cb cb, void *data) 1751eio_req *eio_fstat (int fd, int pri, eio_cb cb, void *data)
1689{ 1752{
1690 REQ (EIO_FSTAT); req->int1 = fd; SEND; 1753 REQ (EIO_FSTAT); req->int1 = fd; SEND;
1691} 1754}
1692 1755
1756eio_req *eio_fstatvfs (int fd, int pri, eio_cb cb, void *data)
1757{
1758 REQ (EIO_FSTATVFS); req->int1 = fd; SEND;
1759}
1760
1693eio_req *eio_futime (int fd, double atime, double mtime, int pri, eio_cb cb, void *data) 1761eio_req *eio_futime (int fd, double atime, double mtime, int pri, eio_cb cb, void *data)
1694{ 1762{
1695 REQ (EIO_FUTIME); req->int1 = fd; req->nv1 = atime; req->nv2 = mtime; SEND; 1763 REQ (EIO_FUTIME); req->int1 = fd; req->nv1 = atime; req->nv2 = mtime; SEND;
1696} 1764}
1697 1765
1767} 1835}
1768 1836
1769eio_req *eio_lstat (const char *path, int pri, eio_cb cb, void *data) 1837eio_req *eio_lstat (const char *path, int pri, eio_cb cb, void *data)
1770{ 1838{
1771 return eio__1path (EIO_LSTAT, path, pri, cb, data); 1839 return eio__1path (EIO_LSTAT, path, pri, cb, data);
1840}
1841
1842eio_req *eio_statvfs (const char *path, int pri, eio_cb cb, void *data)
1843{
1844 return eio__1path (EIO_STATVFS, path, pri, cb, data);
1772} 1845}
1773 1846
1774eio_req *eio_unlink (const char *path, int pri, eio_cb cb, void *data) 1847eio_req *eio_unlink (const char *path, int pri, eio_cb cb, void *data)
1775{ 1848{
1776 return eio__1path (EIO_UNLINK, path, pri, cb, data); 1849 return eio__1path (EIO_UNLINK, path, pri, cb, data);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines