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.81 by root, Tue Jul 5 20:34:42 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
1006 1010
1007 /* according to source inspection, this is correct, and useful behaviour */ 1011 /* according to source inspection, this is correct, and useful behaviour */
1008 if (sbytes) 1012 if (sbytes)
1009 res = sbytes; 1013 res = sbytes;
1010 1014
1011# elif defined (__APPLE__) 1015# elif defined (__APPLE__) && 0 /* broken, as everything on os x */
1012 off_t sbytes = count; 1016 off_t sbytes = count;
1013 res = sendfile (ifd, ofd, offset, &sbytes, 0, 0); 1017 res = sendfile (ifd, ofd, offset, &sbytes, 0, 0);
1014 1018
1015 /* according to the manpage, sbytes is always valid */ 1019 /* according to the manpage, sbytes is always valid */
1016 if (sbytes) 1020 if (sbytes)
1115 count -= cnt; 1119 count -= cnt;
1116 } 1120 }
1117 } 1121 }
1118 1122
1119 return res; 1123 return res;
1124}
1125
1126#ifdef PAGESIZE
1127# define eio_pagesize() PAGESIZE
1128#else
1129static intptr_t
1130eio_pagesize (void)
1131{
1132 static intptr_t page;
1133
1134 if (!page)
1135 page = sysconf (_SC_PAGESIZE);
1136
1137 return page;
1138}
1139#endif
1140
1141static void
1142eio_page_align (void **addr, size_t *length)
1143{
1144 intptr_t mask = eio_pagesize () - 1;
1145
1146 /* round down addr */
1147 intptr_t adj = mask & (intptr_t)*addr;
1148
1149 *addr = (void *)((intptr_t)*addr - adj);
1150 *length += adj;
1151
1152 /* round up length */
1153 *length = (*length + mask) & ~mask;
1154}
1155
1156#if !_POSIX_MEMLOCK
1157# define eio__mlockall(a) ((errno = ENOSYS), -1)
1158#else
1159
1160static int
1161eio__mlockall (int flags)
1162{
1163 #if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 7
1164 extern int mallopt (int, int);
1165 mallopt (-6, 238); /* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=473812 */
1166 #endif
1167
1168 if (EIO_MCL_CURRENT != MCL_CURRENT
1169 || EIO_MCL_FUTURE != MCL_FUTURE)
1170 {
1171 flags = 0
1172 | (flags & EIO_MCL_CURRENT ? MCL_CURRENT : 0)
1173 | (flags & EIO_MCL_FUTURE ? MCL_FUTURE : 0);
1174 }
1175
1176 return mlockall (flags);
1177}
1178#endif
1179
1180#if !_POSIX_MEMLOCK_RANGE
1181# define eio__mlock(a,b) ((errno = ENOSYS), -1)
1182#else
1183
1184static int
1185eio__mlock (void *addr, size_t length)
1186{
1187 eio_page_align (&addr, &length);
1188
1189 return mlock (addr, length);
1190}
1191
1192#endif
1193
1194#if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO)
1195# define eio__msync(a,b,c) ((errno = ENOSYS), -1)
1196#else
1197
1198static int
1199eio__msync (void *mem, size_t len, int flags)
1200{
1201 eio_page_align (&mem, &len);
1202
1203 if (EIO_MS_ASYNC != MS_SYNC
1204 || EIO_MS_INVALIDATE != MS_INVALIDATE
1205 || EIO_MS_SYNC != MS_SYNC)
1206 {
1207 flags = 0
1208 | (flags & EIO_MS_ASYNC ? MS_ASYNC : 0)
1209 | (flags & EIO_MS_INVALIDATE ? MS_INVALIDATE : 0)
1210 | (flags & EIO_MS_SYNC ? MS_SYNC : 0);
1211 }
1212
1213 return msync (mem, len, flags);
1214}
1215
1216#endif
1217
1218static int
1219eio__mtouch (eio_req *req)
1220{
1221 void *mem = req->ptr2;
1222 size_t len = req->size;
1223 int flags = req->int1;
1224
1225 eio_page_align (&mem, &len);
1226
1227 {
1228 intptr_t addr = (intptr_t)mem;
1229 intptr_t end = addr + len;
1230 intptr_t page = eio_pagesize ();
1231
1232 if (addr < end)
1233 if (flags & EIO_MT_MODIFY) /* modify */
1234 do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len && !EIO_CANCELLED (req));
1235 else
1236 do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len && !EIO_CANCELLED (req));
1237 }
1238
1239 return 0;
1240}
1241
1242/*****************************************************************************/
1243/* requests implemented outside eio_execute, because they are so large */
1244
1245static void
1246eio__realpath (eio_req *req, etp_worker *self)
1247{
1248 char *rel = req->ptr1;
1249 char *res;
1250 char *tmp1, *tmp2;
1251#if SYMLOOP_MAX > 32
1252 int symlinks = SYMLOOP_MAX;
1253#else
1254 int symlinks = 32;
1255#endif
1256
1257 req->result = -1;
1258
1259 errno = EINVAL;
1260 if (!rel)
1261 return;
1262
1263 errno = ENOENT;
1264 if (!*rel)
1265 return;
1266
1267 if (!req->ptr2)
1268 {
1269 X_LOCK (wrklock);
1270 req->flags |= EIO_FLAG_PTR2_FREE;
1271 X_UNLOCK (wrklock);
1272 req->ptr2 = malloc (PATH_MAX * 3);
1273
1274 errno = ENOMEM;
1275 if (!req->ptr2)
1276 return;
1277 }
1278
1279 res = req->ptr2;
1280 tmp1 = res + PATH_MAX;
1281 tmp2 = tmp1 + PATH_MAX;
1282
1283#if 0 /* disabled, the musl way to do things is just too racy */
1284#if __linux && defined(O_NONBLOCK) && defined(O_NOATIME)
1285 /* on linux we may be able to ask the kernel */
1286 {
1287 int fd = open (rel, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOATIME);
1288
1289 if (fd >= 0)
1290 {
1291 sprintf (tmp1, "/proc/self/fd/%d", fd);
1292 req->result = readlink (tmp1, res, PATH_MAX);
1293 close (fd);
1294
1295 /* here we should probably stat the open file and the disk file, to make sure they still match */
1296
1297 if (req->result > 0)
1298 goto done;
1299 }
1300 else if (errno == ELOOP || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EIO)
1301 return;
1302 }
1303#endif
1304#endif
1305
1306 if (*rel != '/')
1307 {
1308 if (!getcwd (res, PATH_MAX))
1309 return;
1310
1311 if (res [1]) /* only use if not / */
1312 res += strlen (res);
1313 }
1314
1315 while (*rel)
1316 {
1317 ssize_t len, linklen;
1318 char *beg = rel;
1319
1320 while (*rel && *rel != '/')
1321 ++rel;
1322
1323 len = rel - beg;
1324
1325 if (!len) /* skip slashes */
1326 {
1327 ++rel;
1328 continue;
1329 }
1330
1331 if (beg [0] == '.')
1332 {
1333 if (len == 1)
1334 continue; /* . - nop */
1335
1336 if (beg [1] == '.' && len == 2)
1337 {
1338 /* .. - back up one component, if possible */
1339
1340 while (res != req->ptr2)
1341 if (*--res == '/')
1342 break;
1343
1344 continue;
1345 }
1346 }
1347
1348 errno = ENAMETOOLONG;
1349 if (res + 1 + len + 1 >= tmp1)
1350 return;
1351
1352 /* copy one component */
1353 *res = '/';
1354 memcpy (res + 1, beg, len);
1355
1356 /* zero-terminate, for readlink */
1357 res [len + 1] = 0;
1358
1359 /* now check if it's a symlink */
1360 linklen = readlink (req->ptr2, tmp1, PATH_MAX);
1361
1362 if (linklen < 0)
1363 {
1364 if (errno != EINVAL)
1365 return;
1366
1367 /* it's a normal directory. hopefully */
1368 res += len + 1;
1369 }
1370 else
1371 {
1372 /* yay, it was a symlink - build new path in tmp2 */
1373 int rellen = strlen (rel);
1374
1375 errno = ENAMETOOLONG;
1376 if (linklen + 1 + rellen >= PATH_MAX)
1377 return;
1378
1379 errno = ELOOP;
1380 if (!--symlinks)
1381 return;
1382
1383 if (*tmp1 == '/')
1384 res = req->ptr2; /* symlink resolves to an absolute path */
1385
1386 /* we need to be careful, as rel might point into tmp2 already */
1387 memmove (tmp2 + linklen + 1, rel, rellen + 1);
1388 tmp2 [linklen] = '/';
1389 memcpy (tmp2, tmp1, linklen);
1390
1391 rel = tmp2;
1392 }
1393 }
1394
1395 /* special case for the lone root path */
1396 if (res == req->ptr2)
1397 *res++ = '/';
1398
1399 req->result = res - (char *)req->ptr2;
1400
1401done:
1402 req->ptr2 = realloc (req->ptr2, req->result); /* trade time for space savings */
1120} 1403}
1121 1404
1122static signed char 1405static signed char
1123eio_dent_cmp (const eio_dirent *a, const eio_dirent *b) 1406eio_dent_cmp (const eio_dirent *a, const eio_dirent *b)
1124{ 1407{
1305 flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER); 1588 flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER);
1306 1589
1307 X_LOCK (wrklock); 1590 X_LOCK (wrklock);
1308 /* the corresponding closedir is in ETP_WORKER_CLEAR */ 1591 /* the corresponding closedir is in ETP_WORKER_CLEAR */
1309 self->dirp = dirp = opendir (req->ptr1); 1592 self->dirp = dirp = opendir (req->ptr1);
1593
1594 if (req->flags & EIO_FLAG_PTR1_FREE)
1595 free (req->ptr1);
1310 1596
1311 req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE; 1597 req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE;
1312 req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0; 1598 req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0;
1313 req->ptr2 = names = malloc (namesalloc); 1599 req->ptr2 = names = malloc (namesalloc);
1314 X_UNLOCK (wrklock); 1600 X_UNLOCK (wrklock);
1481 break; 1767 break;
1482 } 1768 }
1483 } 1769 }
1484} 1770}
1485 1771
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/*****************************************************************************/ 1772/*****************************************************************************/
1603 1773
1604#define ALLOC(len) \ 1774#define ALLOC(len) \
1605 if (!req->ptr2) \ 1775 if (!req->ptr2) \
1606 { \ 1776 { \
1663 X_UNLOCK (reqlock); 1833 X_UNLOCK (reqlock);
1664 1834
1665 if (req->type < 0) 1835 if (req->type < 0)
1666 goto quit; 1836 goto quit;
1667 1837
1668 if (!EIO_CANCELLED (req))
1669 ETP_EXECUTE (self, req); 1838 ETP_EXECUTE (self, req);
1670 1839
1671 X_LOCK (reslock); 1840 X_LOCK (reslock);
1672 1841
1673 ++npending; 1842 ++npending;
1674 1843
1695eio_init (void (*want_poll)(void), void (*done_poll)(void)) 1864eio_init (void (*want_poll)(void), void (*done_poll)(void))
1696{ 1865{
1697 return etp_init (want_poll, done_poll); 1866 return etp_init (want_poll, done_poll);
1698} 1867}
1699 1868
1700ECB_INLINE void 1869ecb_inline void
1701eio_api_destroy (eio_req *req) 1870eio_api_destroy (eio_req *req)
1702{ 1871{
1703 free (req); 1872 free (req);
1704} 1873}
1705 1874
1728 } 1897 }
1729 1898
1730static void 1899static void
1731eio_execute (etp_worker *self, eio_req *req) 1900eio_execute (etp_worker *self, eio_req *req)
1732{ 1901{
1902 if (ecb_expect_false (EIO_CANCELLED (req)))
1903 {
1904 req->result = -1;
1905 req->errorno = ECANCELED;
1906 return;
1907 }
1908
1733 switch (req->type) 1909 switch (req->type)
1734 { 1910 {
1735 case EIO_READ: ALLOC (req->size); 1911 case EIO_READ: ALLOC (req->size);
1736 req->result = req->offs >= 0 1912 req->result = req->offs >= 0
1737 ? pread (req->int1, req->ptr2, req->size, req->offs) 1913 ? pread (req->int1, req->ptr2, req->size, req->offs)
1771 case EIO_RENAME: req->result = rename (req->ptr1, req->ptr2); break; 1947 case EIO_RENAME: req->result = rename (req->ptr1, req->ptr2); break;
1772 case EIO_LINK: req->result = link (req->ptr1, req->ptr2); break; 1948 case EIO_LINK: req->result = link (req->ptr1, req->ptr2); break;
1773 case EIO_SYMLINK: req->result = symlink (req->ptr1, req->ptr2); break; 1949 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; 1950 case EIO_MKNOD: req->result = mknod (req->ptr1, (mode_t)req->int2, (dev_t)req->offs); break;
1775 1951
1952 case EIO_REALPATH: eio__realpath (req, self); break;
1953
1776 case EIO_READLINK: ALLOC (PATH_MAX); 1954 case EIO_READLINK: ALLOC (PATH_MAX);
1777 req->result = readlink (req->ptr1, req->ptr2, PATH_MAX); break; 1955 req->result = readlink (req->ptr1, req->ptr2, PATH_MAX); break;
1778 1956
1779 case EIO_SYNC: req->result = 0; sync (); break; 1957 case EIO_SYNC: req->result = 0; sync (); break;
1780 case EIO_FSYNC: req->result = fsync (req->int1); break; 1958 case EIO_FSYNC: req->result = fsync (req->int1); break;
1997eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data) 2175eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data)
1998{ 2176{
1999 return eio__1path (EIO_READLINK, path, pri, cb, data); 2177 return eio__1path (EIO_READLINK, path, pri, cb, data);
2000} 2178}
2001 2179
2180eio_req *eio_realpath (const char *path, int pri, eio_cb cb, void *data)
2181{
2182 return eio__1path (EIO_REALPATH, path, pri, cb, data);
2183}
2184
2002eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data) 2185eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data)
2003{ 2186{
2004 return eio__1path (EIO_STAT, path, pri, cb, data); 2187 return eio__1path (EIO_STAT, path, pri, cb, data);
2005} 2188}
2006 2189

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines