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

Comparing libeio/eio.c (file contents):
Revision 1.82 by root, Thu Jul 7 15:44:44 2011 UTC vs.
Revision 1.89 by root, Thu Jul 14 22:36:17 2011 UTC

54#include <stdlib.h> 54#include <stdlib.h>
55#include <string.h> 55#include <string.h>
56#include <errno.h> 56#include <errno.h>
57#include <sys/types.h> 57#include <sys/types.h>
58#include <sys/stat.h> 58#include <sys/stat.h>
59#include <sys/statvfs.h>
60#include <limits.h> 59#include <limits.h>
61#include <fcntl.h> 60#include <fcntl.h>
62#include <assert.h> 61#include <assert.h>
63 62
64/* intptr_t comes from unistd.h, says POSIX/UNIX/tradition */ 63/* intptr_t comes from unistd.h, says POSIX/UNIX/tradition */
83 82
84#ifndef EIO_FEED 83#ifndef EIO_FEED
85# define EIO_FEED(req) do { if ((req)->feed ) (req)->feed (req); } while (0) 84# define EIO_FEED(req) do { if ((req)->feed ) (req)->feed (req); } while (0)
86#endif 85#endif
87 86
87#ifndef EIO_FD_TO_WIN32_HANDLE
88# define EIO_FD_TO_WIN32_HANDLE(fd) _get_osfhandle (fd)
89#endif
90#ifndef EIO_WIN32_HANDLE_TO_FD
91# define EIO_WIN32_HANDLE_TO_FD(handle) _open_osfhandle (handle, 0)
92#endif
93
94#define EIO_ERRNO(errval,retval) ((errno = errval), retval)
95
96#define EIO_ENOSYS() EIO_ERRNO (ENOSYS, -1)
97
88#ifdef _WIN32 98#ifdef _WIN32
89 99
90 /*doh*/ 100 #define PAGESIZE 4096 /* GetSystemInfo? */
101
102 #ifdef EIO_STRUCT_STATI64
103 #define stat(path,buf) _stati64 (path,buf)
104 #define fstat(fd,buf) _fstati64 (path,buf)
105 #endif
106 #define lstat(path,buf) stat (path,buf)
107 #define fsync(fd) (FlushFileBuffers (EIO_FD_TO_WIN32_HANDLE (fd)) ? 0 : EIO_ERRNO (EBADF, -1))
108 #define mkdir(path,mode) _mkdir (path)
109 #define link(old,neu) (CreateHardLink (neu, old, 0) ? 0 : EIO_ERRNO (ENOENT, -1))
110
111 #define chown(path,uid,gid) EIO_ENOSYS ()
112 #define fchown(fd,uid,gid) EIO_ENOSYS ()
113 #define truncate(path,offs) EIO_ENOSYS () /* far-miss: SetEndOfFile */
114 #define ftruncate(fd,offs) EIO_ENOSYS () /* near-miss: SetEndOfFile */
115 #define mknod(path,mode,dev) EIO_ENOSYS ()
116 #define sync() EIO_ENOSYS ()
117
118 /* we could even stat and see if it exists */
119 static int
120 symlink (const char *old, const char *neu)
121 {
122 if (CreateSymbolicLink (neu, old, 1))
123 return 0;
124
125 if (CreateSymbolicLink (neu, old, 0))
126 return 0;
127
128 return EIO_ERRNO (ENOENT, -1);
129 }
130
91#else 131#else
92 132
93# include <sys/time.h> 133 #include <sys/time.h>
94# include <sys/select.h> 134 #include <sys/select.h>
135 #include <sys/statvfs.h>
95# include <unistd.h> 136 #include <unistd.h>
96# include <utime.h> 137 #include <utime.h>
97# include <signal.h> 138 #include <signal.h>
98# include <dirent.h> 139 #include <dirent.h>
99 140
100#if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES 141 #if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES
101# include <sys/mman.h> 142 #include <sys/mman.h>
102#endif 143 #endif
103 144
104/* POSIX_SOURCE is useless on bsd's, and XOPEN_SOURCE is unreliable there, too */ 145 /* POSIX_SOURCE is useless on bsd's, and XOPEN_SOURCE is unreliable there, too */
105# if __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ 146 #if __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
106# define _DIRENT_HAVE_D_TYPE /* sigh */ 147 #define _DIRENT_HAVE_D_TYPE /* sigh */
107# define D_INO(de) (de)->d_fileno 148 #define D_INO(de) (de)->d_fileno
108# define D_NAMLEN(de) (de)->d_namlen 149 #define D_NAMLEN(de) (de)->d_namlen
109# elif __linux || defined d_ino || _XOPEN_SOURCE >= 600 150 #elif __linux || defined d_ino || _XOPEN_SOURCE >= 600
110# define D_INO(de) (de)->d_ino 151 #define D_INO(de) (de)->d_ino
111# endif 152 #endif
112 153
113#ifdef _D_EXACT_NAMLEN 154 #ifdef _D_EXACT_NAMLEN
114# undef D_NAMLEN 155 #undef D_NAMLEN
115# define D_NAMLEN(de) _D_EXACT_NAMLEN (de) 156 #define D_NAMLEN(de) _D_EXACT_NAMLEN (de)
116#endif 157 #endif
117 158
118# ifdef _DIRENT_HAVE_D_TYPE 159 #ifdef _DIRENT_HAVE_D_TYPE
119# define D_TYPE(de) (de)->d_type 160 #define D_TYPE(de) (de)->d_type
120# endif 161 #endif
121 162
122# ifndef EIO_STRUCT_DIRENT 163 #ifndef EIO_STRUCT_DIRENT
123# define EIO_STRUCT_DIRENT struct dirent 164 #define EIO_STRUCT_DIRENT struct dirent
124# endif 165 #endif
125 166
126#endif 167#endif
127 168
128#if HAVE_SENDFILE 169#if HAVE_SENDFILE
129# if __linux 170# if __linux
381} 422}
382 423
383static void ecb_cold 424static void ecb_cold
384etp_thread_init (void) 425etp_thread_init (void)
385{ 426{
427#if !HAVE_PREADWRITE
428 X_MUTEX_CREATE (preadwritelock);
429#endif
386 X_MUTEX_CREATE (wrklock); 430 X_MUTEX_CREATE (wrklock);
387 X_MUTEX_CREATE (reslock); 431 X_MUTEX_CREATE (reslock);
388 X_MUTEX_CREATE (reqlock); 432 X_MUTEX_CREATE (reqlock);
389 X_COND_CREATE (reqwait); 433 X_COND_CREATE (reqwait);
390} 434}
391 435
392static void ecb_cold 436static void ecb_cold
393etp_atfork_prepare (void) 437etp_atfork_prepare (void)
394{ 438{
395 X_LOCK (wrklock);
396 X_LOCK (reqlock);
397 X_LOCK (reslock);
398#if !HAVE_PREADWRITE
399 X_LOCK (preadwritelock);
400#endif
401} 439}
402 440
403static void ecb_cold 441static void ecb_cold
404etp_atfork_parent (void) 442etp_atfork_parent (void)
405{ 443{
406#if !HAVE_PREADWRITE
407 X_UNLOCK (preadwritelock);
408#endif
409 X_UNLOCK (reslock);
410 X_UNLOCK (reqlock);
411 X_UNLOCK (wrklock);
412} 444}
413 445
414static void ecb_cold 446static void ecb_cold
415etp_atfork_child (void) 447etp_atfork_child (void)
416{ 448{
845# undef pread 877# undef pread
846# undef pwrite 878# undef pwrite
847# define pread eio__pread 879# define pread eio__pread
848# define pwrite eio__pwrite 880# define pwrite eio__pwrite
849 881
850static ssize_t 882static eio_ssize_t
851eio__pread (int fd, void *buf, size_t count, off_t offset) 883eio__pread (int fd, void *buf, size_t count, off_t offset)
852{ 884{
853 ssize_t res; 885 eio_ssize_t res;
854 off_t ooffset; 886 off_t ooffset;
855 887
856 X_LOCK (preadwritelock); 888 X_LOCK (preadwritelock);
857 ooffset = lseek (fd, 0, SEEK_CUR); 889 ooffset = lseek (fd, 0, SEEK_CUR);
858 lseek (fd, offset, SEEK_SET); 890 lseek (fd, offset, SEEK_SET);
861 X_UNLOCK (preadwritelock); 893 X_UNLOCK (preadwritelock);
862 894
863 return res; 895 return res;
864} 896}
865 897
866static ssize_t 898static eio_ssize_t
867eio__pwrite (int fd, void *buf, size_t count, off_t offset) 899eio__pwrite (int fd, void *buf, size_t count, off_t offset)
868{ 900{
869 ssize_t res; 901 eio_ssize_t res;
870 off_t ooffset; 902 off_t ooffset;
871 903
872 X_LOCK (preadwritelock); 904 X_LOCK (preadwritelock);
873 ooffset = lseek (fd, 0, SEEK_CUR); 905 ooffset = lseek (fd, 0, SEEK_CUR);
874 lseek (fd, offset, SEEK_SET); 906 lseek (fd, offset, SEEK_SET);
948 /* even though we could play tricks with the flags, it's better to always 980 /* even though we could play tricks with the flags, it's better to always
949 * call fdatasync, as that matches the expectation of its users best */ 981 * call fdatasync, as that matches the expectation of its users best */
950 return fdatasync (fd); 982 return fdatasync (fd);
951} 983}
952 984
985static int
986eio__fallocate (int fd, int mode, off_t offset, size_t len)
987{
988#if HAVE_FALLOCATE
989 return fallocate (fd, mode, offset, len);
990#else
991 errno = ENOSYS;
992 return -1;
993#endif
994}
995
953#if !HAVE_READAHEAD 996#if !HAVE_READAHEAD
954# undef readahead 997# undef readahead
955# define readahead(fd,offset,count) eio__readahead (fd, offset, count, self) 998# define readahead(fd,offset,count) eio__readahead (fd, offset, count, self)
956 999
957static ssize_t 1000static eio_ssize_t
958eio__readahead (int fd, off_t offset, size_t count, etp_worker *self) 1001eio__readahead (int fd, off_t offset, size_t count, etp_worker *self)
959{ 1002{
960 size_t todo = count; 1003 size_t todo = count;
961 dBUF; 1004 dBUF;
962 1005
974} 1017}
975 1018
976#endif 1019#endif
977 1020
978/* sendfile always needs emulation */ 1021/* sendfile always needs emulation */
979static ssize_t 1022static eio_ssize_t
980eio__sendfile (int ofd, int ifd, off_t offset, size_t count, etp_worker *self) 1023eio__sendfile (int ofd, int ifd, off_t offset, size_t count, etp_worker *self)
981{ 1024{
982 ssize_t written = 0; 1025 eio_ssize_t written = 0;
983 ssize_t res; 1026 eio_ssize_t res;
984 1027
985 if (!count) 1028 if (!count)
986 return 0; 1029 return 0;
987 1030
988 for (;;) 1031 for (;;)
1040 if (res < 0 && sbytes) 1083 if (res < 0 && sbytes)
1041 res = sbytes; 1084 res = sbytes;
1042 1085
1043# endif 1086# endif
1044 1087
1045#elif defined (_WIN32) 1088#elif defined (_WIN32) && 0
1046 /* does not work, just for documentation of what would need to be done */ 1089 /* does not work, just for documentation of what would need to be done */
1047 /* actually, cannot be done like this, as TransmitFile changes the file offset, */ 1090 /* actually, cannot be done like this, as TransmitFile changes the file offset, */
1048 /* libeio guarantees that the file offset does not change, and windows */ 1091 /* libeio guarantees that the file offset does not change, and windows */
1049 /* has no way to get an independent handle to the same file description */ 1092 /* has no way to get an independent handle to the same file description */
1050 HANDLE h = TO_SOCKET (ifd); 1093 HANDLE h = TO_SOCKET (ifd);
1097 1140
1098 res = 0; 1141 res = 0;
1099 1142
1100 while (count) 1143 while (count)
1101 { 1144 {
1102 ssize_t cnt; 1145 eio_ssize_t cnt;
1103 1146
1104 cnt = pread (ifd, eio_buf, count > EIO_BUFSIZE ? EIO_BUFSIZE : count, offset); 1147 cnt = pread (ifd, eio_buf, count > EIO_BUFSIZE ? EIO_BUFSIZE : count, offset);
1105 1148
1106 if (cnt <= 0) 1149 if (cnt <= 0)
1107 { 1150 {
1155 /* round up length */ 1198 /* round up length */
1156 *length = (*length + mask) & ~mask; 1199 *length = (*length + mask) & ~mask;
1157} 1200}
1158 1201
1159#if !_POSIX_MEMLOCK 1202#if !_POSIX_MEMLOCK
1160# define eio__mlockall(a) ((errno = ENOSYS), -1) 1203# define eio__mlockall(a) EIO_ENOSYS ()
1161#else 1204#else
1162 1205
1163static int 1206static int
1164eio__mlockall (int flags) 1207eio__mlockall (int flags)
1165{ 1208{
1179 return mlockall (flags); 1222 return mlockall (flags);
1180} 1223}
1181#endif 1224#endif
1182 1225
1183#if !_POSIX_MEMLOCK_RANGE 1226#if !_POSIX_MEMLOCK_RANGE
1184# define eio__mlock(a,b) ((errno = ENOSYS), -1) 1227# define eio__mlock(a,b) EIO_ENOSYS ()
1185#else 1228#else
1186 1229
1187static int 1230static int
1188eio__mlock (void *addr, size_t length) 1231eio__mlock (void *addr, size_t length)
1189{ 1232{
1193} 1236}
1194 1237
1195#endif 1238#endif
1196 1239
1197#if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO) 1240#if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO)
1198# define eio__msync(a,b,c) ((errno = ENOSYS), -1) 1241# define eio__msync(a,b,c) EIO_ENOSYS ()
1199#else 1242#else
1200 1243
1201static int 1244static int
1202eio__msync (void *mem, size_t len, int flags) 1245eio__msync (void *mem, size_t len, int flags)
1203{ 1246{
1315 res += strlen (res); 1358 res += strlen (res);
1316 } 1359 }
1317 1360
1318 while (*rel) 1361 while (*rel)
1319 { 1362 {
1320 ssize_t len, linklen; 1363 eio_ssize_t len, linklen;
1321 char *beg = rel; 1364 char *beg = rel;
1322 1365
1323 while (*rel && *rel != '/') 1366 while (*rel && *rel != '/')
1324 ++rel; 1367 ++rel;
1325 1368
1792X_THREAD_PROC (etp_proc) 1835X_THREAD_PROC (etp_proc)
1793{ 1836{
1794 ETP_REQ *req; 1837 ETP_REQ *req;
1795 struct timespec ts; 1838 struct timespec ts;
1796 etp_worker *self = (etp_worker *)thr_arg; 1839 etp_worker *self = (etp_worker *)thr_arg;
1840 int timeout;
1797 1841
1798 /* try to distribute timeouts somewhat randomly */ 1842 /* try to distribute timeouts somewhat evenly */
1799 ts.tv_nsec = ((unsigned long)self & 1023UL) * (1000000000UL / 1024UL); 1843 ts.tv_nsec = ((unsigned long)self & 1023UL) * (1000000000UL / 1024UL);
1800 1844
1801 for (;;) 1845 for (;;)
1802 { 1846 {
1847 ts.tv_sec = 0;
1848
1803 X_LOCK (reqlock); 1849 X_LOCK (reqlock);
1804 1850
1805 for (;;) 1851 for (;;)
1806 { 1852 {
1807 self->req = req = reqq_shift (&req_queue); 1853 self->req = req = reqq_shift (&req_queue);
1808 1854
1809 if (req) 1855 if (req)
1810 break; 1856 break;
1811 1857
1858 if (ts.tv_sec == 1) /* no request, but timeout detected, let's quit */
1859 {
1860 X_UNLOCK (reqlock);
1861 X_LOCK (wrklock);
1862 --started;
1863 X_UNLOCK (wrklock);
1864 goto quit;
1865 }
1866
1812 ++idle; 1867 ++idle;
1813 1868
1814 ts.tv_sec = time (0) + idle_timeout; 1869 if (idle <= max_idle)
1815 if (X_COND_TIMEDWAIT (reqwait, reqlock, ts) == ETIMEDOUT) 1870 /* we are allowed to idle, so do so without any timeout */
1871 X_COND_WAIT (reqwait, reqlock);
1872 else
1816 { 1873 {
1817 if (idle > max_idle) 1874 /* initialise timeout once */
1818 { 1875 if (!ts.tv_sec)
1819 --idle; 1876 ts.tv_sec = time (0) + idle_timeout;
1820 X_UNLOCK (reqlock);
1821 X_LOCK (wrklock);
1822 --started;
1823 X_UNLOCK (wrklock);
1824 goto quit;
1825 }
1826 1877
1827 /* we are allowed to idle, so do so without any timeout */
1828 X_COND_WAIT (reqwait, reqlock); 1878 if (X_COND_TIMEDWAIT (reqwait, reqlock, ts) == ETIMEDOUT)
1879 ts.tv_sec = 1; /* assuming this is not a value computed above.,.. */
1829 } 1880 }
1830 1881
1831 --idle; 1882 --idle;
1832 } 1883 }
1833 1884
1963 case EIO_MSYNC: req->result = eio__msync (req->ptr2, req->size, req->int1); break; 2014 case EIO_MSYNC: req->result = eio__msync (req->ptr2, req->size, req->int1); break;
1964 case EIO_MTOUCH: req->result = eio__mtouch (req); break; 2015 case EIO_MTOUCH: req->result = eio__mtouch (req); break;
1965 case EIO_MLOCK: req->result = eio__mlock (req->ptr2, req->size); break; 2016 case EIO_MLOCK: req->result = eio__mlock (req->ptr2, req->size); break;
1966 case EIO_MLOCKALL: req->result = eio__mlockall (req->int1); break; 2017 case EIO_MLOCKALL: req->result = eio__mlockall (req->int1); break;
1967 case EIO_SYNC_FILE_RANGE: req->result = eio__sync_file_range (req->int1, req->offs, req->size, req->int2); break; 2018 case EIO_SYNC_FILE_RANGE: req->result = eio__sync_file_range (req->int1, req->offs, req->size, req->int2); break;
2019 case EIO_FALLOCATE: req->result = eio__fallocate (req->int1, req->int2, req->offs, req->size); break;
1968 2020
1969 case EIO_READDIR: eio__scandir (req, self); break; 2021 case EIO_READDIR: eio__scandir (req, self); break;
1970 2022
1971 case EIO_BUSY: 2023 case EIO_BUSY:
1972#ifdef _WIN32 2024#ifdef _WIN32
2072eio_req *eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data) 2124eio_req *eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data)
2073{ 2125{
2074 REQ (EIO_SYNC_FILE_RANGE); req->int1 = fd; req->offs = offset; req->size = nbytes; req->int2 = flags; SEND; 2126 REQ (EIO_SYNC_FILE_RANGE); req->int1 = fd; req->offs = offset; req->size = nbytes; req->int2 = flags; SEND;
2075} 2127}
2076 2128
2129eio_req *eio_fallocate (int fd, int mode, off_t offset, size_t len, int pri, eio_cb cb, void *data)
2130{
2131 REQ (EIO_FALLOCATE); req->int1 = fd; req->int2 = mode; req->offs = offset; req->size = len; SEND;
2132}
2133
2077eio_req *eio_fdatasync (int fd, int pri, eio_cb cb, void *data) 2134eio_req *eio_fdatasync (int fd, int pri, eio_cb cb, void *data)
2078{ 2135{
2079 REQ (EIO_FDATASYNC); req->int1 = fd; SEND; 2136 REQ (EIO_FDATASYNC); req->int1 = fd; SEND;
2080} 2137}
2081 2138
2122eio_req *eio_fchmod (int fd, mode_t mode, int pri, eio_cb cb, void *data) 2179eio_req *eio_fchmod (int fd, mode_t mode, int pri, eio_cb cb, void *data)
2123{ 2180{
2124 REQ (EIO_FCHMOD); req->int1 = fd; req->int2 = (long)mode; SEND; 2181 REQ (EIO_FCHMOD); req->int1 = fd; req->int2 = (long)mode; SEND;
2125} 2182}
2126 2183
2127eio_req *eio_fchown (int fd, uid_t uid, gid_t gid, int pri, eio_cb cb, void *data) 2184eio_req *eio_fchown (int fd, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data)
2128{ 2185{
2129 REQ (EIO_FCHOWN); req->int1 = fd; req->int2 = (long)uid; req->int3 = (long)gid; SEND; 2186 REQ (EIO_FCHOWN); req->int1 = fd; req->int2 = (long)uid; req->int3 = (long)gid; SEND;
2130} 2187}
2131 2188
2132eio_req *eio_dup2 (int fd, int fd2, int pri, eio_cb cb, void *data) 2189eio_req *eio_dup2 (int fd, int fd2, int pri, eio_cb cb, void *data)
2152eio_req *eio_truncate (const char *path, off_t offset, int pri, eio_cb cb, void *data) 2209eio_req *eio_truncate (const char *path, off_t offset, int pri, eio_cb cb, void *data)
2153{ 2210{
2154 REQ (EIO_TRUNCATE); PATH; req->offs = offset; SEND; 2211 REQ (EIO_TRUNCATE); PATH; req->offs = offset; SEND;
2155} 2212}
2156 2213
2157eio_req *eio_chown (const char *path, uid_t uid, gid_t gid, int pri, eio_cb cb, void *data) 2214eio_req *eio_chown (const char *path, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data)
2158{ 2215{
2159 REQ (EIO_CHOWN); PATH; req->int2 = (long)uid; req->int3 = (long)gid; SEND; 2216 REQ (EIO_CHOWN); PATH; req->int2 = (long)uid; req->int3 = (long)gid; SEND;
2160} 2217}
2161 2218
2162eio_req *eio_chmod (const char *path, mode_t mode, int pri, eio_cb cb, void *data) 2219eio_req *eio_chmod (const char *path, mode_t mode, int pri, eio_cb cb, void *data)
2309} 2366}
2310 2367
2311/*****************************************************************************/ 2368/*****************************************************************************/
2312/* misc garbage */ 2369/* misc garbage */
2313 2370
2314ssize_t 2371eio_ssize_t
2315eio_sendfile_sync (int ofd, int ifd, off_t offset, size_t count) 2372eio_sendfile_sync (int ofd, int ifd, off_t offset, size_t count)
2316{ 2373{
2317 etp_worker wrk; 2374 etp_worker wrk;
2318 ssize_t ret; 2375 eio_ssize_t ret;
2319 2376
2320 wrk.dbuf = 0; 2377 wrk.dbuf = 0;
2321 2378
2322 ret = eio__sendfile (ofd, ifd, offset, count, &wrk); 2379 ret = eio__sendfile (ofd, ifd, offset, count, &wrk);
2323 2380

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines