32#include <sys/socket.h> 
   34#define BEGIN_NAMESPACE_ROOFIT namespace RooFit { 
   35#define END_NAMESPACE_ROOFIT } 
   40namespace BidirMMapPipe_impl {
 
   56                    int (*
f)(
int, 
char*, std::size_t))
 
   57            { 
return f(err, buf, sz); }
 
   59            static int dostrerror_r(
int, 
char*, std::size_t,
 
   60                    char* (*
f)(
int, 
char*, std::size_t));
 
   65            virtual const char* 
what() const noexcept { 
return m_buf; }
 
   68    BidirMMapPipeException::BidirMMapPipeException(
const char* msg, 
int err)
 
   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; }
 
   80            dostrerror_r(err, &m_buf[msgsz], s_sz - msgsz, ::strerror_r);
 
   85    int BidirMMapPipeException::dostrerror_r(
int err, 
char* buf,
 
   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;
 
  121            Page() : m_next(0), m_size(0), m_pos(0)
 
  125                assert(std::numeric_limits<unsigned short>::max() >=
 
  126                        PageChunk::pagesize());
 
  129            void setNext(
const Page* 
p);
 
  133            unsigned short& 
size() { 
return m_size; }
 
  135            unsigned size()
 const { 
return m_size; }
 
  137            unsigned short& 
pos() { 
return m_pos; }
 
  139            unsigned pos()
 const { 
return m_pos; }
 
  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))
 
  147                + PageChunk::pagesize(); }
 
  150            { 
return PageChunk::pagesize() - 
sizeof(
Page); }
 
  152            bool empty()
 const { 
return !m_size; }
 
  156            unsigned free()
 const { 
return capacity() - m_size; }
 
  168            const char* p1 = 
reinterpret_cast<char*
>(
this);
 
  169            const char* p2 = 
reinterpret_cast<const char*
>(
p);
 
  170            std::ptrdiff_t tmp = p2 - p1;
 
  172            assert(!(tmp % PageChunk::pagesize()));
 
  173            tmp /= 
static_cast<std::ptrdiff_t
>(PageChunk::pagesize());
 
  176            assert(m_next == tmp);
 
  184        if (!m_next) 
return 0;
 
  185        char* ptmp = 
reinterpret_cast<char*
>(
const_cast<Page*
>(
this));
 
  186        ptmp += std::ptrdiff_t(m_next) * PageChunk::pagesize();
 
  187        return reinterpret_cast<Page*
>(ptmp);
 
  234            static unsigned pagesize() { 
return PageChunk::pagesize(); }
 
  237            { 
return PageChunk::mmapVariety(); }
 
  251            unsigned m_szmap[(maxsz - minsz) / szincr];
 
  258            void updateCurSz(
int sz, 
int incr);
 
  260            int nextChunkSz() 
const;
 
  262            void putOnFreeList(
Chunk* chunk);
 
  264            void release(
Chunk* chunk);
 
  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) :
 
  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);
 
  367    { 
return p.m_pimpl->m_parent == 
this; }
 
  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);
 
  570        p.m_pimpl->m_parent = 0;
 
  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());
 
  732        if (
p->m_childPid) kill(
p->m_childPid, SIGTERM);
 
  733        p->doClose(
true, 
true);
 
  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();
 
  821                    p->doClose(
true, 
true);
 
  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());
 
 1384            if (
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);
 
 1419            assert(
p->capacity() >= 
p->size());
 
 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            std::vector<char> s(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;
 
 1892            std::cout << 
"block size " << std::setw(9) << (1 << i) <<
 
 1893                " avg " << std::setw(7) << avg << 
" us min " <<
 
 1894                std::setw(7) << min << 
" us max " << std::setw(7) << max <<
 
 1895                "us speed " << std::setw(9) <<
 
 1897                " MB/s" << std::endl;
 
 1899        std::cout << 
"[PARENT]: all children had exit code 0" << std::endl;
 
 1903        std::cout << std::endl << 
"[PARENT]: benchmark: raw transfer rate with child as sink" << std::endl;
 
 1904        for (
unsigned i = 0; i <= 24; ++i) {
 
 1905            std::vector<char> s(1 + (1 << i));
 
 1906            std::memset(s, 
'A', 1 << i);
 
 1908            const unsigned n = 1 << 7;
 
 1909            double avg = 0., min = 1e42, max = -1e42;
 
 1911            for (
unsigned j = 
n; j--; ) {
 
 1913                ::gettimeofday(&
t1, 0);
 
 1916                if (!*pipe || pipe->
eof()) 
break;
 
 1918                ::gettimeofday(&t2, 0);
 
 1919                t2.tv_sec -= 
t1.tv_sec;
 
 1920                t2.tv_usec -= 
t1.tv_usec;
 
 1922                if (dt < min) min = dt;
 
 1923                if (dt > max) max = dt;
 
 1931            avg *= 1e6; min *= 1e6; max *= 1e6;
 
 1932            int retVal = pipe->
close();
 
 1934                std::cout << 
"[PARENT]: child exited with code " << retVal << std::endl;
 
 1938            std::cout << 
"block size " << std::setw(9) << (1 << i) <<
 
 1939                " avg " << std::setw(7) << avg << 
" us min " <<
 
 1940                std::setw(7) << min << 
" us max " << std::setw(7) << max <<
 
 1941                "us speed " << std::setw(9) <<
 
 1943                " MB/s" << std::endl;
 
 1945        std::cout << 
"[PARENT]: all children had exit code 0" << std::endl;
 
 1949        std::cout << std::endl << 
"[PARENT]: benchmark: raw transfer rate with child as source" << std::endl;
 
 1951        double avg = 0., min = 1e42, max = -1e42;
 
 1952        unsigned n = 0, bsz = 0;
 
 1954        while (*pipe && !pipe->
eof()) {
 
 1956            ::gettimeofday(&
t1, 0);
 
 1959            if (!*pipe || pipe->
eof()) 
break;
 
 1961            ::gettimeofday(&t2, 0);
 
 1962            t2.tv_sec -= 
t1.tv_sec;
 
 1963            t2.tv_usec -= 
t1.tv_usec;
 
 1965            if (std::strlen(s)) {
 
 1967                if (dt < min) min = dt;
 
 1968                if (dt > max) max = dt;
 
 1970                bsz = std::strlen(s);
 
 1975                avg *= 1e6; min *= 1e6; max *= 1e6;
 
 1977                std::cout << 
"block size " << std::setw(9) << bsz <<
 
 1978                    " avg " << std::setw(7) << avg << 
" us min " <<
 
 1979                    std::setw(7) << min << 
" us max " << std::setw(7) <<
 
 1980                    max << 
"us speed " << std::setw(9) <<
 
 1982                    " MB/s" << std::endl;
 
 1989        int retVal = pipe->
close();
 
 1990            std::cout << 
"[PARENT]: child exited with code " << retVal << std::endl;
 
 1991        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...
 
winID h TVirtualViewer3D TVirtualGLPainter p
 
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
 
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
 
unsigned events
events of interest (or'ed bitmask)
 
unsigned revents
events that happened (or'ed bitmask)
 
BidirMMapPipe * pipe
pipe of interest
 
exception to throw if low-level OS calls go wrong
 
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
 
class representing a chunk of pages
 
BidirMMapPipeException Exception
convenience typedef
 
std::list< void * > m_freelist
free pages list
 
void * m_end
pointer one behind end of mmapped area
 
static void domunmap(void *p, unsigned len)
munmap pages p, len is length of mmapped area in bytes
 
void * m_begin
pointer to start of mmapped area
 
void zap(Pages &p)
free all pages except for those pointed to by p
 
MMapVariety
type of mmap support found
 
@ FileBacked
mmapping a temp file works
 
@ Unknown
don't know yet what'll work
 
@ DevZero
mmapping /dev/zero works
 
@ Copy
mmap doesn't work, have to copy back and forth
 
@ Anonymous
anonymous mmap works
 
static unsigned pagesize()
return the logical page size
 
PagePool * m_parent
parent page pool
 
unsigned m_nUsedGrp
number of used page groups
 
static MMapVariety s_mmapworks
mmap variety that works on this system
 
static unsigned s_physpgsz
system physical page size
 
static void * dommap(unsigned len)
mmap pages, len is length of mmapped area in bytes
 
static MMapVariety mmapVariety()
return mmap variety support found
 
unsigned m_nPgPerGrp
number of pages per group
 
static unsigned physPgSz()
return the physical page size of the system
 
static unsigned s_pagesize
logical page size (run-time determined)
 
void push(const Pages &p)
push a group of pages onto the free list
 
Pages pop()
pop a group of pages off the free list
 
unsigned len() const
return length of chunk
 
PageChunk(const PageChunk &)
forbid copying
 
static unsigned getPageSize()
determine page size at run time
 
bool contains(const Pages &p) const
return if p is contained in this PageChunk
 
bool full() const
return true if no free page groups in this chunk
 
bool empty() const
return true if no used page groups in this chunk
 
class representing a page pool
 
void zap(Pages &p)
zap the pool (unmap all but Pages p)
 
void updateCurSz(int sz, int incr)
adjust _cursz to current largest block
 
unsigned m_nPgPerGrp
page group size
 
static unsigned pagesize()
return (logical) page size of the system
 
ChunkList m_chunks
list of chunks used by the pool
 
ChunkList m_freelist
list of chunks used by the pool which are not full
 
static MMapVariety mmapVariety()
return variety of mmap supported on the system
 
void putOnFreeList(Chunk *chunk)
release a chunk
 
Pages pop()
pop a free element out of the pool
 
int nextChunkSz() const
find size of next chunk to allocate (in a hopefully smart way)
 
BidirMMapPipeException Exception
convenience typedef
 
std::list< Chunk * > ChunkList
list of chunks
 
int m_cursz
current chunk size
 
PageChunk::MMapVariety MMapVariety
convenience typedef
 
@ szincr
size class increment (sz = 1 << (minsz + k * szincr))
 
@ minsz
minimum chunk size (just below 1 << minsz bytes)
 
@ maxsz
maximum chunk size (just below 1 << maxsz bytes)
 
unsigned nPagesPerGroup() const
return number of pages per group (ie. as returned by pop())
 
PagePool(unsigned nPagesPerGroup)
constructor
 
unsigned m_szmap[(maxsz - minsz)/szincr]
chunk size map (histogram of chunk sizes)
 
void release(Chunk *chunk)
release a chunk
 
BidirMMapPipe_impl::PageChunk Chunk
a chunk of memory in the pool
 
class representing the header structure in an mmapped page
 
unsigned char * begin() const
return pointer to first byte in payload data area of page
 
short m_next
next page in list (in pagesizes)
 
unsigned short & size()
return reference to size field
 
static unsigned capacity()
return the capacity of the page
 
unsigned short & pos()
return reference to position field
 
unsigned free() const
free space left (to be written to)
 
Page(const Page &)
copy construction forbidden
 
void setNext(const Page *p)
set pointer to next page
 
unsigned short m_pos
index of next byte in payload area
 
bool full() const
true if page completely full
 
unsigned short m_size
size of payload (in bytes)
 
unsigned size() const
return size (of payload data)
 
unsigned char * end() const
return pointer to first byte in payload data area of page
 
Page & operator=(const Page &)=delete
assigment forbidden
 
unsigned pos() const
return position
 
bool empty() const
true if page empty
 
Page * next() const
return pointer to next page
 
bool filled() const
true if page partially filled
 
unsigned remaining() const
bytes remaining to be read
 
handle class for a number of Pages
 
Pages & operator=(const Pages &other)
assignment operator
 
static unsigned pagesize()
return page size
 
unsigned pageno(Page *p) const
perform page to page number mapping
 
impl * m_pimpl
pointer to implementation
 
Page * page(unsigned pgno) const
return page number pageno
 
Pages()
default constructor
 
BidirMMapPipe creates a bidirectional channel between the current process and a child it forks.
 
void doFlush(bool forcePartialPages=true)
perform the flush
 
unsigned recvpages()
receive a pages from the other end (may block), queue them
 
std::vector< PollEntry > PollVector
convenience typedef for poll() interface
 
Page * m_busylist
linked list: busy pages (data to be read)
 
BidirMMapPipe_impl::BidirMMapPipeException Exception
convenience typedef for BidirMMapPipeException
 
@ PagesPerEnd
pages per pipe end
 
@ FlushThresh
flush threshold
 
@ TotPages
pages shared (child + parent)
 
BidirMMapPipe_impl::Pages m_pages
mmapped pages
 
void flush()
flush buffers with unwritten data
 
static BidirMMapPipe_impl::PagePool & pagepool()
return page pool
 
static BidirMMapPipe_impl::PagePool * s_pagepool
pool of mmapped pages
 
size_type write(const void *addr, size_type sz)
wirte to pipe
 
bool good() const
status of stream is good
 
static int poll(PollVector &pipes, int timeout)
poll a set of pipes for events (ready to read from, ready to write to, error)
 
bool isChild() const
return if this end of the pipe is the child end
 
static void teardownall(void)
cleanup routine - at exit, we want our children to get a SIGTERM...
 
bool eof() const
true if end-of-file
 
static std::list< BidirMMapPipe * > s_openpipes
list of open BidirMMapPipes
 
static unsigned lenPageList(const Page *list)
return length of a page list
 
Page * dirtypage()
get a dirty page to write data to (may block)
 
int close()
flush buffers, close pipe
 
int m_flags
flags (e.g. end of file)
 
BidirMMapPipe(bool useExceptions=true, bool useSocketpair=false)
constructor (forks!)
 
void sendpages(Page *plist)
send page(s) to the other end (may block)
 
bool bad() const
true on I/O error
 
~BidirMMapPipe()
destructor
 
int doClose(bool force, bool holdlock=false)
close the pipe (no flush if forced)
 
BidirMMapPipe & operator<<(const bool &val)
 
bool closed() const
true if closed
 
size_type bytesReadableNonBlocking()
number of bytes that can be read without blocking
 
int m_inpipe
pipe end from which data may be read
 
static unsigned s_pagepoolrefcnt
page pool reference counter
 
@ failbit
logical failure (e.g. pipe closed)
 
@ eofbit
end of file reached
 
@ exceptionsbit
error reporting with exceptions
 
Page * m_dirtylist
linked list: dirty pages (data to be sent)
 
bool isParent() const
return if this end of the pipe is the parent end
 
static pthread_mutex_t s_openpipesmutex
protects s_openpipes
 
@ ReadError
pipe error read end
 
@ Writable
pipe can be written to
 
@ ReadInvalid
read end of pipe invalid
 
@ WriteEndOfFile
write pipe in end-of-file state
 
@ WriteInvalid
write end of pipe invalid
 
@ None
nothing special on this pipe
 
@ ReadEndOfFile
read pipe in end-of-file state
 
@ WriteError
pipe error Write end
 
@ Readable
pipe has data for reading
 
unsigned recvpages_nonblock()
receive pages from other end (non-blocking)
 
static int debugflag()
return the current setting of the debug flag
 
BidirMMapPipe & operator>>(bool &val)
 
void purge()
purge buffered data waiting to be read and/or written
 
size_type bytesWritableNonBlocking()
number of bytes that can be written without blocking
 
void feedPageLists(Page *plist)
"feed" the busy and free lists with a list of pages
 
Page * busypage()
get a busy page to read data from (may block)
 
size_type read(void *addr, size_type sz)
read from pipe
 
std::size_t size_type
type used to represent sizes
 
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)
 
static int s_debugflag
debug flag
 
int m_outpipe
pipe end to which data may be written
 
Page * m_freelist
linked list: free pages
 
pid_t m_childPid
pid of the child (zero if we're child)
 
void markPageDirty(Page *p)
put on dirty pages list
 
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....
 
Page * m_pages
pointer to first page
 
unsigned m_refcnt
reference counter
 
unsigned char m_npages
length in pages
 
PageChunk * m_parent
pointer to parent pool
 
static unsigned long masks[]