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

Comparing libeio/eio.c (file contents):
Revision 1.62 by root, Tue Feb 15 03:15:16 2011 UTC vs.
Revision 1.69 by root, Fri Jun 10 06:50:42 2011 UTC

35 * and other provisions required by the GPL. If you do not delete the 35 * and other provisions required by the GPL. If you do not delete the
36 * provisions above, a recipient may use your version of this file under 36 * provisions above, a recipient may use your version of this file under
37 * either the BSD or the GPL. 37 * either the BSD or the GPL.
38 */ 38 */
39 39
40#ifndef _WIN32
41# include "config.h"
42#endif
43
40#include "eio.h" 44#include "eio.h"
41 45
42#ifdef EIO_STACKSIZE 46#ifdef EIO_STACKSIZE
43# define XTHREAD_STACKSIZE EIO_STACKSIZE 47# define XTHREAD_STACKSIZE EIO_STACKSIZE
44#endif 48#endif
54#include <sys/statvfs.h> 58#include <sys/statvfs.h>
55#include <limits.h> 59#include <limits.h>
56#include <fcntl.h> 60#include <fcntl.h>
57#include <assert.h> 61#include <assert.h>
58 62
63/* intptr_t comes from unistd.h, says POSIX/UNIX/tradition */
64/* intptr_t only comes form stdint.h, says idiot openbsd coder */
65#if HAVE_STDINT_H
66# include <stdint.h>
67#endif
68
59#ifndef EIO_FINISH 69#ifndef EIO_FINISH
60# define EIO_FINISH(req) ((req)->finish) && !EIO_CANCELLED (req) ? (req)->finish (req) : 0 70# define EIO_FINISH(req) ((req)->finish) && !EIO_CANCELLED (req) ? (req)->finish (req) : 0
61#endif 71#endif
62 72
63#ifndef EIO_DESTROY 73#ifndef EIO_DESTROY
71#ifdef _WIN32 81#ifdef _WIN32
72 82
73 /*doh*/ 83 /*doh*/
74#else 84#else
75 85
76# include "config.h"
77# include <sys/time.h> 86# include <sys/time.h>
78# include <sys/select.h> 87# include <sys/select.h>
79# include <unistd.h> 88# include <unistd.h>
80# include <utime.h> 89# include <utime.h>
81# include <signal.h> 90# include <signal.h>
933 942
934/* sendfile always needs emulation */ 943/* sendfile always needs emulation */
935static ssize_t 944static ssize_t
936eio__sendfile (int ofd, int ifd, off_t offset, size_t count, etp_worker *self) 945eio__sendfile (int ofd, int ifd, off_t offset, size_t count, etp_worker *self)
937{ 946{
947 ssize_t written = 0;
938 ssize_t res; 948 ssize_t res;
939 949
940 if (!count) 950 if (!count)
941 return 0; 951 return 0;
942 952
953 for (;;)
954 {
943#if HAVE_SENDFILE 955#if HAVE_SENDFILE
944# if __linux 956# if __linux
957 off_t soffset = offset;
945 res = sendfile (ofd, ifd, &offset, count); 958 res = sendfile (ofd, ifd, &soffset, count);
946 959
947# elif __FreeBSD__ 960# elif __FreeBSD__
948 /* 961 /*
949 * Of course, the freebsd sendfile is a dire hack with no thoughts 962 * Of course, the freebsd sendfile is a dire hack with no thoughts
950 * wasted on making it similar to other I/O functions. 963 * wasted on making it similar to other I/O functions.
951 */ 964 */
952 {
953 off_t sbytes; 965 off_t sbytes;
954 res = sendfile (ifd, ofd, offset, count, 0, &sbytes, 0); 966 res = sendfile (ifd, ofd, offset, count, 0, &sbytes, 0);
955 967
956 #if 0 /* according to the manpage, this is correct, but broken behaviour */ 968 #if 0 /* according to the manpage, this is correct, but broken behaviour */
957 /* freebsd' sendfile will return 0 on success */ 969 /* freebsd' sendfile will return 0 on success */
958 /* freebsd 8 documents it as only setting *sbytes on EINTR and EAGAIN, but */ 970 /* freebsd 8 documents it as only setting *sbytes on EINTR and EAGAIN, but */
959 /* not on e.g. EIO or EPIPE - sounds broken */ 971 /* not on e.g. EIO or EPIPE - sounds broken */
960 if ((res < 0 && (errno == EAGAIN || errno == EINTR) && sbytes) || res == 0) 972 if ((res < 0 && (errno == EAGAIN || errno == EINTR) && sbytes) || res == 0)
961 res = sbytes; 973 res = sbytes;
962 #endif 974 #endif
963 975
964 /* according to source inspection, this is correct, and useful behaviour */ 976 /* according to source inspection, this is correct, and useful behaviour */
965 if (sbytes) 977 if (sbytes)
966 res = sbytes; 978 res = sbytes;
967 }
968 979
969# elif defined (__APPLE__) 980# elif defined (__APPLE__)
970
971 {
972 off_t sbytes = count; 981 off_t sbytes = count;
973 res = sendfile (ifd, ofd, offset, &sbytes, 0, 0); 982 res = sendfile (ifd, ofd, offset, &sbytes, 0, 0);
974 983
975 /* according to the manpage, sbytes is always valid */ 984 /* according to the manpage, sbytes is always valid */
976 if (sbytes) 985 if (sbytes)
977 res = sbytes; 986 res = sbytes;
978 }
979 987
980# elif __hpux 988# elif __hpux
981 res = sendfile (ofd, ifd, offset, count, 0, 0); 989 res = sendfile (ofd, ifd, offset, count, 0, 0);
982 990
983# elif __solaris 991# elif __solaris
984 {
985 struct sendfilevec vec; 992 struct sendfilevec vec;
986 size_t sbytes; 993 size_t sbytes;
987 994
988 vec.sfv_fd = ifd; 995 vec.sfv_fd = ifd;
989 vec.sfv_flag = 0; 996 vec.sfv_flag = 0;
990 vec.sfv_off = offset; 997 vec.sfv_off = offset;
991 vec.sfv_len = count; 998 vec.sfv_len = count;
992 999
993 res = sendfilev (ofd, &vec, 1, &sbytes); 1000 res = sendfilev (ofd, &vec, 1, &sbytes);
994 1001
995 if (res < 0 && sbytes) 1002 if (res < 0 && sbytes)
996 res = sbytes; 1003 res = sbytes;
997 }
998 1004
999# endif 1005# endif
1000 1006
1001#elif defined (_WIN32) 1007#elif defined (_WIN32)
1002
1003 /* does not work, just for documentation of what would need to be done */ 1008 /* does not work, just for documentation of what would need to be done */
1004 {
1005 HANDLE h = TO_SOCKET (ifd); 1009 HANDLE h = TO_SOCKET (ifd);
1006 SetFilePointer (h, offset, 0, FILE_BEGIN); 1010 SetFilePointer (h, offset, 0, FILE_BEGIN);
1007 res = TransmitFile (TO_SOCKET (ofd), h, count, 0, 0, 0, 0); 1011 res = TransmitFile (TO_SOCKET (ofd), h, count, 0, 0, 0, 0);
1008 }
1009 1012
1010#else 1013#else
1011 res = -1; 1014 res = -1;
1012 errno = ENOSYS; 1015 errno = ENOSYS;
1013#endif 1016#endif
1014 1017
1018 /* we assume sendfile can copy at least 128mb in one go */
1019 if (res <= 128 * 1024 * 1024)
1020 {
1021 if (res > 0)
1022 written += res;
1023
1024 if (written)
1025 return written;
1026
1027 break;
1028 }
1029 else
1030 {
1031 /* if we requested more, then probably the kernel was lazy */
1032 written += res;
1033 offset += res;
1034 count -= res;
1035
1036 if (!count)
1037 return written;
1038 }
1039 }
1040
1015 if (res < 0 1041 if (res < 0
1016 && (errno == ENOSYS || errno == EINVAL || errno == ENOTSOCK 1042 && (errno == ENOSYS || errno == EINVAL || errno == ENOTSOCK
1017 /* BSDs */ 1043 /* BSDs */
1018#ifdef ENOTSUP /* sigh, if the steenking pile called openbsd would only try to at least compile posix code... */ 1044#ifdef ENOTSUP /* sigh, if the steenking pile called openbsd would only try to at least compile posix code... */
1019 || errno == ENOTSUP 1045 || errno == ENOTSUP
1020#endif 1046#endif
1060} 1086}
1061 1087
1062static signed char 1088static signed char
1063eio_dent_cmp (const eio_dirent *a, const eio_dirent *b) 1089eio_dent_cmp (const eio_dirent *a, const eio_dirent *b)
1064{ 1090{
1065 return a->score - b->score ? a->score - b->score /* works because our signed char is always 0..100 */ 1091 return a->score - b->score ? a->score - b->score /* works because our signed char is always 0..100 */
1066 : a->inode < b->inode ? -1 : a->inode > b->inode ? 1 : 0; 1092 : a->inode < b->inode ? -1
1093 : a->inode > b->inode ? 1
1094 : 0;
1067} 1095}
1068 1096
1069#define EIO_DENT_CMP(i,op,j) eio_dent_cmp (&i, &j) op 0 1097#define EIO_DENT_CMP(i,op,j) eio_dent_cmp (&i, &j) op 0
1070 1098
1071#define EIO_SORT_CUTOFF 30 /* quite high, but performs well on many filesystems */ 1099#define EIO_SORT_CUTOFF 30 /* quite high, but performs well on many filesystems */
1077 unsigned char bits [9 + sizeof (ino_t) * 8]; 1105 unsigned char bits [9 + sizeof (ino_t) * 8];
1078 unsigned char *bit = bits; 1106 unsigned char *bit = bits;
1079 1107
1080 assert (CHAR_BIT == 8); 1108 assert (CHAR_BIT == 8);
1081 assert (sizeof (eio_dirent) * 8 < 256); 1109 assert (sizeof (eio_dirent) * 8 < 256);
1082 assert (offsetof (eio_dirent, inode)); /* we use 0 as sentinel */ 1110 assert (offsetof (eio_dirent, inode)); /* we use bit #0 as sentinel */
1083 assert (offsetof (eio_dirent, score)); /* we use 0 as sentinel */ 1111 assert (offsetof (eio_dirent, score)); /* we use bit #0 as sentinel */
1084 1112
1085 if (size <= EIO_SORT_FAST) 1113 if (size <= EIO_SORT_FAST)
1086 return; 1114 return;
1087 1115
1088 /* first prepare an array of bits to test in our radix sort */ 1116 /* first prepare an array of bits to test in our radix sort */
1243 flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER); 1271 flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER);
1244 1272
1245 X_LOCK (wrklock); 1273 X_LOCK (wrklock);
1246 /* the corresponding closedir is in ETP_WORKER_CLEAR */ 1274 /* the corresponding closedir is in ETP_WORKER_CLEAR */
1247 self->dirp = dirp = opendir (req->ptr1); 1275 self->dirp = dirp = opendir (req->ptr1);
1276
1248 req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE; 1277 req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE;
1249 req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0; 1278 req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0;
1250 req->ptr2 = names = malloc (namesalloc); 1279 req->ptr2 = names = malloc (namesalloc);
1251 X_UNLOCK (wrklock); 1280 X_UNLOCK (wrklock);
1252 1281
1264 /* sort etc. */ 1293 /* sort etc. */
1265 req->int1 = flags; 1294 req->int1 = flags;
1266 req->result = dentoffs; 1295 req->result = dentoffs;
1267 1296
1268 if (flags & EIO_READDIR_STAT_ORDER) 1297 if (flags & EIO_READDIR_STAT_ORDER)
1269 eio_dent_sort (dents, dentoffs, 0, inode_bits); /* sort by inode exclusively */ 1298 eio_dent_sort (dents, dentoffs, flags & EIO_READDIR_DIRS_FIRST ? 7 : 0, inode_bits);
1270 else if (flags & EIO_READDIR_DIRS_FIRST) 1299 else if (flags & EIO_READDIR_DIRS_FIRST)
1271 if (flags & EIO_READDIR_FOUND_UNKNOWN) 1300 if (flags & EIO_READDIR_FOUND_UNKNOWN)
1272 eio_dent_sort (dents, dentoffs, 7, inode_bits); /* sort by score and inode */ 1301 eio_dent_sort (dents, dentoffs, 7, inode_bits); /* sort by score and inode */
1273 else 1302 else
1274 { 1303 {
1276 eio_dirent *oth = dents + dentoffs; 1305 eio_dirent *oth = dents + dentoffs;
1277 eio_dirent *dir = dents; 1306 eio_dirent *dir = dents;
1278 1307
1279 /* now partition dirs to the front, and non-dirs to the back */ 1308 /* now partition dirs to the front, and non-dirs to the back */
1280 /* by walking from both sides and swapping if necessary */ 1309 /* by walking from both sides and swapping if necessary */
1281 /* also clear score, so it doesn't influence sorting */
1282 while (oth > dir) 1310 while (oth > dir)
1283 { 1311 {
1284 if (dir->type == EIO_DT_DIR) 1312 if (dir->type == EIO_DT_DIR)
1285 ++dir; 1313 ++dir;
1286 else if ((--oth)->type == EIO_DT_DIR) 1314 else if ((--oth)->type == EIO_DT_DIR)
1289 1317
1290 ++dir; 1318 ++dir;
1291 } 1319 }
1292 } 1320 }
1293 1321
1294 /* now sort the dirs only */ 1322 /* now sort the dirs only (dirs all have the same score) */
1295 eio_dent_sort (dents, dir - dents, 0, inode_bits); 1323 eio_dent_sort (dents, dir - dents, 0, inode_bits);
1296 } 1324 }
1297 1325
1298 break; 1326 break;
1299 } 1327 }
1512} 1540}
1513 1541
1514#endif 1542#endif
1515 1543
1516int 1544int
1517eio__mtouch (void *mem, size_t len, int flags) 1545eio__mtouch (eio_req *req)
1518{ 1546{
1547 void *mem = req->ptr2;
1548 size_t len = req->size;
1549 int flags = req->int1;
1550
1519 eio_page_align (&mem, &len); 1551 eio_page_align (&mem, &len);
1520 1552
1521 { 1553 {
1522 intptr_t addr = (intptr_t)mem; 1554 intptr_t addr = (intptr_t)mem;
1523 intptr_t end = addr + len; 1555 intptr_t end = addr + len;
1524 intptr_t page = eio_pagesize (); 1556 intptr_t page = eio_pagesize ();
1525 1557
1526 if (addr < end) 1558 if (addr < end)
1527 if (flags & EIO_MT_MODIFY) /* modify */ 1559 if (flags & EIO_MT_MODIFY) /* modify */
1528 do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len); 1560 do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len && !EIO_CANCELLED (req));
1529 else 1561 else
1530 do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len); 1562 do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len && !EIO_CANCELLED (req));
1531 } 1563 }
1532 1564
1533 return 0; 1565 return 0;
1534} 1566}
1535 1567
1709 1741
1710 case EIO_SYNC: req->result = 0; sync (); break; 1742 case EIO_SYNC: req->result = 0; sync (); break;
1711 case EIO_FSYNC: req->result = fsync (req->int1); break; 1743 case EIO_FSYNC: req->result = fsync (req->int1); break;
1712 case EIO_FDATASYNC: req->result = fdatasync (req->int1); break; 1744 case EIO_FDATASYNC: req->result = fdatasync (req->int1); break;
1713 case EIO_MSYNC: req->result = eio__msync (req->ptr2, req->size, req->int1); break; 1745 case EIO_MSYNC: req->result = eio__msync (req->ptr2, req->size, req->int1); break;
1714 case EIO_MTOUCH: req->result = eio__mtouch (req->ptr2, req->size, req->int1); break; 1746 case EIO_MTOUCH: req->result = eio__mtouch (req); break;
1715 case EIO_MLOCK: req->result = eio__mlock (req->ptr2, req->size); break; 1747 case EIO_MLOCK: req->result = eio__mlock (req->ptr2, req->size); break;
1716 case EIO_MLOCKALL: req->result = eio__mlockall (req->int1); break; 1748 case EIO_MLOCKALL: req->result = eio__mlockall (req->int1); break;
1717 case EIO_SYNC_FILE_RANGE: req->result = eio__sync_file_range (req->int1, req->offs, req->size, req->int2); break; 1749 case EIO_SYNC_FILE_RANGE: req->result = eio__sync_file_range (req->int1, req->offs, req->size, req->int2); break;
1718 1750
1719 case EIO_READDIR: eio__scandir (req, self); break; 1751 case EIO_READDIR: eio__scandir (req, self); break;
1763 case EIO_NOP: 1795 case EIO_NOP:
1764 req->result = 0; 1796 req->result = 0;
1765 break; 1797 break;
1766 1798
1767 case EIO_CUSTOM: 1799 case EIO_CUSTOM:
1768 ((void (*)(eio_req *))req->feed) (req); 1800 req->feed (req);
1769 break; 1801 break;
1770 1802
1771 default: 1803 default:
1772 errno = ENOSYS; 1804 errno = ENOSYS;
1773 req->result = -1; 1805 req->result = -1;
1994eio_req *eio_rename (const char *path, const char *new_path, int pri, eio_cb cb, void *data) 2026eio_req *eio_rename (const char *path, const char *new_path, int pri, eio_cb cb, void *data)
1995{ 2027{
1996 return eio__2path (EIO_RENAME, path, new_path, pri, cb, data); 2028 return eio__2path (EIO_RENAME, path, new_path, pri, cb, data);
1997} 2029}
1998 2030
1999eio_req *eio_custom (eio_cb execute, int pri, eio_cb cb, void *data) 2031eio_req *eio_custom (void (*)(eio_req *) execute, int pri, eio_cb cb, void *data);
2000{ 2032{
2001 REQ (EIO_CUSTOM); req->feed = (void (*)(eio_req *))execute; SEND; 2033 REQ (EIO_CUSTOM); req->feed = execute; SEND;
2002} 2034}
2003 2035
2004#endif 2036#endif
2005 2037
2006eio_req *eio_grp (eio_cb cb, void *data) 2038eio_req *eio_grp (eio_cb cb, void *data)

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines