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.79 by root, Tue Jul 5 16:57:41 2011 UTC

200/*****************************************************************************/ 200/*****************************************************************************/
201 201
202#define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1) 202#define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1)
203 203
204/* calculate time difference in ~1/EIO_TICKS of a second */ 204/* calculate time difference in ~1/EIO_TICKS of a second */
205ECB_INLINE int 205ecb_inline int
206tvdiff (struct timeval *tv1, struct timeval *tv2) 206tvdiff (struct timeval *tv1, struct timeval *tv2)
207{ 207{
208 return (tv2->tv_sec - tv1->tv_sec ) * EIO_TICKS 208 return (tv2->tv_sec - tv1->tv_sec ) * EIO_TICKS
209 + ((tv2->tv_usec - tv1->tv_usec) >> 10); 209 + ((tv2->tv_usec - tv1->tv_usec) >> 10);
210} 210}
739 if (grp->grp_first == req) 739 if (grp->grp_first == req)
740 grp->grp_first = req->grp_next; 740 grp->grp_first = req->grp_next;
741 741
742 res2 = grp_dec (grp); 742 res2 = grp_dec (grp);
743 743
744 if (!res && res2) 744 if (!res)
745 res = res2; 745 res = res2;
746 } 746 }
747 747
748 eio_destroy (req); 748 eio_destroy (req);
749 749
1006 1006
1007 /* according to source inspection, this is correct, and useful behaviour */ 1007 /* according to source inspection, this is correct, and useful behaviour */
1008 if (sbytes) 1008 if (sbytes)
1009 res = sbytes; 1009 res = sbytes;
1010 1010
1011# elif defined (__APPLE__) 1011# elif defined (__APPLE__) && 0 /* broken, as everything on os x */
1012 off_t sbytes = count; 1012 off_t sbytes = count;
1013 res = sendfile (ifd, ofd, offset, &sbytes, 0, 0); 1013 res = sendfile (ifd, ofd, offset, &sbytes, 0, 0);
1014 1014
1015 /* according to the manpage, sbytes is always valid */ 1015 /* according to the manpage, sbytes is always valid */
1016 if (sbytes) 1016 if (sbytes)
1115 count -= cnt; 1115 count -= cnt;
1116 } 1116 }
1117 } 1117 }
1118 1118
1119 return res; 1119 return res;
1120}
1121
1122#ifdef PAGESIZE
1123# define eio_pagesize() PAGESIZE
1124#else
1125static intptr_t
1126eio_pagesize (void)
1127{
1128 static intptr_t page;
1129
1130 if (!page)
1131 page = sysconf (_SC_PAGESIZE);
1132
1133 return page;
1134}
1135#endif
1136
1137static void
1138eio_page_align (void **addr, size_t *length)
1139{
1140 intptr_t mask = eio_pagesize () - 1;
1141
1142 /* round down addr */
1143 intptr_t adj = mask & (intptr_t)*addr;
1144
1145 *addr = (void *)((intptr_t)*addr - adj);
1146 *length += adj;
1147
1148 /* round up length */
1149 *length = (*length + mask) & ~mask;
1150}
1151
1152#if !_POSIX_MEMLOCK
1153# define eio__mlockall(a) ((errno = ENOSYS), -1)
1154#else
1155
1156static int
1157eio__mlockall (int flags)
1158{
1159 #if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 7
1160 extern int mallopt (int, int);
1161 mallopt (-6, 238); /* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=473812 */
1162 #endif
1163
1164 if (EIO_MCL_CURRENT != MCL_CURRENT
1165 || EIO_MCL_FUTURE != MCL_FUTURE)
1166 {
1167 flags = 0
1168 | (flags & EIO_MCL_CURRENT ? MCL_CURRENT : 0)
1169 | (flags & EIO_MCL_FUTURE ? MCL_FUTURE : 0);
1170 }
1171
1172 return mlockall (flags);
1173}
1174#endif
1175
1176#if !_POSIX_MEMLOCK_RANGE
1177# define eio__mlock(a,b) ((errno = ENOSYS), -1)
1178#else
1179
1180static int
1181eio__mlock (void *addr, size_t length)
1182{
1183 eio_page_align (&addr, &length);
1184
1185 return mlock (addr, length);
1186}
1187
1188#endif
1189
1190#if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO)
1191# define eio__msync(a,b,c) ((errno = ENOSYS), -1)
1192#else
1193
1194static int
1195eio__msync (void *mem, size_t len, int flags)
1196{
1197 eio_page_align (&mem, &len);
1198
1199 if (EIO_MS_ASYNC != MS_SYNC
1200 || EIO_MS_INVALIDATE != MS_INVALIDATE
1201 || EIO_MS_SYNC != MS_SYNC)
1202 {
1203 flags = 0
1204 | (flags & EIO_MS_ASYNC ? MS_ASYNC : 0)
1205 | (flags & EIO_MS_INVALIDATE ? MS_INVALIDATE : 0)
1206 | (flags & EIO_MS_SYNC ? MS_SYNC : 0);
1207 }
1208
1209 return msync (mem, len, flags);
1210}
1211
1212#endif
1213
1214static int
1215eio__mtouch (eio_req *req)
1216{
1217 void *mem = req->ptr2;
1218 size_t len = req->size;
1219 int flags = req->int1;
1220
1221 eio_page_align (&mem, &len);
1222
1223 {
1224 intptr_t addr = (intptr_t)mem;
1225 intptr_t end = addr + len;
1226 intptr_t page = eio_pagesize ();
1227
1228 if (addr < end)
1229 if (flags & EIO_MT_MODIFY) /* modify */
1230 do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len && !EIO_CANCELLED (req));
1231 else
1232 do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len && !EIO_CANCELLED (req));
1233 }
1234
1235 return 0;
1236}
1237
1238/*****************************************************************************/
1239/* requests implemented outside eio_execute, because they are so large */
1240
1241static void
1242eio__realpath (eio_req *req, etp_worker *self)
1243{
1244 char *rel = req->ptr1;
1245 char *res;
1246 char *tmp1, *tmp2;
1247#if SYMLOOP_MAX > 32
1248 int symlinks = SYMLOOP_MAX;
1249#else
1250 int symlinks = 32;
1251#endif
1252
1253 req->result = -1;
1254
1255 errno = EINVAL;
1256 if (!rel)
1257 return;
1258
1259 errno = ENOENT;
1260 if (!*rel)
1261 return;
1262
1263 if (!req->ptr2)
1264 {
1265 X_LOCK (wrklock);
1266 req->flags |= EIO_FLAG_PTR2_FREE;
1267 X_UNLOCK (wrklock);
1268 req->ptr2 = malloc (PATH_MAX * 3);
1269
1270 errno = ENOMEM;
1271 if (!req->ptr2)
1272 return;
1273 }
1274
1275 res = req->ptr2;
1276 tmp1 = res + PATH_MAX;
1277 tmp2 = tmp1 + PATH_MAX;
1278
1279#if 0 /* disabled, the musl way to do things is just too racy */
1280#if __linux && defined(O_NONBLOCK) && defined(O_NOATIME)
1281 /* on linux we may be able to ask the kernel */
1282 {
1283 int fd = open (rel, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOATIME);
1284
1285 if (fd >= 0)
1286 {
1287 sprintf (tmp1, "/proc/self/fd/%d", fd);
1288 req->result = readlink (tmp1, res, PATH_MAX);
1289 close (fd);
1290
1291 /* here we should probably stat the open file and the disk file, to make sure they still match */
1292
1293 if (req->result > 0)
1294 goto done;
1295 }
1296 else if (errno == ELOOP || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EIO)
1297 return;
1298 }
1299#endif
1300#endif
1301
1302 if (*rel != '/')
1303 {
1304 if (!getcwd (res, PATH_MAX))
1305 return;
1306
1307 if (res [1]) /* only use if not / */
1308 res += strlen (res);
1309 }
1310
1311 while (*rel)
1312 {
1313 ssize_t len, linklen;
1314 char *beg = rel;
1315
1316 while (*rel && *rel != '/')
1317 ++rel;
1318
1319 len = rel - beg;
1320
1321 if (!len) /* skip slashes */
1322 {
1323 ++rel;
1324 continue;
1325 }
1326
1327 if (beg [0] == '.')
1328 {
1329 if (len == 1)
1330 continue; /* . - nop */
1331
1332 if (beg [1] == '.' && len == 2)
1333 {
1334 /* .. - back up one component, if possible */
1335
1336 while (res != req->ptr2)
1337 if (*--res == '/')
1338 break;
1339
1340 continue;
1341 }
1342 }
1343
1344 errno = ENAMETOOLONG;
1345 if (res + 1 + len + 1 >= tmp1)
1346 return;
1347
1348 /* copy one component */
1349 *res = '/';
1350 memcpy (res + 1, beg, len);
1351
1352 /* zero-terminate, for readlink */
1353 res [len + 1] = 0;
1354
1355 /* now check if it's a symlink */
1356 linklen = readlink (req->ptr2, tmp1, PATH_MAX);
1357
1358 if (linklen < 0)
1359 {
1360 if (errno != EINVAL)
1361 return;
1362
1363 /* it's a normal directory. hopefully */
1364 res += len + 1;
1365 }
1366 else
1367 {
1368 /* yay, it was a symlink - build new path in tmp2 */
1369 int rellen = strlen (rel);
1370
1371 errno = ENAMETOOLONG;
1372 if (linklen + 1 + rellen >= PATH_MAX)
1373 return;
1374
1375 errno = ELOOP;
1376 if (!--symlinks)
1377 return;
1378
1379 if (*tmp1 == '/')
1380 res = req->ptr2; /* symlink resolves to an absolute path */
1381
1382 /* we need to be careful, as rel might point into tmp2 already */
1383 memmove (tmp2 + linklen + 1, rel, rellen + 1);
1384 tmp2 [linklen] = '/';
1385 memcpy (tmp2, tmp1, linklen);
1386
1387 rel = tmp2;
1388 }
1389 }
1390
1391 /* special case for the lone root path */
1392 if (res == req->ptr2)
1393 *res++ = '/';
1394
1395 req->result = res - (char *)req->ptr2;
1396
1397done:
1398 req->ptr2 = realloc (req->ptr2, req->result); /* trade time for space savings */
1120} 1399}
1121 1400
1122static signed char 1401static signed char
1123eio_dent_cmp (const eio_dirent *a, const eio_dirent *b) 1402eio_dent_cmp (const eio_dirent *a, const eio_dirent *b)
1124{ 1403{
1305 flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER); 1584 flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER);
1306 1585
1307 X_LOCK (wrklock); 1586 X_LOCK (wrklock);
1308 /* the corresponding closedir is in ETP_WORKER_CLEAR */ 1587 /* the corresponding closedir is in ETP_WORKER_CLEAR */
1309 self->dirp = dirp = opendir (req->ptr1); 1588 self->dirp = dirp = opendir (req->ptr1);
1589
1590 if (req->flags & EIO_FLAG_PTR1_FREE)
1591 free (req->ptr1);
1310 1592
1311 req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE; 1593 req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE;
1312 req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0; 1594 req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0;
1313 req->ptr2 = names = malloc (namesalloc); 1595 req->ptr2 = names = malloc (namesalloc);
1314 X_UNLOCK (wrklock); 1596 X_UNLOCK (wrklock);
1481 break; 1763 break;
1482 } 1764 }
1483 } 1765 }
1484} 1766}
1485 1767
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/*****************************************************************************/ 1768/*****************************************************************************/
1603 1769
1604#define ALLOC(len) \ 1770#define ALLOC(len) \
1605 if (!req->ptr2) \ 1771 if (!req->ptr2) \
1606 { \ 1772 { \
1695eio_init (void (*want_poll)(void), void (*done_poll)(void)) 1861eio_init (void (*want_poll)(void), void (*done_poll)(void))
1696{ 1862{
1697 return etp_init (want_poll, done_poll); 1863 return etp_init (want_poll, done_poll);
1698} 1864}
1699 1865
1700ECB_INLINE void 1866ecb_inline void
1701eio_api_destroy (eio_req *req) 1867eio_api_destroy (eio_req *req)
1702{ 1868{
1703 free (req); 1869 free (req);
1704} 1870}
1705 1871
1771 case EIO_RENAME: req->result = rename (req->ptr1, req->ptr2); break; 1937 case EIO_RENAME: req->result = rename (req->ptr1, req->ptr2); break;
1772 case EIO_LINK: req->result = link (req->ptr1, req->ptr2); break; 1938 case EIO_LINK: req->result = link (req->ptr1, req->ptr2); break;
1773 case EIO_SYMLINK: req->result = symlink (req->ptr1, req->ptr2); break; 1939 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; 1940 case EIO_MKNOD: req->result = mknod (req->ptr1, (mode_t)req->int2, (dev_t)req->offs); break;
1775 1941
1942 case EIO_REALPATH: eio__realpath (req, self); break;
1943
1776 case EIO_READLINK: ALLOC (PATH_MAX); 1944 case EIO_READLINK: ALLOC (PATH_MAX);
1777 req->result = readlink (req->ptr1, req->ptr2, PATH_MAX); break; 1945 req->result = readlink (req->ptr1, req->ptr2, PATH_MAX); break;
1778 1946
1779 case EIO_SYNC: req->result = 0; sync (); break; 1947 case EIO_SYNC: req->result = 0; sync (); break;
1780 case EIO_FSYNC: req->result = fsync (req->int1); break; 1948 case EIO_FSYNC: req->result = fsync (req->int1); break;
1997eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data) 2165eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data)
1998{ 2166{
1999 return eio__1path (EIO_READLINK, path, pri, cb, data); 2167 return eio__1path (EIO_READLINK, path, pri, cb, data);
2000} 2168}
2001 2169
2170eio_req *eio_realpath (const char *path, int pri, eio_cb cb, void *data)
2171{
2172 return eio__1path (EIO_REALPATH, path, pri, cb, data);
2173}
2174
2002eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data) 2175eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data)
2003{ 2176{
2004 return eio__1path (EIO_STAT, path, pri, cb, data); 2177 return eio__1path (EIO_STAT, path, pri, cb, data);
2005} 2178}
2006 2179

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines