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

Comparing libeio/eio.c (file contents):
Revision 1.90 by root, Sat Jul 16 16:46:10 2011 UTC vs.
Revision 1.91 by root, Sun Jul 17 04:20:04 2011 UTC

111 #define fsync(fd) (FlushFileBuffers ((HANDLE)EIO_FD_TO_WIN32_HANDLE (fd)) ? 0 : EIO_ERRNO (EBADF, -1)) 111 #define fsync(fd) (FlushFileBuffers ((HANDLE)EIO_FD_TO_WIN32_HANDLE (fd)) ? 0 : EIO_ERRNO (EBADF, -1))
112 #define mkdir(path,mode) _mkdir (path) 112 #define mkdir(path,mode) _mkdir (path)
113 #define link(old,neu) (CreateHardLink (neu, old, 0) ? 0 : EIO_ERRNO (ENOENT, -1)) 113 #define link(old,neu) (CreateHardLink (neu, old, 0) ? 0 : EIO_ERRNO (ENOENT, -1))
114 114
115 #define chmod(path,mode) _chmod (path, mode) 115 #define chmod(path,mode) _chmod (path, mode)
116 #define dup(fd) _dup (fd)
117 #define dup2(fd1,fd2) _dup2 (fd1, fd2)
118
116 #define fchmod(fd,mode) EIO_ENOSYS () 119 #define fchmod(fd,mode) EIO_ENOSYS ()
117 #define chown(path,uid,gid) EIO_ENOSYS () 120 #define chown(path,uid,gid) EIO_ENOSYS ()
118 #define fchown(fd,uid,gid) EIO_ENOSYS () 121 #define fchown(fd,uid,gid) EIO_ENOSYS ()
119 #define truncate(path,offs) EIO_ENOSYS () /* far-miss: SetEndOfFile */ 122 #define truncate(path,offs) EIO_ENOSYS () /* far-miss: SetEndOfFile */
120 #define ftruncate(fd,offs) EIO_ENOSYS () /* near-miss: SetEndOfFile */ 123 #define ftruncate(fd,offs) EIO_ENOSYS () /* near-miss: SetEndOfFile */
138 141
139 return EIO_ERRNO (ENOENT, -1); 142 return EIO_ERRNO (ENOENT, -1);
140 } 143 }
141 144
142 /* POSIX API only */ 145 /* POSIX API only */
143 #define CreateHardLink(neu,old) 0 146 #define CreateHardLink(neu,old,flags) 0
144 #define CreateSymbolicLink(neu,old,flags) 0 147 #define CreateSymbolicLink(neu,old,flags) 0
145 148
146 struct statvfs 149 struct statvfs
147 { 150 {
148 int dummy; 151 int dummy;
149 }; 152 };
153
154 #define DT_DIR EIO_DT_DIR
155 #define DT_REG EIO_DT_REG
156 #define D_NAME(entp) entp.cFileName
157 #define D_TYPE(entp) (entp.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? DT_DIR : DT_REG)
150 158
151#else 159#else
152 160
153 #include <sys/time.h> 161 #include <sys/time.h>
154 #include <sys/select.h> 162 #include <sys/select.h>
159 #include <dirent.h> 167 #include <dirent.h>
160 168
161 #if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES 169 #if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES
162 #include <sys/mman.h> 170 #include <sys/mman.h>
163 #endif 171 #endif
172
173 #define D_NAME(entp) entp->d_name
164 174
165 /* POSIX_SOURCE is useless on bsd's, and XOPEN_SOURCE is unreliable there, too */ 175 /* POSIX_SOURCE is useless on bsd's, and XOPEN_SOURCE is unreliable there, too */
166 #if __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ 176 #if __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
167 #define _DIRENT_HAVE_D_TYPE /* sigh */ 177 #define _DIRENT_HAVE_D_TYPE /* sigh */
168 #define D_INO(de) (de)->d_fileno 178 #define D_INO(de) (de)->d_fileno
206#endif 216#endif
207#ifndef D_INO 217#ifndef D_INO
208# define D_INO(de) 0 218# define D_INO(de) 0
209#endif 219#endif
210#ifndef D_NAMLEN 220#ifndef D_NAMLEN
211# define D_NAMLEN(de) strlen ((de)->d_name) 221# define D_NAMLEN(entp) strlen (D_NAME (entp))
212#endif 222#endif
213 223
214/* used for struct dirent, AIX doesn't provide it */ 224/* used for struct dirent, AIX doesn't provide it */
215#ifndef NAME_MAX 225#ifndef NAME_MAX
216# define NAME_MAX 4096 226# define NAME_MAX 4096
250#define ETP_WORKER_CLEAR(req) \ 260#define ETP_WORKER_CLEAR(req) \
251 if (wrk->dbuf) \ 261 if (wrk->dbuf) \
252 { \ 262 { \
253 free (wrk->dbuf); \ 263 free (wrk->dbuf); \
254 wrk->dbuf = 0; \ 264 wrk->dbuf = 0; \
255 } \
256 \
257 if (wrk->dirp) \
258 { \
259 closedir (wrk->dirp); \
260 wrk->dirp = 0; \
261 } 265 }
262 266
263#define ETP_WORKER_COMMON \ 267#define ETP_WORKER_COMMON \
264 void *dbuf; \ 268 void *dbuf;
265 DIR *dirp;
266 269
267/*****************************************************************************/ 270/*****************************************************************************/
268 271
269#define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1) 272#define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1)
270 273
396} etp_reqq; 399} etp_reqq;
397 400
398static etp_reqq req_queue; 401static etp_reqq req_queue;
399static etp_reqq res_queue; 402static etp_reqq res_queue;
400 403
404static void ecb_noinline ecb_cold
405reqq_init (etp_reqq *q)
406{
407 int pri;
408
409 for (pri = 0; pri < ETP_NUM_PRI; ++pri)
410 q->qs[pri] = q->qe[pri] = 0;
411
412 q->size = 0;
413}
414
401static int ecb_noinline 415static int ecb_noinline
402reqq_push (etp_reqq *q, ETP_REQ *req) 416reqq_push (etp_reqq *q, ETP_REQ *req)
403{ 417{
404 int pri = req->pri; 418 int pri = req->pri;
405 req->next = 0; 419 req->next = 0;
452 X_MUTEX_CREATE (reqlock); 466 X_MUTEX_CREATE (reqlock);
453 X_COND_CREATE (reqwait); 467 X_COND_CREATE (reqwait);
454} 468}
455 469
456static void ecb_cold 470static void ecb_cold
457etp_atfork_prepare (void)
458{
459}
460
461static void ecb_cold
462etp_atfork_parent (void)
463{
464}
465
466static void ecb_cold
467etp_atfork_child (void) 471etp_atfork_child (void)
468{ 472{
469 ETP_REQ *prv; 473 reqq_init (&req_queue);
474 reqq_init (&res_queue);
470 475
471 while ((prv = reqq_shift (&req_queue))) 476 wrk_first.next =
472 ETP_DESTROY (prv); 477 wrk_first.prev = &wrk_first;
473
474 while ((prv = reqq_shift (&res_queue)))
475 ETP_DESTROY (prv);
476
477 while (wrk_first.next != &wrk_first)
478 {
479 etp_worker *wrk = wrk_first.next;
480
481 if (wrk->req)
482 ETP_DESTROY (wrk->req);
483
484 etp_worker_clear (wrk);
485 etp_worker_free (wrk);
486 }
487 478
488 started = 0; 479 started = 0;
489 idle = 0; 480 idle = 0;
490 nreqs = 0; 481 nreqs = 0;
491 nready = 0; 482 nready = 0;
496 487
497static void ecb_cold 488static void ecb_cold
498etp_once_init (void) 489etp_once_init (void)
499{ 490{
500 etp_thread_init (); 491 etp_thread_init ();
501 X_THREAD_ATFORK (etp_atfork_prepare, etp_atfork_parent, etp_atfork_child); 492 X_THREAD_ATFORK (0, 0, etp_atfork_child);
502} 493}
503 494
504static int ecb_cold 495static int ecb_cold
505etp_init (void (*want_poll)(void), void (*done_poll)(void)) 496etp_init (void (*want_poll)(void), void (*done_poll)(void))
506{ 497{
1483 1474
1484#define EIO_SORT_CUTOFF 30 /* quite high, but performs well on many filesystems */ 1475#define EIO_SORT_CUTOFF 30 /* quite high, but performs well on many filesystems */
1485#define EIO_SORT_FAST 60 /* when to only use insertion sort */ 1476#define EIO_SORT_FAST 60 /* when to only use insertion sort */
1486 1477
1487static void 1478static void
1488eio_dent_radix_sort (eio_dirent *dents, int size, signed char score_bits, ino_t inode_bits) 1479eio_dent_radix_sort (eio_dirent *dents, int size, signed char score_bits, eio_ino_t inode_bits)
1489{ 1480{
1490 unsigned char bits [9 + sizeof (ino_t) * 8]; 1481 unsigned char bits [9 + sizeof (eio_ino_t) * 8];
1491 unsigned char *bit = bits; 1482 unsigned char *bit = bits;
1492 1483
1493 assert (CHAR_BIT == 8); 1484 assert (CHAR_BIT == 8);
1494 assert (sizeof (eio_dirent) * 8 < 256); 1485 assert (sizeof (eio_dirent) * 8 < 256);
1495 assert (offsetof (eio_dirent, inode)); /* we use bit #0 as sentinel */ 1486 assert (offsetof (eio_dirent, inode)); /* we use bit #0 as sentinel */
1497 1488
1498 if (size <= EIO_SORT_FAST) 1489 if (size <= EIO_SORT_FAST)
1499 return; 1490 return;
1500 1491
1501 /* first prepare an array of bits to test in our radix sort */ 1492 /* first prepare an array of bits to test in our radix sort */
1502 /* try to take endianness into account, as well as differences in ino_t sizes */ 1493 /* try to take endianness into account, as well as differences in eio_ino_t sizes */
1503 /* inode_bits must contain all inodes ORed together */ 1494 /* inode_bits must contain all inodes ORed together */
1504 /* which is used to skip bits that are 0 everywhere, which is very common */ 1495 /* which is used to skip bits that are 0 everywhere, which is very common */
1505 { 1496 {
1506 ino_t endianness; 1497 eio_ino_t endianness;
1507 int i, j; 1498 int i, j;
1508 1499
1509 /* we store the byte offset of byte n into byte n of "endianness" */ 1500 /* we store the byte offset of byte n into byte n of "endianness" */
1510 for (i = 0; i < sizeof (ino_t); ++i) 1501 for (i = 0; i < sizeof (eio_ino_t); ++i)
1511 ((unsigned char *)&endianness)[i] = i; 1502 ((unsigned char *)&endianness)[i] = i;
1512 1503
1513 *bit++ = 0; 1504 *bit++ = 0;
1514 1505
1515 for (i = 0; i < sizeof (ino_t); ++i) 1506 for (i = 0; i < sizeof (eio_ino_t); ++i)
1516 { 1507 {
1517 /* shifting off the byte offsets out of "endianness" */ 1508 /* shifting off the byte offsets out of "endianness" */
1518 int offs = (offsetof (eio_dirent, inode) + (endianness & 0xff)) * 8; 1509 int offs = (offsetof (eio_dirent, inode) + (endianness & 0xff)) * 8;
1519 endianness >>= 8; 1510 endianness >>= 8;
1520 1511
1521 for (j = 0; j < 8; ++j) 1512 for (j = 0; j < 8; ++j)
1522 if (inode_bits & (((ino_t)1) << (i * 8 + j))) 1513 if (inode_bits & (((eio_ino_t)1) << (i * 8 + j)))
1523 *bit++ = offs + j; 1514 *bit++ = offs + j;
1524 } 1515 }
1525 1516
1526 for (j = 0; j < 8; ++j) 1517 for (j = 0; j < 8; ++j)
1527 if (score_bits & (1 << j)) 1518 if (score_bits & (1 << j))
1528 *bit++ = offsetof (eio_dirent, score) * 8 + j; 1519 *bit++ = offsetof (eio_dirent, score) * 8 + j;
1529 } 1520 }
1530 1521
1531 /* now actually do the sorting (a variant of MSD radix sort) */ 1522 /* now actually do the sorting (a variant of MSD radix sort) */
1532 { 1523 {
1533 eio_dirent *base_stk [9 + sizeof (ino_t) * 8], *base; 1524 eio_dirent *base_stk [9 + sizeof (eio_ino_t) * 8], *base;
1534 eio_dirent *end_stk [9 + sizeof (ino_t) * 8], *end; 1525 eio_dirent *end_stk [9 + sizeof (eio_ino_t) * 8], *end;
1535 unsigned char *bit_stk [9 + sizeof (ino_t) * 8]; 1526 unsigned char *bit_stk [9 + sizeof (eio_ino_t) * 8];
1536 int stk_idx = 0; 1527 int stk_idx = 0;
1537 1528
1538 base_stk [stk_idx] = dents; 1529 base_stk [stk_idx] = dents;
1539 end_stk [stk_idx] = dents + size; 1530 end_stk [stk_idx] = dents + size;
1540 bit_stk [stk_idx] = bit - 1; 1531 bit_stk [stk_idx] = bit - 1;
1619 } 1610 }
1620 } 1611 }
1621} 1612}
1622 1613
1623static void 1614static void
1624eio_dent_sort (eio_dirent *dents, int size, signed char score_bits, ino_t inode_bits) 1615eio_dent_sort (eio_dirent *dents, int size, signed char score_bits, eio_ino_t inode_bits)
1625{ 1616{
1626 if (size <= 1) 1617 if (size <= 1)
1627 return; /* our insertion sort relies on size > 0 */ 1618 return; /* our insertion sort relies on size > 0 */
1628 1619
1629 /* first we use a radix sort, but only for dirs >= EIO_SORT_FAST */ 1620 /* first we use a radix sort, but only for dirs >= EIO_SORT_FAST */
1637 1628
1638/* read a full directory */ 1629/* read a full directory */
1639static void 1630static void
1640eio__scandir (eio_req *req, etp_worker *self) 1631eio__scandir (eio_req *req, etp_worker *self)
1641{ 1632{
1642 DIR *dirp;
1643 EIO_STRUCT_DIRENT *entp;
1644 char *name, *names; 1633 char *name, *names;
1645 int namesalloc = 4096; 1634 int namesalloc = 4096 - sizeof (void *) * 4;
1646 int namesoffs = 0; 1635 int namesoffs = 0;
1647 int flags = req->int1; 1636 int flags = req->int1;
1648 eio_dirent *dents = 0; 1637 eio_dirent *dents = 0;
1649 int dentalloc = 128; 1638 int dentalloc = 128;
1650 int dentoffs = 0; 1639 int dentoffs = 0;
1651 ino_t inode_bits = 0; 1640 eio_ino_t inode_bits = 0;
1641#ifdef _WIN32
1642 HANDLE dirp;
1643 WIN32_FIND_DATA entp;
1644#else
1645 DIR *dirp;
1646 EIO_STRUCT_DIRENT *entp;
1647#endif
1652 1648
1653 req->result = -1; 1649 req->result = -1;
1654 1650
1655 if (!(flags & EIO_READDIR_DENTS)) 1651 if (!(flags & EIO_READDIR_DENTS))
1656 flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER); 1652 flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER);
1657 1653
1658 X_LOCK (wrklock); 1654#ifdef _WIN32
1659 /* the corresponding closedir is in ETP_WORKER_CLEAR */ 1655 {
1656 char *path = malloc (MAX_PATH);
1657 _snprintf (path, MAX_PATH, "%s/*", (const char *)req->ptr1);
1658 dirp = FindFirstFile (path, &entp);
1659 free (path);
1660
1661 if (!dirp)
1662 {
1663 switch (GetLastError ())
1664 {
1665 case ERROR_FILE_NOT_FOUND:
1666 req->result = 0;
1667 break;
1668
1669 case ERROR_PATH_NOT_FOUND:
1670 case ERROR_NO_MORE_FILES:
1671 errno = ENOENT;
1672 break;
1673
1674 case ERROR_NOT_ENOUGH_MEMORY:
1675 errno = ENOMEM;
1676 break;
1677
1678 default:
1679 errno = EINVAL;
1680 break;
1681 }
1682
1683 }
1684 }
1685#else
1660 self->dirp = dirp = opendir (req->ptr1); 1686 dirp = opendir (req->ptr1);
1687#endif
1661 1688
1662 if (req->flags & EIO_FLAG_PTR1_FREE) 1689 if (req->flags & EIO_FLAG_PTR1_FREE)
1663 free (req->ptr1); 1690 free (req->ptr1);
1664 1691
1665 req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE; 1692 req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE;
1666 req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0; 1693 req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0;
1667 req->ptr2 = names = malloc (namesalloc); 1694 req->ptr2 = names = malloc (namesalloc);
1668 X_UNLOCK (wrklock);
1669 1695
1670 if (dirp && names && (!flags || dents)) 1696 if (dirp && names && (!flags || dents))
1671 for (;;) 1697 for (;;)
1672 { 1698 {
1699 int more;
1700
1701#ifdef _WIN32
1702 more = dirp;
1703#else
1673 errno = 0; 1704 errno = 0;
1674 entp = readdir (dirp); 1705 entp = readdir (dirp);
1706 more = entp;
1707#endif
1675 1708
1676 if (!entp) 1709 if (!more)
1677 { 1710 {
1711#ifndef _WIN32
1712 int old_errno = errno;
1713 closedir (dirp);
1714 errno = old_errno;
1715
1678 if (errno) 1716 if (errno)
1679 break; 1717 break;
1718#endif
1680 1719
1681 /* sort etc. */ 1720 /* sort etc. */
1682 req->int1 = flags; 1721 req->int1 = flags;
1683 req->result = dentoffs; 1722 req->result = dentoffs;
1684 1723
1713 1752
1714 break; 1753 break;
1715 } 1754 }
1716 1755
1717 /* now add the entry to our list(s) */ 1756 /* now add the entry to our list(s) */
1718 name = entp->d_name; 1757 name = D_NAME (entp);
1719 1758
1720 /* skip . and .. entries */ 1759 /* skip . and .. entries */
1721 if (name [0] != '.' || (name [1] && (name [1] != '.' || name [2]))) 1760 if (name [0] != '.' || (name [1] && (name [1] != '.' || name [2])))
1722 { 1761 {
1723 int len = D_NAMLEN (entp) + 1; 1762 int len = D_NAMLEN (entp) + 1;
1724 1763
1725 while (ecb_expect_false (namesoffs + len > namesalloc)) 1764 while (ecb_expect_false (namesoffs + len > namesalloc))
1726 { 1765 {
1727 namesalloc *= 2; 1766 namesalloc *= 2;
1728 X_LOCK (wrklock);
1729 req->ptr2 = names = realloc (names, namesalloc); 1767 req->ptr2 = names = realloc (names, namesalloc);
1730 X_UNLOCK (wrklock);
1731 1768
1732 if (!names) 1769 if (!names)
1733 break; 1770 break;
1734 } 1771 }
1735 1772
1740 struct eio_dirent *ent; 1777 struct eio_dirent *ent;
1741 1778
1742 if (ecb_expect_false (dentoffs == dentalloc)) 1779 if (ecb_expect_false (dentoffs == dentalloc))
1743 { 1780 {
1744 dentalloc *= 2; 1781 dentalloc *= 2;
1745 X_LOCK (wrklock);
1746 req->ptr1 = dents = realloc (dents, dentalloc * sizeof (eio_dirent)); 1782 req->ptr1 = dents = realloc (dents, dentalloc * sizeof (eio_dirent));
1747 X_UNLOCK (wrklock);
1748 1783
1749 if (!dents) 1784 if (!dents)
1750 break; 1785 break;
1751 } 1786 }
1752 1787
1832 if (EIO_CANCELLED (req)) 1867 if (EIO_CANCELLED (req))
1833 { 1868 {
1834 errno = ECANCELED; 1869 errno = ECANCELED;
1835 break; 1870 break;
1836 } 1871 }
1872
1873#ifdef _WIN32
1874 if (!FindNextFile (dirp, &entp))
1875 {
1876 FindClose (dirp);
1877 dirp = 0;
1878 }
1879#endif
1837 } 1880 }
1838} 1881}
1839 1882
1840/*****************************************************************************/ 1883/*****************************************************************************/
1841 1884
1857X_THREAD_PROC (etp_proc) 1900X_THREAD_PROC (etp_proc)
1858{ 1901{
1859 ETP_REQ *req; 1902 ETP_REQ *req;
1860 struct timespec ts; 1903 struct timespec ts;
1861 etp_worker *self = (etp_worker *)thr_arg; 1904 etp_worker *self = (etp_worker *)thr_arg;
1862 int timeout;
1863 1905
1864 /* try to distribute timeouts somewhat evenly */ 1906 /* try to distribute timeouts somewhat evenly */
1865 ts.tv_nsec = ((unsigned long)self & 1023UL) * (1000000000UL / 1024UL); 1907 ts.tv_nsec = ((unsigned long)self & 1023UL) * (1000000000UL / 1024UL);
1866 1908
1867 for (;;) 1909 for (;;)

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines