32#include <sys/socket.h>
34#define BEGIN_NAMESPACE_ROOFIT namespace RooFit {
35#define END_NAMESPACE_ROOFIT }
56 int (*
f)(
int,
char*, std::size_t))
57 {
return f(err, buf, sz); }
60 char* (*
f)(
int,
char*, std::size_t));
65 virtual const char*
what() const noexcept {
return m_buf; }
70 std::size_t msgsz = std::strlen(msg);
72 msgsz = std::min(msgsz, std::size_t(
s_sz));
73 std::copy(msg, msg + msgsz,
m_buf);
74 if (msgsz <
s_sz) {
m_buf[msgsz] =
':'; ++msgsz; }
75 if (msgsz <
s_sz) {
m_buf[msgsz] =
' '; ++msgsz; }
86 std::size_t sz,
char* (*
f)(
int,
char*, std::size_t))
89 char *tmp =
f(err, buf, sz);
90 if (tmp && tmp != buf) {
91 std::strncpy(buf, tmp, sz);
93 if (std::strlen(tmp) > sz - 1)
return ERANGE;
125 assert(std::numeric_limits<unsigned short>::max() >=
142 {
return reinterpret_cast<unsigned char*
>(
const_cast<Page*
>(
this))
145 inline unsigned char*
end()
const
146 {
return reinterpret_cast<unsigned char*
>(
const_cast<Page*
>(
this))
168 const char* p1 =
reinterpret_cast<char*
>(
this);
169 const char* p2 =
reinterpret_cast<const char*
>(p);
170 std::ptrdiff_t tmp = p2 - p1;
185 char* ptmp =
reinterpret_cast<char*
>(
const_cast<Page*
>(
this));
187 return reinterpret_cast<Page*
>(ptmp);
292 m_pimpl(other.m_pimpl)
297 if (&other ==
this)
return *
this;
311 assert(pgno < m_pimpl->m_npages);
312 unsigned char* pptr =
315 return reinterpret_cast<Page*
>(pptr);
320 const unsigned char* pptr =
321 reinterpret_cast<const unsigned char*
>(p);
322 const unsigned char* bptr =
324 assert(0 == ((pptr - bptr) %
pagesize()));
325 const unsigned nr = (pptr - bptr) /
pagesize();
326 assert(nr < m_pimpl->m_npages);
333 long pgsz = sysconf(_SC_PAGESIZE);
334 if (-1 == pgsz)
throw Exception(
"sysconf", errno);
335 if (pgsz > 512 && pgsz >
long(
sizeof(
Page)))
345 unsigned length,
unsigned nPgPerGroup) :
346 m_begin(dommap(length)),
347 m_end(reinterpret_cast<
void*>(
348 reinterpret_cast<unsigned char*>(m_begin) + length)),
349 m_parent(parent), m_nPgPerGrp(nPgPerGroup), m_nUsedGrp(0)
352 unsigned char* p =
reinterpret_cast<unsigned char*
>(
m_begin);
353 unsigned char* pend =
reinterpret_cast<unsigned char*
>(
m_end);
355 m_freelist.push_back(
reinterpret_cast<void*
>(p));
382 m_freelist.push_front(
reinterpret_cast<void*
>(p[0u]));
406 static bool msgprinted =
false;
408#if defined(MAP_ANONYMOUS)
410#define MYANONFLAG MAP_ANONYMOUS
411#elif defined(MAP_ANON)
413#define MYANONFLAG MAP_ANON
418 void* retVal = ::mmap(0,
len, PROT_READ | PROT_WRITE,
419 MYANONFLAG | MAP_SHARED, -1, 0);
420 if (MAP_FAILED == retVal) {
426 std::cerr <<
" INFO: In " << __func__ <<
" (" <<
427 __FILE__ <<
", line " << __LINE__ <<
428 "): anonymous mmapping works, excellent!" <<
440 int fd = ::open(
"/dev/zero", O_RDWR);
442 throw Exception(
"open /dev/zero", errno);
443 void* retVal = ::mmap(0,
len,
444 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
445 if (MAP_FAILED == retVal) {
453 if (-1 == ::close(fd))
454 throw Exception(
"close /dev/zero", errno);
456 std::cerr <<
" INFO: In " << __func__ <<
" (" << __FILE__ <<
457 ", line " << __LINE__ <<
"): mmapping /dev/zero works, "
458 "very good!" << std::endl;
467 if (-1 == (fd = ::mkstemp(
const_cast<char*
>(
name.c_str()))))
throw Exception(
"mkstemp", errno);
469 if (-1 == ::unlink(
name.c_str())) {
475 if (-1 == ::lseek(fd,
len - 1, SEEK_SET)) {
481 if (1 != ::write(fd,
name.c_str(), 1)) {
487 void* retVal = ::mmap(0,
len,
488 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
489 if (MAP_FAILED == retVal) {
497 if (-1 == ::close(fd)) {
499 ::munmap(retVal,
len);
503 std::cerr <<
" INFO: In " << __func__ <<
" (" << __FILE__ <<
504 ", line " << __LINE__ <<
"): mmapping temporary files "
505 "works, good!" << std::endl;
516 std::cerr <<
"WARNING: In " << __func__ <<
" (" << __FILE__ <<
517 ", line " << __LINE__ <<
"): anonymous mmapping of "
518 "shared buffers failed, falling back to read/write on "
519 " pipes!" << std::endl;
523 void* retVal = std::malloc(
len);
524 if (!retVal)
throw Exception(
"malloc", errno);
538 if (-1 == ::munmap(addr,
len))
560 unsigned char* p0 =
reinterpret_cast<unsigned char*
>(
m_begin);
561 unsigned char* p1 =
reinterpret_cast<unsigned char*
>(p[0u]);
563 unsigned char* p3 =
reinterpret_cast<unsigned char*
>(
m_end);
564 if (p1 != p0) ::mprotect(p0, p1 - p0, PROT_NONE);
565 if (p2 != p3) ::mprotect(p2, p3 - p2, PROT_NONE);
577 m_cursz(minsz), m_nPgPerGrp(nPgPerGroup)
582 const unsigned mult =
586 const unsigned actual = mult *
587 (desired / mult +
bool(desired % mult));
590 std::cerr <<
" INFO: In " << __func__ <<
" (" <<
591 __FILE__ <<
", line " << __LINE__ <<
593 ", subdividing into logical pages of size " <<
616 for (ChunkList::iterator it =
m_chunks.begin();
m_chunks.end() != it; ++it) {
617 if ((*it)->contains(p)) {
649 assert(chunk->
empty());
651 ChunkList::iterator it = std::find(
654 throw Exception(
"PagePool::release(PageChunk*)", EINVAL);
659 throw Exception(
"PagePool::release(PageChunk*)", EINVAL);
668 assert(!chunk->
full());
740 m_pages(pagepool().
pop())
751 m_pages(pagepool().
pop()), m_busylist(0),
m_freelist(0), m_dirtylist(0),
752 m_inpipe(-1), m_outpipe(-1), m_flags(failbit), m_childPid(0),
753 m_parentPid(::getpid())
758 int fds[4] = { -1, -1, -1, -1 };
760 static bool firstcall =
true;
773 for (
unsigned i = 1; i <
TotPages; ++i)
776 if (!useSocketpair) {
778 if (0 != ::pipe(&fds[0]))
throw Exception(
"pipe", errno);
779 if (0 != ::pipe(&fds[2]))
throw Exception(
"pipe", errno);
781 if (0 != ::socketpair(AF_UNIX, SOCK_STREAM, 0, &fds[0]))
802 fds[0] = fds[3] = -1;
817 for (std::list<BidirMMapPipe*>::iterator it =
s_openpipes.begin();
834 throw Exception(
"handshake: xferraw write", EPIPE);
836 throw Exception(
"handshake: xferraw read", EPIPE);
837 if (
'P' !=
c)
throw Exception(
"handshake", EPIPE);
848 fds[1] = fds[2] = -1;
870 throw Exception(
"handshake: xferraw write", EPIPE);
872 throw Exception(
"handshake: xferraw read", EPIPE);
873 if (
'C' !=
c)
throw Exception(
"handshake", EPIPE);
879 if (-1 == ::fcntl(
m_outpipe, F_GETFD, &fdflags))
881 fdflags |= FD_CLOEXEC;
882 if (-1 == ::fcntl(
m_outpipe, F_SETFD, fdflags))
885 if (-1 == ::fcntl(
m_inpipe, F_GETFD, &fdflags))
887 fdflags |= FD_CLOEXEC;
888 if (-1 == ::fcntl(
m_inpipe, F_SETFD, fdflags))
896 for (
int i = 0; i < 4; ++i)
897 if (-1 != fds[i] && 0 != fds[i])
::close(fds[i]);
928 if (!force)
throw Exception(
"close", errno);
950 while ((err =
::poll(&fds, 1, 1 << 20)) >= 0) {
951 if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))
break;
952 if (fds.revents & POLLIN) {
957 }
while (0 > err && EINTR == errno);
962 if (!force)
throw Exception(
"close", errno);
971 }
catch (std::exception&) {
981 }
while (-1 == tmp && EINTR == errno);
983 if (!force)
throw Exception(
"waitpid", errno);
988 std::list<BidirMMapPipe*>::iterator it = std::find(
1001 ssize_t (*xferfn)(
int,
void*, std::size_t))
1004 unsigned char* buf =
reinterpret_cast<unsigned char*
>(addr);
1006 ssize_t tmp = xferfn(fd, buf, len);
1012 }
else if (0 == tmp) {
1015 }
else if (-1 == tmp) {
1022 if (xferred)
return xferred;
1026#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
1029 std::cerr <<
" ERROR: In " << __func__ <<
" (" <<
1030 __FILE__ <<
", line " << __LINE__ <<
1031 "): expect transfer to block!" << std::endl;
1037 throw Exception(
"xferraw: unexpected return value from read/write",
1047 unsigned char pg =
m_pages[plist];
1052 for (
Page* p = plist; p; p = p->
next()) {
1053 if (
sizeof(
Page) + p->size() !=
1056 throw Exception(
"sendpages: short write", EPIPE);
1061 throw Exception(
"sendpages: short write", EPIPE);
1063 }
else { assert(plist); }
1069 unsigned retVal = 0;
1070 Page *plisthead = 0, *plisttail = 0;
1072 plisthead = plisttail =
m_pages[pg];
1077 for (; plisttail; ++retVal) {
1078 Page* p = plisttail;
1081 plisttail = p->
next();
1082 if (!p->
size())
continue;
1103 fds.events = POLLIN;
1105 unsigned retVal = 0;
1107 int rc =
::poll(&fds, 1, 0);
1109 if (EINTR == errno)
continue;
1112 if (1 == retVal && fds.revents & POLLIN &&
1113 !(fds.revents & (POLLNVAL | POLLERR))) {
1127 for ( ; p; p = p->
next()) ++
n;
1136 while (blend && blend->
next()) blend = blend->
next();
1140 Page *sendlisthead = 0, *sendlisttail = 0;
1161 if (!sendlisthead) sendlisthead = p;
1162 if (sendlisttail) sendlisttail->
setNext(p);
1182 sendlisttail->setNext(p);
1190 struct pollfd fds[2];
1192 fds[0].events = fds[0].revents = 0;
1195 fds[1].events = fds[1].revents = 0;
1197 fds[0].events |= POLLIN;
1201 retVal =
::poll(fds, nfds, 0);
1202 if (0 > retVal && EINTR == errno)
1207 bool ok = !(fds[0].revents & (POLLERR | POLLNVAL | POLLHUP));
1209 ok = ok && !(fds[1].revents & (POLLERR | POLLNVAL | POLLHUP));
1211 if (ok && fds[0].revents & POLLIN) {
1213 if (!ret) ok =
false;
1222 throw Exception(
"feedPageLists: poll", errno);
1236 while (dl && dl->
next()) dl = dl->
next();
1258 if (p)
while (p->
next()) p = p->
next();
1259 if (!p || p->
full()) {
1274 Page *flushlisthead = 0, *flushlisttail = 0;
1277 if (!forcePartialPages && !p->
full())
break;
1282 if (!flushlisthead) flushlisthead = p;
1283 if (flushlisttail) flushlisttail->
setNext(p);
1286 if (flushlisthead)
sendpages(flushlisthead);
1295 while (
l &&
l->next())
l =
l->
next();
1313 retVal += p->size() - p->pos();
1324 bool couldwrite =
false;
1328 fds.events = POLLOUT;
1332 retVal =
::poll(&fds, 1, 0);
1334 if (EINTR == errno)
continue;
1335 throw Exception(
"bytesWritableNonBlocking: poll", errno);
1337 if (1 == retVal && fds.revents & POLLOUT &&
1338 !(fds.revents & (POLLNVAL | POLLERR | POLLHUP)))
1345 unsigned npages = 0;
1351 retVal += p->free();
1367 unsigned char *ap =
reinterpret_cast<unsigned char*
>(addr);
1376 unsigned char* pp = p->
begin() + p->
pos();
1378 std::copy(pp, pp + csz, ap);
1383 assert(p->
size() >= p->
pos());
1403 const unsigned char *ap =
reinterpret_cast<const unsigned char*
>(addr);
1412 unsigned char* pp = p->
begin() + p->
size();
1414 std::copy(ap, ap + csz, pp);
1439 bool canskiptimeout =
false;
1441 std::vector<unsigned>::iterator mit =
masks.begin();
1442 for (PollVector::iterator it = pipes.begin(); pipes.end() != it;
1449 canskiptimeout =
true;
1470 while (dl && dl->
next()) dl = dl->
next();
1475 if (pe.
revents) canskiptimeout =
true;
1478 std::vector<pollfd> fds;
1479 fds.reserve(2 * pipes.size());
1480 std::map<int, PollEntry*> fds2pipes;
1481 for (PollVector::const_iterator it = pipes.begin();
1482 pipes.end() != it; ++it) {
1485 fds2pipes.insert(std::make_pair((tmp.fd = pe.
pipe->
m_inpipe),
1487 tmp.
events = tmp.revents = 0;
1490 tmp.events |= POLLIN;
1494 fds2pipes.insert(std::make_pair(
1506 retVal =
::poll(&fds[0], fds.size(), canskiptimeout ? 0 : timeout);
1508 if (EINTR == errno)
continue;
1514 for (std::vector<pollfd>::iterator it = fds.begin();
1515 fds.end() != it; ++it) {
1521 if (fe.revents & POLLNVAL && fe.fd == pe.
pipe->
m_inpipe)
1525 if (fe.revents & POLLERR && fe.fd == pe.
pipe->
m_inpipe)
1529 if (fe.revents & POLLHUP && fe.fd == pe.
pipe->
m_inpipe)
1533 if ((fe.revents & POLLIN) && fe.fd == pe.
pipe->
m_inpipe &&
1534 !(fe.revents & (POLLNVAL | POLLERR))) {
1540 int tmp =
::poll(&fe, 1, 0);
1541 if (tmp > 0)
goto oncemore;
1543 if (EINTR == errno)
continue;
1555 while (dl && dl->
next()) dl = dl->
next();
1563 mit =
masks.begin();
1564 for (PollVector::iterator it = pipes.begin();
1565 pipes.end() != it; ++it, ++mit)
1566 if ((it->revents &= *mit)) ++npipes;
1572 size_t sz = std::strlen(str);
1574 if (sz)
write(str, sz);
1583 str =
reinterpret_cast<char*
>(std::realloc(str, sz + 1));
1584 if (!str)
throw Exception(
"realloc", errno);
1585 if (sz)
read(str, sz);
1593 size_t sz = str.size();
1595 write(str.data(), sz);
1606 for (
unsigned char c; sz--; str.push_back(
c)) *
this >>
c;
1613#ifdef TEST_BIDIRMMAPPIPE
1619 while (pipe.
good() && !pipe.
eof()) {
1623 if (!pipe)
return -1;
1624 if (pipe.
eof())
break;
1626 std::cout <<
"[CHILD] : read: " << str << std::endl;
1627 str =
"... early in the morning?";
1631 if (str.empty())
break;
1632 if (!pipe)
return -1;
1633 if (pipe.
eof())
break;
1634 std::cout <<
"[CHILD] : wrote: " << str << std::endl;
1644 ::srand48(::getpid());
1652 for (
int i = 0; i < 5; ++i) {
1654 ::usleep(
int(1e6 * ::drand48()));
1655 std::ostringstream buf;
1656 buf <<
"child pid " << ::getpid() <<
" sends message " << i;
1657 std::string str = buf.str();
1658 std::cout <<
"[CHILD] : " << str << std::endl;
1660 if (!pipe)
return -1;
1661 if (pipe.
eof())
break;
1677 while (pipe && !pipe.
eof()) {
1684 if (pipe.
eof())
break;
1687 if (!std::strlen(str))
break;
1698 while (pipe && !pipe.
eof()) {
1700 if (!std::strlen(str))
break;
1712 for (
unsigned i = 0; i <= 24; ++i) {
1713 str =
reinterpret_cast<char*
>(std::realloc(str, (1 << i) + 1));
1714 std::memset(str,
'4', 1 << i);
1716 for (
unsigned j = 0; j < 1 << 7; ++j) {
1718 if (!pipe || pipe.
eof()) {
1739 int retVal = childexec(*p);
1746#include <sys/time.h>
1752 std::cout <<
"[PARENT]: simple challenge-response test, "
1753 "one child:" << std::endl;
1755 for (
int i = 0; i < 5; ++i) {
1756 std::string str(
"What shall we do with a drunken sailor...");
1758 if (!*pipe)
return -1;
1759 std::cout <<
"[PARENT]: wrote: " << str << std::endl;
1761 if (!*pipe)
return -1;
1762 std::cout <<
"[PARENT]: read: " << str << std::endl;
1769 int retVal = pipe->
close();
1770 std::cout <<
"[PARENT]: exit status of child: " << retVal <<
1772 if (retVal)
return retVal;
1778 std::cout << std::endl <<
"[PARENT]: polling test, " << nch <<
1779 " children:" << std::endl;
1785 for (
unsigned i = 0; i < nch; ++i) {
1786 std::cout <<
"[PARENT]: spawning child " << i << std::endl;
1787 pipes.push_back(PollEntry(spawnChild(randomchild),
1791 std::cout <<
"[PARENT]: waking up children" << std::endl;
1792 for (
unsigned i = 0; i < nch; ++i)
1794 std::cout <<
"[PARENT]: waiting for events on children's pipes" << std::endl;
1796 while (!pipes.empty()) {
1800 for (std::vector<PollEntry>::iterator it = pipes.begin();
1801 npipes && pipes.end() != it; ) {
1813 std::cout <<
"[PARENT]: Read from pipe " << it->pipe <<
1814 ": " << s << std::endl;
1827 std::cerr <<
"[DEBUG]: Event on pipe " << it->pipe <<
1830 ((it->revents &
BidirMMapPipe::Writable) ?
" Writable" :
"") <<
1831 ((it->revents &
BidirMMapPipe::ReadError) ?
" ReadError" :
"") <<
1832 ((it->revents &
BidirMMapPipe::WriteError) ?
" WriteError" :
"") <<
1833 ((it->revents &
BidirMMapPipe::ReadEndOfFile) ?
" ReadEndOfFile" :
"") <<
1834 ((it->revents &
BidirMMapPipe::WriteEndOfFile) ?
" WriteEndOfFile" :
"") <<
1835 ((it->revents &
BidirMMapPipe::ReadInvalid) ?
" ReadInvalid" :
"") <<
1836 ((it->revents &
BidirMMapPipe::WriteInvalid) ?
" WriteInvalid" :
"") <<
1839 int retVal = it->pipe->close();
1840 std::cout <<
"[PARENT]: child exit status: " <<
1841 retVal <<
", number of children still alive: " <<
1842 (pipes.size() - 1) << std::endl;
1843 if (retVal)
return retVal;
1845 it = pipes.erase(it);
1853 std::cout << std::endl <<
"[PARENT]: benchmark: round-trip times vs block size" << std::endl;
1854 for (
unsigned i = 0; i <= 24; ++i) {
1855 char *s =
new char[1 + (1 << i)];
1856 std::memset(s,
'A', 1 << i);
1858 const unsigned n = 1 << 7;
1859 double avg = 0., min = 1e42, max = -1e42;
1861 for (
unsigned j =
n; j--; ) {
1863 ::gettimeofday(&
t1, 0);
1865 if (!*pipe || pipe->
eof())
break;
1867 if (!*pipe || pipe->
eof())
break;
1869 ::gettimeofday(&t2, 0);
1870 t2.tv_sec -=
t1.tv_sec;
1871 t2.tv_usec -=
t1.tv_usec;
1873 if (dt < min) min = dt;
1874 if (dt > max) max = dt;
1882 avg *= 1e6; min *= 1e6; max *= 1e6;
1883 int retVal = pipe->
close();
1885 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1893 std::cout <<
"block size " << std::setw(9) << (1 << i) <<
1894 " avg " << std::setw(7) << avg <<
" us min " <<
1895 std::setw(7) << min <<
" us max " << std::setw(7) << max <<
1896 "us speed " << std::setw(9) <<
1898 " MB/s" << std::endl;
1901 std::cout <<
"[PARENT]: all children had exit code 0" << std::endl;
1905 std::cout << std::endl <<
"[PARENT]: benchmark: raw transfer rate with child as sink" << std::endl;
1906 for (
unsigned i = 0; i <= 24; ++i) {
1907 char *s =
new char[1 + (1 << i)];
1908 std::memset(s,
'A', 1 << i);
1910 const unsigned n = 1 << 7;
1911 double avg = 0., min = 1e42, max = -1e42;
1913 for (
unsigned j =
n; j--; ) {
1915 ::gettimeofday(&
t1, 0);
1918 if (!*pipe || pipe->
eof())
break;
1920 ::gettimeofday(&t2, 0);
1921 t2.tv_sec -=
t1.tv_sec;
1922 t2.tv_usec -=
t1.tv_usec;
1924 if (dt < min) min = dt;
1925 if (dt > max) max = dt;
1933 avg *= 1e6; min *= 1e6; max *= 1e6;
1934 int retVal = pipe->
close();
1936 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1940 std::cout <<
"block size " << std::setw(9) << (1 << i) <<
1941 " avg " << std::setw(7) << avg <<
" us min " <<
1942 std::setw(7) << min <<
" us max " << std::setw(7) << max <<
1943 "us speed " << std::setw(9) <<
1945 " MB/s" << std::endl;
1948 std::cout <<
"[PARENT]: all children had exit code 0" << std::endl;
1952 std::cout << std::endl <<
"[PARENT]: benchmark: raw transfer rate with child as source" << std::endl;
1954 double avg = 0., min = 1e42, max = -1e42;
1955 unsigned n = 0, bsz = 0;
1957 while (*pipe && !pipe->
eof()) {
1959 ::gettimeofday(&
t1, 0);
1962 if (!*pipe || pipe->
eof())
break;
1964 ::gettimeofday(&t2, 0);
1965 t2.tv_sec -=
t1.tv_sec;
1966 t2.tv_usec -=
t1.tv_usec;
1968 if (std::strlen(s)) {
1970 if (dt < min) min = dt;
1971 if (dt > max) max = dt;
1973 bsz = std::strlen(s);
1978 avg *= 1e6; min *= 1e6; max *= 1e6;
1980 std::cout <<
"block size " << std::setw(9) << bsz <<
1981 " avg " << std::setw(7) << avg <<
" us min " <<
1982 std::setw(7) << min <<
" us max " << std::setw(7) <<
1983 max <<
"us speed " << std::setw(9) <<
1985 " MB/s" << std::endl;
1992 int retVal = pipe->
close();
1993 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1994 if (retVal)
return retVal;
#define END_NAMESPACE_ROOFIT
#define BEGIN_NAMESPACE_ROOFIT
header file for BidirMMapPipe, a class which forks off a child process and serves as communications c...
typedef void(GLAPIENTRYP _GLUfuncptr)(void)
unsigned revents
events that happened (or'ed bitmask)
BidirMMapPipe * pipe
pipe of interest
unsigned events
events of interest (or'ed bitmask)
exception to throw if low-level OS calls go wrong
char m_buf[s_sz]
buffer containing the error message
static int dostrerror_r(int err, char *buf, std::size_t sz, int(*f)(int, char *, std::size_t))
for the POSIX version of strerror_r
virtual const char * what() const noexcept
return a destcription of what went wrong
BidirMMapPipeException(const char *msg, int err)
constructor taking error code, hint on operation (msg)
class representing a chunk of pages
PageChunk(const PageChunk &)
forbid copying
BidirMMapPipeException Exception
convenience typedef
unsigned m_nUsedGrp
number of used page groups
unsigned len() const
return length of chunk
void * m_begin
pointer to start of mmapped area
static unsigned physPgSz()
return the physical page size of the system
static unsigned s_physpgsz
system physical page size
bool full() const
return true if no free page groups in this chunk
void * m_end
pointer one behind end of mmapped area
void push(const Pages &p)
push a group of pages onto the free list
bool contains(const Pages &p) const
return if p is contained in this PageChunk
PagePool * m_parent
parent page pool
std::list< void * > m_freelist
free pages list
static MMapVariety s_mmapworks
mmap variety that works on this system
MMapVariety
type of mmap support found
@ Copy
mmap doesn't work, have to copy back and forth
@ Unknown
don't know yet what'll work
@ DevZero
mmapping /dev/zero works
@ Anonymous
anonymous mmap works
@ FileBacked
mmapping a temp file works
static void domunmap(void *p, unsigned len)
munmap pages p, len is length of mmapped area in bytes
static unsigned s_pagesize
logical page size (run-time determined)
unsigned m_nPgPerGrp
number of pages per group
static MMapVariety mmapVariety()
return mmap variety support found
Pages pop()
pop a group of pages off the free list
static unsigned pagesize()
return the logical page size
static void * dommap(unsigned len)
mmap pages, len is length of mmapped area in bytes
bool empty() const
return true if no used page groups in this chunk
void zap(Pages &p)
free all pages except for those pointed to by p
static unsigned getPageSize()
determine page size at run time
class representing a page pool
Pages pop()
pop a free element out of the pool
static MMapVariety mmapVariety()
return variety of mmap supported on the system
BidirMMapPipeException Exception
convenience typedef
unsigned nPagesPerGroup() const
return number of pages per group (ie. as returned by pop())
void zap(Pages &p)
zap the pool (unmap all but Pages p)
PageChunk::MMapVariety MMapVariety
convenience typedef
void putOnFreeList(Chunk *chunk)
release a chunk
BidirMMapPipe_impl::PageChunk Chunk
a chunk of memory in the pool
@ minsz
minimum chunk size (just below 1 << minsz bytes)
@ szincr
size class increment (sz = 1 << (minsz + k * szincr))
@ maxsz
maximum chunk size (just below 1 << maxsz bytes)
ChunkList m_freelist
list of chunks used by the pool which are not full
ChunkList m_chunks
list of chunks used by the pool
unsigned m_nPgPerGrp
page group size
std::list< Chunk * > ChunkList
list of chunks
static unsigned pagesize()
return (logical) page size of the system
int m_cursz
current chunk size
unsigned m_szmap[(maxsz - minsz)/szincr]
chunk size map (histogram of chunk sizes)
int nextChunkSz() const
find size of next chunk to allocate (in a hopefully smart way)
void updateCurSz(int sz, int incr)
adjust _cursz to current largest block
PagePool(unsigned nPagesPerGroup)
constructor
void release(Chunk *chunk)
release a chunk
class representing the header structure in an mmapped page
bool full() const
true if page completely full
unsigned short m_pos
index of next byte in payload area
unsigned short & pos()
return reference to position field
short m_next
next page in list (in pagesizes)
unsigned char * end() const
return pointer to first byte in payload data area of page
Page & operator=(const Page &)=delete
assigment forbidden
bool filled() const
true if page partially filled
Page(const Page &)
copy construction forbidden
Page * next() const
return pointer to next page
unsigned short & size()
return reference to size field
unsigned short m_size
size of payload (in bytes)
unsigned char * begin() const
return pointer to first byte in payload data area of page
static unsigned capacity()
return the capacity of the page
void setNext(const Page *p)
set pointer to next page
unsigned free() const
free space left (to be written to)
unsigned size() const
return size (of payload data)
unsigned pos() const
return position
unsigned remaining() const
bytes remaining to be read
bool empty() const
true if page empty
handle class for a number of Pages
Pages()
default constructor
static unsigned pagesize()
return page size
impl * m_pimpl
pointer to implementation
Pages & operator=(const Pages &other)
assignment operator
void swap(Pages &other)
swap with other's contents
Page * page(unsigned pgno) const
return page number pageno
unsigned npages() const
return number of pages accessible
unsigned pageno(Page *p) const
perform page to page number mapping
BidirMMapPipe creates a bidirectional channel between the current process and a child it forks.
void purge()
purge buffered data waiting to be read and/or written
static BidirMMapPipe_impl::PagePool * s_pagepool
pool of mmapped pages
void feedPageLists(Page *plist)
"feed" the busy and free lists with a list of pages
static std::list< BidirMMapPipe * > s_openpipes
list of open BidirMMapPipes
int close()
flush buffers, close pipe
BidirMMapPipe_impl::Pages m_pages
mmapped pages
bool good() const
status of stream is good
Page * m_dirtylist
linked list: dirty pages (data to be sent)
unsigned recvpages()
receive a pages from the other end (may block), queue them
BidirMMapPipe & operator>>(char *(&str))
read a C-style string
static pthread_mutex_t s_openpipesmutex
protects s_openpipes
unsigned recvpages_nonblock()
receive pages from other end (non-blocking)
~BidirMMapPipe()
destructor
int m_inpipe
pipe end from which data may be read
bool isChild() const
return if this end of the pipe is the child end
void doFlush(bool forcePartialPages=true)
perform the flush
static void teardownall(void)
cleanup routine - at exit, we want our children to get a SIGTERM...
@ eofbit
end of file reached
@ failbit
logical failure (e.g. pipe closed)
@ exceptionsbit
error reporting with exceptions
size_type bytesWritableNonBlocking()
number of bytes that can be written without blocking
static BidirMMapPipe_impl::PagePool & pagepool()
return page pool
bool eof() const
true if end-of-file
size_type bytesReadableNonBlocking()
number of bytes that can be read without blocking
static int debugflag()
return the current setting of the debug flag
bool isParent() const
return if this end of the pipe is the parent end
std::size_t size_type
type used to represent sizes
int doClose(bool force, bool holdlock=false)
close the pipe (no flush if forced)
@ PagesPerEnd
pages per pipe end
@ TotPages
pages shared (child + parent)
@ FlushThresh
flush threshold
bool bad() const
true on I/O error
@ WriteInvalid
write end of pipe invalid
@ ReadEndOfFile
read pipe in end-of-file state
@ WriteError
pipe error Write end
@ ReadError
pipe error read end
@ Readable
pipe has data for reading
@ None
nothing special on this pipe
@ ReadInvalid
read end of pipe invalid
@ WriteEndOfFile
write pipe in end-of-file state
@ Writable
pipe can be written to
int m_flags
flags (e.g. end of file)
Page * m_freelist
linked list: free pages
Page * busypage()
get a busy page to read data from (may block)
Page * dirtypage()
get a dirty page to write data to (may block)
void sendpages(Page *plist)
send page(s) to the other end (may block)
BidirMMapPipe & operator<<(const char *str)
write a C-style string
static size_type xferraw(int fd, void *addr, size_type len, ssize_t(*xferfn)(int, void *, std::size_t))
transfer bytes through the pipe (reading, writing, may block)
size_type read(void *addr, size_type sz)
read from pipe
static int s_debugflag
debug flag
bool closed() const
true if closed
BidirMMapPipe_impl::BidirMMapPipeException Exception
convenience typedef for BidirMMapPipeException
size_type write(const void *addr, size_type sz)
wirte to pipe
std::vector< PollEntry > PollVector
convenience typedef for poll() interface
void flush()
flush buffers with unwritten data
static unsigned s_pagepoolrefcnt
page pool reference counter
Page * m_busylist
linked list: busy pages (data to be read)
static int poll(PollVector &pipes, int timeout)
poll a set of pipes for events (ready to read from, ready to write to, error)
int m_outpipe
pipe end to which data may be written
void markPageDirty(Page *p)
put on dirty pages list
BidirMMapPipe(bool useExceptions=true, bool useSocketpair=false)
constructor (forks!)
static unsigned lenPageList(const Page *list)
return length of a page list
pid_t m_childPid
pid of the child (zero if we're child)
namespace for implementation details of BidirMMapPipe
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
std::string const & tmpPath()
Returns the path to the directory that should be used for temporary RooFit files (e....
unsigned char m_npages
length in pages
Page * m_pages
pointer to first page
unsigned m_refcnt
reference counter
PageChunk * m_parent
pointer to parent pool
static unsigned long masks[]