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

Comparing libeio/eio.c (file contents):
Revision 1.72 by root, Fri Jun 10 12:45:20 2011 UTC vs.
Revision 1.82 by root, Thu Jul 7 15:44:44 2011 UTC

60#include <limits.h> 60#include <limits.h>
61#include <fcntl.h> 61#include <fcntl.h>
62#include <assert.h> 62#include <assert.h>
63 63
64/* intptr_t comes from unistd.h, says POSIX/UNIX/tradition */ 64/* intptr_t comes from unistd.h, says POSIX/UNIX/tradition */
65/* intptr_t only comes form stdint.h, says idiot openbsd coder */ 65/* intptr_t only comes from stdint.h, says idiot openbsd coder */
66#if HAVE_STDINT_H 66#if HAVE_STDINT_H
67# include <stdint.h> 67# include <stdint.h>
68#endif 68#endif
69
70#ifndef ECANCELED
71# define ECANCELED EDOM
72#endif
73
74static void eio_destroy (eio_req *req);
69 75
70#ifndef EIO_FINISH 76#ifndef EIO_FINISH
71# define EIO_FINISH(req) ((req)->finish) && !EIO_CANCELLED (req) ? (req)->finish (req) : 0 77# define EIO_FINISH(req) ((req)->finish) && !EIO_CANCELLED (req) ? (req)->finish (req) : 0
72#endif 78#endif
73 79
200/*****************************************************************************/ 206/*****************************************************************************/
201 207
202#define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1) 208#define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1)
203 209
204/* calculate time difference in ~1/EIO_TICKS of a second */ 210/* calculate time difference in ~1/EIO_TICKS of a second */
205ECB_INLINE int 211ecb_inline int
206tvdiff (struct timeval *tv1, struct timeval *tv2) 212tvdiff (struct timeval *tv1, struct timeval *tv2)
207{ 213{
208 return (tv2->tv_sec - tv1->tv_sec ) * EIO_TICKS 214 return (tv2->tv_sec - tv1->tv_sec ) * EIO_TICKS
209 + ((tv2->tv_usec - tv1->tv_usec) >> 10); 215 + ((tv2->tv_usec - tv1->tv_usec) >> 10);
210} 216}
583} 589}
584 590
585static void 591static void
586etp_cancel (ETP_REQ *req) 592etp_cancel (ETP_REQ *req)
587{ 593{
588 X_LOCK (wrklock); 594 req->cancelled = 1;
589 req->flags |= EIO_FLAG_CANCELLED;
590 X_UNLOCK (wrklock);
591 595
592 eio_grp_cancel (req); 596 eio_grp_cancel (req);
593} 597}
594 598
595static void 599static void
711 return eio_finish (grp); 715 return eio_finish (grp);
712 else 716 else
713 return 0; 717 return 0;
714} 718}
715 719
716void 720static void
717eio_destroy (eio_req *req) 721eio_destroy (eio_req *req)
718{ 722{
719 if ((req)->flags & EIO_FLAG_PTR1_FREE) free (req->ptr1); 723 if ((req)->flags & EIO_FLAG_PTR1_FREE) free (req->ptr1);
720 if ((req)->flags & EIO_FLAG_PTR2_FREE) free (req->ptr2); 724 if ((req)->flags & EIO_FLAG_PTR2_FREE) free (req->ptr2);
721 725
739 if (grp->grp_first == req) 743 if (grp->grp_first == req)
740 grp->grp_first = req->grp_next; 744 grp->grp_first = req->grp_next;
741 745
742 res2 = grp_dec (grp); 746 res2 = grp_dec (grp);
743 747
744 if (!res && res2) 748 if (!res)
745 res = res2; 749 res = res2;
746 } 750 }
747 751
748 eio_destroy (req); 752 eio_destroy (req);
749 753
981 if (!count) 985 if (!count)
982 return 0; 986 return 0;
983 987
984 for (;;) 988 for (;;)
985 { 989 {
990#ifdef __APPLE__
991# undef HAVE_SENDFILE /* broken, as everything on os x */
992#endif
986#if HAVE_SENDFILE 993#if HAVE_SENDFILE
987# if __linux 994# if __linux
988 off_t soffset = offset; 995 off_t soffset = offset;
989 res = sendfile (ofd, ifd, &soffset, count); 996 res = sendfile (ofd, ifd, &soffset, count);
990 997
1115 count -= cnt; 1122 count -= cnt;
1116 } 1123 }
1117 } 1124 }
1118 1125
1119 return res; 1126 return res;
1127}
1128
1129#ifdef PAGESIZE
1130# define eio_pagesize() PAGESIZE
1131#else
1132static intptr_t
1133eio_pagesize (void)
1134{
1135 static intptr_t page;
1136
1137 if (!page)
1138 page = sysconf (_SC_PAGESIZE);
1139
1140 return page;
1141}
1142#endif
1143
1144static void
1145eio_page_align (void **addr, size_t *length)
1146{
1147 intptr_t mask = eio_pagesize () - 1;
1148
1149 /* round down addr */
1150 intptr_t adj = mask & (intptr_t)*addr;
1151
1152 *addr = (void *)((intptr_t)*addr - adj);
1153 *length += adj;
1154
1155 /* round up length */
1156 *length = (*length + mask) & ~mask;
1157}
1158
1159#if !_POSIX_MEMLOCK
1160# define eio__mlockall(a) ((errno = ENOSYS), -1)
1161#else
1162
1163static int
1164eio__mlockall (int flags)
1165{
1166 #if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 7
1167 extern int mallopt (int, int);
1168 mallopt (-6, 238); /* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=473812 */
1169 #endif
1170
1171 if (EIO_MCL_CURRENT != MCL_CURRENT
1172 || EIO_MCL_FUTURE != MCL_FUTURE)
1173 {
1174 flags = 0
1175 | (flags & EIO_MCL_CURRENT ? MCL_CURRENT : 0)
1176 | (flags & EIO_MCL_FUTURE ? MCL_FUTURE : 0);
1177 }
1178
1179 return mlockall (flags);
1180}
1181#endif
1182
1183#if !_POSIX_MEMLOCK_RANGE
1184# define eio__mlock(a,b) ((errno = ENOSYS), -1)
1185#else
1186
1187static int
1188eio__mlock (void *addr, size_t length)
1189{
1190 eio_page_align (&addr, &length);
1191
1192 return mlock (addr, length);
1193}
1194
1195#endif
1196
1197#if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO)
1198# define eio__msync(a,b,c) ((errno = ENOSYS), -1)
1199#else
1200
1201static int
1202eio__msync (void *mem, size_t len, int flags)
1203{
1204 eio_page_align (&mem, &len);
1205
1206 if (EIO_MS_ASYNC != MS_SYNC
1207 || EIO_MS_INVALIDATE != MS_INVALIDATE
1208 || EIO_MS_SYNC != MS_SYNC)
1209 {
1210 flags = 0
1211 | (flags & EIO_MS_ASYNC ? MS_ASYNC : 0)
1212 | (flags & EIO_MS_INVALIDATE ? MS_INVALIDATE : 0)
1213 | (flags & EIO_MS_SYNC ? MS_SYNC : 0);
1214 }
1215
1216 return msync (mem, len, flags);
1217}
1218
1219#endif
1220
1221static int
1222eio__mtouch (eio_req *req)
1223{
1224 void *mem = req->ptr2;
1225 size_t len = req->size;
1226 int flags = req->int1;
1227
1228 eio_page_align (&mem, &len);
1229
1230 {
1231 intptr_t addr = (intptr_t)mem;
1232 intptr_t end = addr + len;
1233 intptr_t page = eio_pagesize ();
1234
1235 if (addr < end)
1236 if (flags & EIO_MT_MODIFY) /* modify */
1237 do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len && !EIO_CANCELLED (req));
1238 else
1239 do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len && !EIO_CANCELLED (req));
1240 }
1241
1242 return 0;
1243}
1244
1245/*****************************************************************************/
1246/* requests implemented outside eio_execute, because they are so large */
1247
1248static void
1249eio__realpath (eio_req *req, etp_worker *self)
1250{
1251 char *rel = req->ptr1;
1252 char *res;
1253 char *tmp1, *tmp2;
1254#if SYMLOOP_MAX > 32
1255 int symlinks = SYMLOOP_MAX;
1256#else
1257 int symlinks = 32;
1258#endif
1259
1260 req->result = -1;
1261
1262 errno = EINVAL;
1263 if (!rel)
1264 return;
1265
1266 errno = ENOENT;
1267 if (!*rel)
1268 return;
1269
1270 if (!req->ptr2)
1271 {
1272 X_LOCK (wrklock);
1273 req->flags |= EIO_FLAG_PTR2_FREE;
1274 X_UNLOCK (wrklock);
1275 req->ptr2 = malloc (PATH_MAX * 3);
1276
1277 errno = ENOMEM;
1278 if (!req->ptr2)
1279 return;
1280 }
1281
1282 res = req->ptr2;
1283 tmp1 = res + PATH_MAX;
1284 tmp2 = tmp1 + PATH_MAX;
1285
1286#if 0 /* disabled, the musl way to do things is just too racy */
1287#if __linux && defined(O_NONBLOCK) && defined(O_NOATIME)
1288 /* on linux we may be able to ask the kernel */
1289 {
1290 int fd = open (rel, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOATIME);
1291
1292 if (fd >= 0)
1293 {
1294 sprintf (tmp1, "/proc/self/fd/%d", fd);
1295 req->result = readlink (tmp1, res, PATH_MAX);
1296 close (fd);
1297
1298 /* here we should probably stat the open file and the disk file, to make sure they still match */
1299
1300 if (req->result > 0)
1301 goto done;
1302 }
1303 else if (errno == ELOOP || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EIO)
1304 return;
1305 }
1306#endif
1307#endif
1308
1309 if (*rel != '/')
1310 {
1311 if (!getcwd (res, PATH_MAX))
1312 return;
1313
1314 if (res [1]) /* only use if not / */
1315 res += strlen (res);
1316 }
1317
1318 while (*rel)
1319 {
1320 ssize_t len, linklen;
1321 char *beg = rel;
1322
1323 while (*rel && *rel != '/')
1324 ++rel;
1325
1326 len = rel - beg;
1327
1328 if (!len) /* skip slashes */
1329 {
1330 ++rel;
1331 continue;
1332 }
1333
1334 if (beg [0] == '.')
1335 {
1336 if (len == 1)
1337 continue; /* . - nop */
1338
1339 if (beg [1] == '.' && len == 2)
1340 {
1341 /* .. - back up one component, if possible */
1342
1343 while (res != req->ptr2)
1344 if (*--res == '/')
1345 break;
1346
1347 continue;
1348 }
1349 }
1350
1351 errno = ENAMETOOLONG;
1352 if (res + 1 + len + 1 >= tmp1)
1353 return;
1354
1355 /* copy one component */
1356 *res = '/';
1357 memcpy (res + 1, beg, len);
1358
1359 /* zero-terminate, for readlink */
1360 res [len + 1] = 0;
1361
1362 /* now check if it's a symlink */
1363 linklen = readlink (req->ptr2, tmp1, PATH_MAX);
1364
1365 if (linklen < 0)
1366 {
1367 if (errno != EINVAL)
1368 return;
1369
1370 /* it's a normal directory. hopefully */
1371 res += len + 1;
1372 }
1373 else
1374 {
1375 /* yay, it was a symlink - build new path in tmp2 */
1376 int rellen = strlen (rel);
1377
1378 errno = ENAMETOOLONG;
1379 if (linklen + 1 + rellen >= PATH_MAX)
1380 return;
1381
1382 errno = ELOOP;
1383 if (!--symlinks)
1384 return;
1385
1386 if (*tmp1 == '/')
1387 res = req->ptr2; /* symlink resolves to an absolute path */
1388
1389 /* we need to be careful, as rel might point into tmp2 already */
1390 memmove (tmp2 + linklen + 1, rel, rellen + 1);
1391 tmp2 [linklen] = '/';
1392 memcpy (tmp2, tmp1, linklen);
1393
1394 rel = tmp2;
1395 }
1396 }
1397
1398 /* special case for the lone root path */
1399 if (res == req->ptr2)
1400 *res++ = '/';
1401
1402 req->result = res - (char *)req->ptr2;
1403
1404done:
1405 req->ptr2 = realloc (req->ptr2, req->result); /* trade time for space savings */
1120} 1406}
1121 1407
1122static signed char 1408static signed char
1123eio_dent_cmp (const eio_dirent *a, const eio_dirent *b) 1409eio_dent_cmp (const eio_dirent *a, const eio_dirent *b)
1124{ 1410{
1305 flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER); 1591 flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER);
1306 1592
1307 X_LOCK (wrklock); 1593 X_LOCK (wrklock);
1308 /* the corresponding closedir is in ETP_WORKER_CLEAR */ 1594 /* the corresponding closedir is in ETP_WORKER_CLEAR */
1309 self->dirp = dirp = opendir (req->ptr1); 1595 self->dirp = dirp = opendir (req->ptr1);
1596
1597 if (req->flags & EIO_FLAG_PTR1_FREE)
1598 free (req->ptr1);
1310 1599
1311 req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE; 1600 req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE;
1312 req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0; 1601 req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0;
1313 req->ptr2 = names = malloc (namesalloc); 1602 req->ptr2 = names = malloc (namesalloc);
1314 X_UNLOCK (wrklock); 1603 X_UNLOCK (wrklock);
1481 break; 1770 break;
1482 } 1771 }
1483 } 1772 }
1484} 1773}
1485 1774
1486#ifdef PAGESIZE
1487# define eio_pagesize() PAGESIZE
1488#else
1489static intptr_t
1490eio_pagesize (void)
1491{
1492 static intptr_t page;
1493
1494 if (!page)
1495 page = sysconf (_SC_PAGESIZE);
1496
1497 return page;
1498}
1499#endif
1500
1501static void
1502eio_page_align (void **addr, size_t *length)
1503{
1504 intptr_t mask = eio_pagesize () - 1;
1505
1506 /* round down addr */
1507 intptr_t adj = mask & (intptr_t)*addr;
1508
1509 *addr = (void *)((intptr_t)*addr - adj);
1510 *length += adj;
1511
1512 /* round up length */
1513 *length = (*length + mask) & ~mask;
1514}
1515
1516#if !_POSIX_MEMLOCK
1517# define eio__mlockall(a) ((errno = ENOSYS), -1)
1518#else
1519
1520static int
1521eio__mlockall (int flags)
1522{
1523 #if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 7
1524 extern int mallopt (int, int);
1525 mallopt (-6, 238); /* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=473812 */
1526 #endif
1527
1528 if (EIO_MCL_CURRENT != MCL_CURRENT
1529 || EIO_MCL_FUTURE != MCL_FUTURE)
1530 {
1531 flags = 0
1532 | (flags & EIO_MCL_CURRENT ? MCL_CURRENT : 0)
1533 | (flags & EIO_MCL_FUTURE ? MCL_FUTURE : 0);
1534 }
1535
1536 return mlockall (flags);
1537}
1538#endif
1539
1540#if !_POSIX_MEMLOCK_RANGE
1541# define eio__mlock(a,b) ((errno = ENOSYS), -1)
1542#else
1543
1544static int
1545eio__mlock (void *addr, size_t length)
1546{
1547 eio_page_align (&addr, &length);
1548
1549 return mlock (addr, length);
1550}
1551
1552#endif
1553
1554#if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO)
1555# define eio__msync(a,b,c) ((errno = ENOSYS), -1)
1556#else
1557
1558static int
1559eio__msync (void *mem, size_t len, int flags)
1560{
1561 eio_page_align (&mem, &len);
1562
1563 if (EIO_MS_ASYNC != MS_SYNC
1564 || EIO_MS_INVALIDATE != MS_INVALIDATE
1565 || EIO_MS_SYNC != MS_SYNC)
1566 {
1567 flags = 0
1568 | (flags & EIO_MS_ASYNC ? MS_ASYNC : 0)
1569 | (flags & EIO_MS_INVALIDATE ? MS_INVALIDATE : 0)
1570 | (flags & EIO_MS_SYNC ? MS_SYNC : 0);
1571 }
1572
1573 return msync (mem, len, flags);
1574}
1575
1576#endif
1577
1578static int
1579eio__mtouch (eio_req *req)
1580{
1581 void *mem = req->ptr2;
1582 size_t len = req->size;
1583 int flags = req->int1;
1584
1585 eio_page_align (&mem, &len);
1586
1587 {
1588 intptr_t addr = (intptr_t)mem;
1589 intptr_t end = addr + len;
1590 intptr_t page = eio_pagesize ();
1591
1592 if (addr < end)
1593 if (flags & EIO_MT_MODIFY) /* modify */
1594 do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len && !EIO_CANCELLED (req));
1595 else
1596 do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len && !EIO_CANCELLED (req));
1597 }
1598
1599 return 0;
1600}
1601
1602/*****************************************************************************/ 1775/*****************************************************************************/
1603 1776
1604#define ALLOC(len) \ 1777#define ALLOC(len) \
1605 if (!req->ptr2) \ 1778 if (!req->ptr2) \
1606 { \ 1779 { \
1663 X_UNLOCK (reqlock); 1836 X_UNLOCK (reqlock);
1664 1837
1665 if (req->type < 0) 1838 if (req->type < 0)
1666 goto quit; 1839 goto quit;
1667 1840
1668 if (!EIO_CANCELLED (req))
1669 ETP_EXECUTE (self, req); 1841 ETP_EXECUTE (self, req);
1670 1842
1671 X_LOCK (reslock); 1843 X_LOCK (reslock);
1672 1844
1673 ++npending; 1845 ++npending;
1674 1846
1695eio_init (void (*want_poll)(void), void (*done_poll)(void)) 1867eio_init (void (*want_poll)(void), void (*done_poll)(void))
1696{ 1868{
1697 return etp_init (want_poll, done_poll); 1869 return etp_init (want_poll, done_poll);
1698} 1870}
1699 1871
1700ECB_INLINE void 1872ecb_inline void
1701eio_api_destroy (eio_req *req) 1873eio_api_destroy (eio_req *req)
1702{ 1874{
1703 free (req); 1875 free (req);
1704} 1876}
1705 1877
1728 } 1900 }
1729 1901
1730static void 1902static void
1731eio_execute (etp_worker *self, eio_req *req) 1903eio_execute (etp_worker *self, eio_req *req)
1732{ 1904{
1905 if (ecb_expect_false (EIO_CANCELLED (req)))
1906 {
1907 req->result = -1;
1908 req->errorno = ECANCELED;
1909 return;
1910 }
1911
1733 switch (req->type) 1912 switch (req->type)
1734 { 1913 {
1735 case EIO_READ: ALLOC (req->size); 1914 case EIO_READ: ALLOC (req->size);
1736 req->result = req->offs >= 0 1915 req->result = req->offs >= 0
1737 ? pread (req->int1, req->ptr2, req->size, req->offs) 1916 ? pread (req->int1, req->ptr2, req->size, req->offs)
1771 case EIO_RENAME: req->result = rename (req->ptr1, req->ptr2); break; 1950 case EIO_RENAME: req->result = rename (req->ptr1, req->ptr2); break;
1772 case EIO_LINK: req->result = link (req->ptr1, req->ptr2); break; 1951 case EIO_LINK: req->result = link (req->ptr1, req->ptr2); break;
1773 case EIO_SYMLINK: req->result = symlink (req->ptr1, req->ptr2); break; 1952 case EIO_SYMLINK: req->result = symlink (req->ptr1, req->ptr2); break;
1774 case EIO_MKNOD: req->result = mknod (req->ptr1, (mode_t)req->int2, (dev_t)req->offs); break; 1953 case EIO_MKNOD: req->result = mknod (req->ptr1, (mode_t)req->int2, (dev_t)req->offs); break;
1775 1954
1955 case EIO_REALPATH: eio__realpath (req, self); break;
1956
1776 case EIO_READLINK: ALLOC (PATH_MAX); 1957 case EIO_READLINK: ALLOC (PATH_MAX);
1777 req->result = readlink (req->ptr1, req->ptr2, PATH_MAX); break; 1958 req->result = readlink (req->ptr1, req->ptr2, PATH_MAX); break;
1778 1959
1779 case EIO_SYNC: req->result = 0; sync (); break; 1960 case EIO_SYNC: req->result = 0; sync (); break;
1780 case EIO_FSYNC: req->result = fsync (req->int1); break; 1961 case EIO_FSYNC: req->result = fsync (req->int1); break;
1997eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data) 2178eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data)
1998{ 2179{
1999 return eio__1path (EIO_READLINK, path, pri, cb, data); 2180 return eio__1path (EIO_READLINK, path, pri, cb, data);
2000} 2181}
2001 2182
2183eio_req *eio_realpath (const char *path, int pri, eio_cb cb, void *data)
2184{
2185 return eio__1path (EIO_REALPATH, path, pri, cb, data);
2186}
2187
2002eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data) 2188eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data)
2003{ 2189{
2004 return eio__1path (EIO_STAT, path, pri, cb, data); 2190 return eio__1path (EIO_STAT, path, pri, cb, data);
2005} 2191}
2006 2192

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines