35#include <sys/socket.h>
37#define BEGIN_NAMESPACE_ROOFIT namespace RooFit {
38#define END_NAMESPACE_ROOFIT }
43namespace BidirMMapPipe_impl {
49 class BidirMMapPipeException :
public std::exception
58 static int dostrerror_r(
int err,
char* buf, std::size_t sz,
59 int (*
f)(
int,
char*, std::size_t))
60 {
return f(err, buf, sz); }
62 static int dostrerror_r(
int,
char*, std::size_t,
63 char* (*
f)(
int,
char*, std::size_t));
66 BidirMMapPipeException(
const char* msg,
int err);
68 const char*
what() const noexcept
override {
return m_buf; }
71 BidirMMapPipeException::BidirMMapPipeException(
const char* msg,
int err)
73 std::size_t msgsz = std::strlen(msg);
75 msgsz = std::min(msgsz, std::size_t(s_sz));
76 std::copy(msg, msg + msgsz, m_buf);
77 if (msgsz < s_sz) { m_buf[msgsz] =
':'; ++msgsz; }
78 if (msgsz < s_sz) { m_buf[msgsz] =
' '; ++msgsz; }
83 dostrerror_r(err, &m_buf[msgsz], s_sz - msgsz, ::strerror_r);
88 int BidirMMapPipeException::dostrerror_r(
int err,
char* buf,
89 std::size_t sz,
char* (*
f)(
int,
char*, std::size_t))
92 char *
tmp =
f(err, buf, sz);
93 if (tmp && tmp != buf) {
94 std::strncpy(buf, tmp, sz);
96 if (std::strlen(tmp) > sz - 1)
return ERANGE;
116 unsigned short m_size = 0;
117 unsigned short m_pos = 0;
124 assert(std::numeric_limits<unsigned short>::max() >=
125 PageChunk::pagesize());
128 Page(
const Page &) =
delete;
132 void setNext(
const Page*
p);
136 unsigned short&
size() {
return m_size; }
138 unsigned size()
const {
return m_size; }
140 unsigned short& pos() {
return m_pos; }
142 unsigned pos()
const {
return m_pos; }
144 inline unsigned char* begin()
const
145 {
return reinterpret_cast<unsigned char*
>(
const_cast<Page*
>(
this))
148 inline unsigned char*
end()
const
149 {
return reinterpret_cast<unsigned char*
>(
const_cast<Page*
>(
this))
150 + PageChunk::pagesize(); }
152 static unsigned capacity()
153 {
return PageChunk::pagesize() -
sizeof(Page); }
155 bool empty()
const {
return !m_size; }
157 bool filled()
const {
return !empty(); }
159 unsigned free()
const {
return capacity() - m_size; }
161 unsigned remaining()
const {
return m_size - m_pos; }
163 bool full()
const {
return !
free(); }
166 void Page::setNext(
const Page*
p)
171 const char* p1 =
reinterpret_cast<char*
>(
this);
172 const char* p2 =
reinterpret_cast<const char*
>(
p);
173 std::ptrdiff_t
tmp = p2 - p1;
175 assert(!(tmp % PageChunk::pagesize()));
176 tmp /=
static_cast<std::ptrdiff_t
>(PageChunk::pagesize());
179 assert(m_next == tmp);
185 Page* Page::next()
const
187 if (!m_next)
return nullptr;
188 char* ptmp =
reinterpret_cast<char*
>(
const_cast<Page*
>(
this));
189 ptmp += std::ptrdiff_t(m_next) * PageChunk::pagesize();
190 return reinterpret_cast<Page*
>(ptmp);
213 typedef BidirMMapPipeException
Exception;
221 typedef BidirMMapPipe_impl::PageChunk Chunk;
223 typedef std::list<Chunk*> ChunkList;
225 friend class BidirMMapPipe_impl::PageChunk;
228 typedef PageChunk::MMapVariety MMapVariety;
230 PagePool(
unsigned nPagesPerGroup);
237 static unsigned pagesize() {
return PageChunk::pagesize(); }
239 static MMapVariety mmapVariety()
240 {
return PageChunk::mmapVariety(); }
243 unsigned nPagesPerGroup()
const {
return m_nPgPerGrp; }
252 ChunkList m_freelist;
254 unsigned m_szmap[(maxsz - minsz) / szincr];
258 unsigned m_nPgPerGrp;
261 void updateCurSz(
int sz,
int incr);
263 int nextChunkSz()
const;
265 void putOnFreeList(Chunk* chunk);
267 void release(Chunk* chunk);
270 Pages::Pages(PageChunk* parent, Page* pages,
unsigned npg) :
274 m_pimpl->m_parent = parent;
275 m_pimpl->m_pages = pages;
276 m_pimpl->m_refcnt = 1;
277 m_pimpl->m_npages = npg;
279 for (
unsigned i = 0; i < m_pimpl->m_npages; ++i)
new(page(i)) Page();
282 unsigned PageChunk::s_physpgsz = PageChunk::getPageSize();
283 unsigned PageChunk::s_pagesize = std::min(PageChunk::s_physpgsz, 16384u);
284 PageChunk::MMapVariety PageChunk::s_mmapworks = PageChunk::Unknown;
288 if (m_pimpl && !--(m_pimpl->m_refcnt)) {
289 if (m_pimpl->m_parent) m_pimpl->m_parent->push(*
this);
294 Pages::Pages(
const Pages& other) :
295 m_pimpl(other.m_pimpl)
296 { ++(m_pimpl->m_refcnt); }
298 Pages& Pages::operator=(
const Pages& other)
300 if (&other ==
this)
return *
this;
301 if (!--(m_pimpl->m_refcnt)) {
302 if (m_pimpl->m_parent) m_pimpl->m_parent->push(*
this);
305 m_pimpl = other.m_pimpl;
306 ++(m_pimpl->m_refcnt);
310 unsigned Pages::pagesize() {
return PageChunk::pagesize(); }
312 Page* Pages::page(
unsigned pgno)
const
314 assert(pgno < m_pimpl->m_npages);
315 unsigned char* pptr =
316 reinterpret_cast<unsigned char*
>(m_pimpl->m_pages);
317 pptr += pgno * pagesize();
318 return reinterpret_cast<Page*
>(pptr);
321 unsigned Pages::pageno(Page*
p)
const
323 const unsigned char* pptr =
324 reinterpret_cast<const unsigned char*
>(
p);
325 const unsigned char* bptr =
326 reinterpret_cast<const unsigned char*
>(m_pimpl->m_pages);
327 assert(0 == ((pptr - bptr) % pagesize()));
328 const unsigned nr = (pptr - bptr) / pagesize();
329 assert(nr < m_pimpl->m_npages);
333 unsigned PageChunk::getPageSize()
336 long pgsz = sysconf(_SC_PAGESIZE);
337 if (-1 == pgsz)
throw Exception(
"sysconf", errno);
338 if (pgsz > 512 && pgsz >
long(
sizeof(Page)))
347 PageChunk::PageChunk(PagePool* parent,
348 unsigned length,
unsigned nPgPerGroup) :
350 m_end(reinterpret_cast<
void*>(
351 reinterpret_cast<unsigned char*>(m_begin) +
length)),
352 m_parent(parent), m_nPgPerGrp(nPgPerGroup), m_nUsedGrp(0)
355 unsigned char*
p =
reinterpret_cast<unsigned char*
>(m_begin);
356 unsigned char* pend =
reinterpret_cast<unsigned char*
>(m_end);
358 m_freelist.push_back(
reinterpret_cast<void*
>(
p));
359 p += nPgPerGroup * PagePool::pagesize();
363 PageChunk::~PageChunk()
365 if (m_parent) assert(empty());
366 if (m_begin) domunmap(m_begin,
len());
369 bool PageChunk::contains(
const Pages&
p)
const
370 {
return p.m_pimpl->m_parent ==
this; }
372 Pages PageChunk::pop()
374 assert(!m_freelist.empty());
375 void*
p = m_freelist.front();
376 m_freelist.pop_front();
378 return Pages(
this,
reinterpret_cast<Page*
>(
p), m_nPgPerGrp);
381 void PageChunk::push(
const Pages&
p)
384 bool wasempty = m_freelist.empty();
385 m_freelist.push_front(
reinterpret_cast<void*
>(
p[0u]));
389 if (wasempty) m_parent->putOnFreeList(
this);
391 if (empty())
return m_parent->release(
this);
395 void* PageChunk::dommap(
unsigned len)
397 assert(
len && 0 == (
len % s_physpgsz));
409 static bool msgprinted =
false;
410 if (Anonymous == s_mmapworks || Unknown == s_mmapworks) {
411#if defined(MAP_ANONYMOUS)
413#define MYANONFLAG MAP_ANONYMOUS
414#elif defined(MAP_ANON)
416#define MYANONFLAG MAP_ANON
421 void* retVal = ::mmap(
nullptr,
len, PROT_READ | PROT_WRITE,
422 MYANONFLAG | MAP_SHARED, -1, 0);
423 if (MAP_FAILED == retVal) {
424 if (Anonymous == s_mmapworks)
throw Exception(
"mmap", errno);
426 assert(Unknown == s_mmapworks || Anonymous == s_mmapworks);
427 s_mmapworks = Anonymous;
428 if (BidirMMapPipe::debugflag() && !msgprinted) {
429 std::cerr <<
" INFO: In " << __func__ <<
" (" <<
430 __FILE__ <<
", line " << __LINE__ <<
431 "): anonymous mmapping works, excellent!" <<
440 if (DevZero == s_mmapworks || Unknown == s_mmapworks) {
443 int fd = ::open(
"/dev/zero", O_RDWR);
445 throw Exception(
"open /dev/zero", errno);
446 void* retVal = ::mmap(
nullptr,
len,
447 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
448 if (MAP_FAILED == retVal) {
451 if (DevZero == s_mmapworks)
throw Exception(
"mmap", errsv);
453 assert(Unknown == s_mmapworks || DevZero == s_mmapworks);
454 s_mmapworks = DevZero;
456 if (-1 == ::close(fd))
457 throw Exception(
"close /dev/zero", errno);
458 if (BidirMMapPipe::debugflag() && !msgprinted) {
459 std::cerr <<
" INFO: In " << __func__ <<
" (" << __FILE__ <<
460 ", line " << __LINE__ <<
"): mmapping /dev/zero works, "
461 "very good!" << std::endl;
466 if (FileBacked == s_mmapworks || Unknown == s_mmapworks) {
468 std::string
name = tmpPath +
"/roofit_BidirMMapPipe-XXXXXX";
471 if (-1 == (fd = ::mkstemp(
const_cast<char*
>(
name.c_str()))))
throw Exception(
"mkstemp", errno);
473 if (-1 == ::unlink(
name.c_str())) {
479 if (-1 == ::lseek(fd,
len - 1, SEEK_SET)) {
485 if (1 != ::write(fd,
name.c_str(), 1)) {
491 void* retVal = ::mmap(
nullptr,
len,
492 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
493 if (MAP_FAILED == retVal) {
496 if (FileBacked == s_mmapworks)
throw Exception(
"mmap", errsv);
498 assert(Unknown == s_mmapworks || FileBacked == s_mmapworks);
499 s_mmapworks = FileBacked;
501 if (-1 == ::close(fd)) {
503 ::munmap(retVal,
len);
506 if (BidirMMapPipe::debugflag() && !msgprinted) {
507 std::cerr <<
" INFO: In " << __func__ <<
" (" << __FILE__ <<
508 ", line " << __LINE__ <<
"): mmapping temporary files "
509 "works, good!" << std::endl;
514 if (Copy == s_mmapworks || Unknown == s_mmapworks) {
519 if (BidirMMapPipe::debugflag() && !msgprinted) {
520 std::cerr <<
"WARNING: In " << __func__ <<
" (" << __FILE__ <<
521 ", line " << __LINE__ <<
"): anonymous mmapping of "
522 "shared buffers failed, falling back to read/write on "
523 " pipes!" << std::endl;
527 void* retVal = std::malloc(
len);
528 if (!retVal)
throw Exception(
"malloc", errno);
536 void PageChunk::domunmap(
void* addr,
unsigned len)
538 assert(
len && 0 == (
len % s_physpgsz));
540 assert(Unknown != s_mmapworks);
541 if (Copy != s_mmapworks) {
542 if (-1 == ::munmap(addr,
len))
550 void PageChunk::zap(Pages&
p)
563 if (Copy != s_mmapworks) {
564 unsigned char* p0 =
reinterpret_cast<unsigned char*
>(m_begin);
565 unsigned char* p1 =
reinterpret_cast<unsigned char*
>(
p[0u]);
566 unsigned char* p2 = p1 +
p.npages() * s_physpgsz;
567 unsigned char* p3 =
reinterpret_cast<unsigned char*
>(m_end);
568 if (p1 != p0) ::mprotect(p0, p1 - p0, PROT_NONE);
569 if (p2 != p3) ::mprotect(p2, p3 - p2, PROT_NONE);
574 p.m_pimpl->m_parent =
nullptr;
575 m_begin = m_end =
nullptr;
580 PagePool::PagePool(
unsigned nPgPerGroup) : m_nPgPerGrp(nPgPerGroup)
584 if (PageChunk::pagesize() != PageChunk::physPgSz()) {
585 const unsigned mult =
586 PageChunk::physPgSz() / PageChunk::pagesize();
587 const unsigned desired = nPgPerGroup * PageChunk::pagesize();
589 const unsigned actual = mult *
590 (desired / mult +
bool(desired % mult));
591 const unsigned newPgPerGrp = actual / PageChunk::pagesize();
592 if (BidirMMapPipe::debugflag()) {
593 std::cerr <<
" INFO: In " << __func__ <<
" (" <<
594 __FILE__ <<
", line " << __LINE__ <<
595 "): physical page size " << PageChunk::physPgSz() <<
596 ", subdividing into logical pages of size " <<
597 PageChunk::pagesize() <<
", adjusting nPgPerGroup " <<
598 m_nPgPerGrp <<
" -> " << newPgPerGrp <<
601 assert(newPgPerGrp >= m_nPgPerGrp);
602 m_nPgPerGrp = newPgPerGrp;
604 std::fill(m_szmap, m_szmap + ((maxsz - minsz) / szincr), 0);
607 PagePool::~PagePool()
610 for (ChunkList::iterator it = m_chunks.begin(); m_chunks.end() != it; ++it)
615 void PagePool::zap(Pages&
p)
619 for (ChunkList::iterator it = m_chunks.begin(); m_chunks.end() != it; ++it) {
620 if ((*it)->contains(
p)) {
627 std::fill(m_szmap, m_szmap + ((maxsz - minsz) / szincr), 0);
631 Pages PagePool::pop()
633 if (m_freelist.empty()) {
635 const int sz = nextChunkSz();
636 Chunk *
c =
new Chunk(
this,
637 sz * m_nPgPerGrp * pagesize(), m_nPgPerGrp);
638 m_chunks.push_front(
c);
639 m_freelist.push_back(
c);
643 Chunk*
c = m_freelist.front();
646 if (
c->full()) m_freelist.pop_front();
650 void PagePool::release(PageChunk* chunk)
652 assert(chunk->empty());
654 ChunkList::iterator it = std::find(
655 m_freelist.begin(), m_freelist.end(), chunk);
656 if (m_freelist.end() == it)
657 throw Exception(
"PagePool::release(PageChunk*)", EINVAL);
658 m_freelist.erase(it);
660 it = std::find(m_chunks.begin(), m_chunks.end(), chunk);
661 if (m_chunks.end() == it)
662 throw Exception(
"PagePool::release(PageChunk*)", EINVAL);
664 const unsigned sz = chunk->len() / (pagesize() * m_nPgPerGrp);
669 void PagePool::putOnFreeList(PageChunk* chunk)
671 assert(!chunk->full());
672 m_freelist.push_back(chunk);
675 void PagePool::updateCurSz(
int sz,
int incr)
677 m_szmap[(sz - minsz) / szincr] += incr;
679 for (
int i = (maxsz - minsz) / szincr; i--; ) {
681 m_cursz += i * szincr;
687 int PagePool::nextChunkSz()
const
691 if (m_chunks.empty()) {
699 if (1 != m_chunks.size()) {
709 if (sz > maxsz) sz = maxsz;
710 if (sz < minsz) sz = minsz;
716pthread_mutex_t BidirMMapPipe::s_openpipesmutex = PTHREAD_MUTEX_INITIALIZER;
717std::list<BidirMMapPipe*> BidirMMapPipe::s_openpipes;
718BidirMMapPipe_impl::PagePool* BidirMMapPipe::s_pagepool =
nullptr;
719unsigned BidirMMapPipe::s_pagepoolrefcnt = 0;
720int BidirMMapPipe::s_debugflag = 0;
722BidirMMapPipe_impl::PagePool& BidirMMapPipe::pagepool()
725 s_pagepool =
new BidirMMapPipe_impl::PagePool(TotPages);
729void BidirMMapPipe::teardownall(
void)
731 pthread_mutex_lock(&s_openpipesmutex);
732 while (!s_openpipes.empty()) {
733 BidirMMapPipe *
p = s_openpipes.front();
734 pthread_mutex_unlock(&s_openpipesmutex);
735 if (
p->m_childPid) kill(
p->m_childPid, SIGTERM);
736 p->doClose(
true,
true);
737 pthread_mutex_lock(&s_openpipesmutex);
739 pthread_mutex_unlock(&s_openpipesmutex);
742BidirMMapPipe::BidirMMapPipe(
const BidirMMapPipe&) :
743 m_pages(pagepool().pop())
746 { BidirMMapPipe_impl::Pages
p;
p.swap(m_pages); }
747 if (!s_pagepoolrefcnt) {
749 s_pagepool =
nullptr;
753BidirMMapPipe::BidirMMapPipe(
bool useExceptions,
bool useSocketpair) :
754 m_pages(pagepool().pop()), m_busylist(nullptr), m_freelist(nullptr), m_dirtylist(nullptr),
755 m_inpipe(-1), m_outpipe(-1), m_flags(failbit), m_childPid(0),
756 m_parentPid(::getpid())
760 assert(0 < TotPages && 0 == (TotPages & 1) && TotPages <= 256);
761 int fds[4] = { -1, -1, -1, -1 };
763 static bool firstcall =
true;
764 if (useExceptions) m_flags |= exceptionsbit;
771 if (0 != atexit(BidirMMapPipe::teardownall))
776 for (
unsigned i = 1; i < TotPages; ++i)
777 m_pages[i - 1]->setNext(m_pages[i]);
778 m_pages[PagesPerEnd - 1]->setNext(
nullptr);
779 if (!useSocketpair) {
781 if (0 != ::pipe(&fds[0]))
throw Exception(
"pipe", errno);
782 if (0 != ::pipe(&fds[2]))
throw Exception(
"pipe", errno);
784 if (0 != ::socketpair(AF_UNIX, SOCK_STREAM, 0, &fds[0]))
788 pthread_mutex_lock(&s_openpipesmutex);
790 switch ((m_childPid = ::fork())) {
793 pthread_mutex_unlock(&s_openpipesmutex);
800 if (-1 == ::close(fds[0]) || (-1 == ::close(fds[3]))) {
802 pthread_mutex_unlock(&s_openpipesmutex);
805 fds[0] = fds[3] = -1;
810 if (-1 == ::close(fds[0])) {
812 pthread_mutex_unlock(&s_openpipesmutex);
816 m_inpipe = m_outpipe = fds[1];
820 for (std::list<BidirMMapPipe*>::iterator it = s_openpipes.begin();
821 s_openpipes.end() != it; ) {
822 BidirMMapPipe*
p = *it;
823 it = s_openpipes.erase(it);
824 p->doClose(
true,
true);
826 pagepool().zap(m_pages);
827 s_pagepoolrefcnt = 0;
829 s_pagepool =
nullptr;
830 s_openpipes.push_front(
this);
831 pthread_mutex_unlock(&s_openpipesmutex);
833 m_freelist = m_pages[PagesPerEnd];
836 if (1 != xferraw(m_outpipe, &
c, 1, ::write))
837 throw Exception(
"handshake: xferraw write", EPIPE);
838 if (1 != xferraw(m_inpipe, &
c, 1, ::read))
839 throw Exception(
"handshake: xferraw read", EPIPE);
840 if (
'P' !=
c)
throw Exception(
"handshake", EPIPE);
846 if (-1 == ::close(fds[1]) || -1 == ::close(fds[2])) {
848 pthread_mutex_unlock(&s_openpipesmutex);
851 fds[1] = fds[2] = -1;
856 if (-1 == ::close(fds[1])) {
858 pthread_mutex_unlock(&s_openpipesmutex);
862 m_inpipe = m_outpipe = fds[0];
866 s_openpipes.push_front(
this);
867 pthread_mutex_unlock(&s_openpipesmutex);
869 m_freelist = m_pages[0u];
872 if (1 != xferraw(m_outpipe, &
c, 1, ::write))
873 throw Exception(
"handshake: xferraw write", EPIPE);
874 if (1 != xferraw(m_inpipe, &
c, 1, ::read))
875 throw Exception(
"handshake: xferraw read", EPIPE);
876 if (
'C' !=
c)
throw Exception(
"handshake", EPIPE);
882 if (-1 == ::fcntl(m_outpipe, F_GETFD, &fdflags))
884 fdflags |= FD_CLOEXEC;
885 if (-1 == ::fcntl(m_outpipe, F_SETFD, fdflags))
887 if (m_inpipe != m_outpipe) {
888 if (-1 == ::fcntl(m_inpipe, F_GETFD, &fdflags))
890 fdflags |= FD_CLOEXEC;
891 if (-1 == ::fcntl(m_inpipe, F_SETFD, fdflags))
897 }
catch (BidirMMapPipe::Exception&) {
898 if (0 != m_childPid) kill(m_childPid, SIGTERM);
899 for (
int i = 0; i < 4; ++i)
900 if (-1 != fds[i] && 0 != fds[i]) ::close(fds[i]);
903 BidirMMapPipe_impl::Pages
p;
p.swap(m_pages);
905 if (!--s_pagepoolrefcnt) {
907 s_pagepool =
nullptr;
913int BidirMMapPipe::close()
915 assert(!(m_flags & failbit));
916 return doClose(
false);
919int BidirMMapPipe::doClose(
bool force,
bool holdlock)
921 if (m_flags & failbit)
return 0;
923 if (!force && -1 != m_outpipe && -1 != m_inpipe) flush();
925 if (m_inpipe == m_outpipe) {
926 if (-1 != m_outpipe && !force && -1 == ::shutdown(m_outpipe, SHUT_WR))
930 if (-1 != m_outpipe && -1 == ::close(m_outpipe))
931 if (!force)
throw Exception(
"close", errno);
936 if (!force && -1 != m_inpipe) {
953 while ((err = ::poll(&fds, 1, 1 << 20)) >= 0) {
954 if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))
break;
955 if (fds.revents & POLLIN) {
957 if (1 > ::read(m_inpipe, &
c, 1))
break;
960 }
while (0 > err && EINTR == errno);
964 if (-1 != m_inpipe && -1 == ::close(m_inpipe))
965 if (!force)
throw Exception(
"close", errno);
969 { BidirMMapPipe_impl::Pages
p;
p.swap(m_pages); }
970 if (!--s_pagepoolrefcnt) {
972 s_pagepool =
nullptr;
974 }
catch (std::exception&) {
977 m_busylist = m_freelist = m_dirtylist =
nullptr;
983 tmp = waitpid(m_childPid, &retVal, 0);
984 }
while (-1 == tmp && EINTR == errno);
986 if (!force)
throw Exception(
"waitpid", errno);
990 if (!holdlock) pthread_mutex_lock(&s_openpipesmutex);
991 std::list<BidirMMapPipe*>::iterator it = std::find(
992 s_openpipes.begin(), s_openpipes.end(),
this);
993 if (s_openpipes.end() != it) s_openpipes.erase(it);
994 if (!holdlock) pthread_mutex_unlock(&s_openpipesmutex);
999BidirMMapPipe::~BidirMMapPipe()
1002BidirMMapPipe::size_type BidirMMapPipe::xferraw(
1003 int fd,
void* addr, size_type
len,
1004 ssize_t (*xferfn)(
int,
void*, std::size_t))
1006 size_type xferred = 0;
1007 unsigned char* buf =
reinterpret_cast<unsigned char*
>(addr);
1009 ssize_t
tmp = xferfn(fd, buf,
len);
1015 }
else if (0 == tmp) {
1018 }
else if (-1 == tmp) {
1025 if (xferred)
return xferred;
1029#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
1032 std::cerr <<
" ERROR: In " << __func__ <<
" (" <<
1033 __FILE__ <<
", line " << __LINE__ <<
1034 "): expect transfer to block!" << std::endl;
1040 throw Exception(
"xferraw: unexpected return value from read/write",
1047void BidirMMapPipe::sendpages(Page* plist)
1050 unsigned char pg = m_pages[plist];
1051 if (1 == xferraw(m_outpipe, &pg, 1, ::write)) {
1052 if (BidirMMapPipe_impl::PageChunk::Copy ==
1053 BidirMMapPipe_impl::PageChunk::mmapVariety()) {
1055 for (Page*
p = plist;
p;
p =
p->next()) {
1056 if (
sizeof(Page) +
p->size() !=
1057 xferraw(m_outpipe,
p,
sizeof(Page) +
p->size(),
1059 throw Exception(
"sendpages: short write", EPIPE);
1064 throw Exception(
"sendpages: short write", EPIPE);
1066 }
else { assert(plist); }
1069unsigned BidirMMapPipe::recvpages()
1072 unsigned retVal = 0;
1073 Page *plisthead =
nullptr;
1074 Page *plisttail =
nullptr;
1075 if (1 == xferraw(m_inpipe, &pg, 1, ::read)) {
1076 plisthead = plisttail = m_pages[pg];
1078 if (BidirMMapPipe_impl::PageChunk::Copy ==
1079 BidirMMapPipe_impl::PageChunk::mmapVariety()) {
1081 for (; plisttail; ++retVal) {
1082 Page*
p = plisttail;
1083 if (
sizeof(Page) == xferraw(m_inpipe,
p,
sizeof(Page),
1085 plisttail =
p->next();
1086 if (
p->empty())
continue;
1088 if (
p->size() != xferraw(m_inpipe,
p->begin(),
p->size(),
1093 retVal = lenPageList(plisthead);
1097 if (plisthead) feedPageLists(plisthead);
1103unsigned BidirMMapPipe::recvpages_nonblock()
1107 fds.events = POLLIN;
1109 unsigned retVal = 0;
1111 int rc = ::poll(&fds, 1, 0);
1113 if (EINTR == errno)
continue;
1116 if (1 == retVal && fds.revents & POLLIN &&
1117 !(fds.revents & (POLLNVAL | POLLERR))) {
1128unsigned BidirMMapPipe::lenPageList(
const Page*
p)
1131 for ( ;
p;
p =
p->next()) ++
n;
1135void BidirMMapPipe::feedPageLists(Page* plist)
1139 Page *blend = m_busylist;
1140 while (blend && blend->next()) blend = blend->next();
1144 Page *sendlisthead =
nullptr;
1145 Page *sendlisttail =
nullptr;
1150 p->setNext(
nullptr);
1155 if (blend) blend->setNext(
p);
1156 else m_busylist =
p;
1163 if ((isParent() && m_pages[
p] >= PagesPerEnd) ||
1164 (isChild() && m_pages[
p] < PagesPerEnd)) {
1166 if (!sendlisthead) sendlisthead =
p;
1167 if (sendlisttail) sendlisttail->setNext(
p);
1171 p->setNext(m_freelist);
1181 while ((dp = m_dirtylist) && dp->full()) {
1184 m_dirtylist =
p->next();
1186 p->setNext(
nullptr);
1187 sendlisttail->setNext(
p);
1194 const int nfds = (m_outpipe == m_inpipe) ? 1 : 2;
1195 struct pollfd fds[2];
1196 fds[0].fd = m_outpipe;
1197 fds[0].events = fds[0].revents = 0;
1198 if (m_outpipe != m_inpipe) {
1199 fds[1].fd = m_inpipe;
1200 fds[1].events = fds[1].revents = 0;
1202 fds[0].events |= POLLIN;
1206 retVal = ::poll(fds, nfds, 0);
1207 if (0 > retVal && EINTR == errno)
1212 bool ok = !(fds[0].revents & (POLLERR | POLLNVAL | POLLHUP));
1213 if (m_outpipe != m_inpipe) {
1214 ok = ok && !(fds[1].revents & (POLLERR | POLLNVAL | POLLHUP));
1216 if (ok && fds[0].revents & POLLIN) {
1217 unsigned ret = recvpages();
1218 if (!ret) ok =
false;
1222 if (ok) sendpages(sendlisthead);
1227 throw Exception(
"feedPageLists: poll", errno);
1232void BidirMMapPipe::markPageDirty(Page*
p)
1235 assert(
p == m_freelist);
1237 m_freelist =
p->next();
1238 p->setNext(
nullptr);
1240 Page* dl = m_dirtylist;
1241 while (dl && dl->next()) dl = dl->next();
1242 if (dl) dl->setNext(
p);
1243 else m_dirtylist =
p;
1246BidirMMapPipe::Page* BidirMMapPipe::busypage()
1249 recvpages_nonblock();
1253 while (!(
p = m_busylist))
if (!recvpages())
return nullptr;
1257BidirMMapPipe::Page* BidirMMapPipe::dirtypage()
1260 recvpages_nonblock();
1261 Page*
p = m_dirtylist;
1263 if (
p)
while (
p->next())
p =
p->next();
1264 if (!
p ||
p->full()) {
1266 while (!(
p = m_freelist))
if (!recvpages())
return nullptr;
1272void BidirMMapPipe::flush()
1273{
return doFlush(
true); }
1275void BidirMMapPipe::doFlush(
bool forcePartialPages)
1277 assert(!(m_flags & failbit));
1279 Page *flushlisthead =
nullptr;
1280 Page *flushlisttail =
nullptr;
1281 while (m_dirtylist) {
1282 Page*
p = m_dirtylist;
1283 if (!forcePartialPages && !
p->full())
break;
1285 m_dirtylist =
p->next();
1286 p->setNext(
nullptr);
1288 if (!flushlisthead) flushlisthead =
p;
1289 if (flushlisttail) flushlisttail->setNext(
p);
1292 if (flushlisthead) sendpages(flushlisthead);
1295void BidirMMapPipe::purge()
1297 assert(!(m_flags & failbit));
1300 Page *
l = m_busylist;
1301 while (
l &&
l->next())
l =
l->next();
1302 if (
l)
l->setNext(m_dirtylist);
1303 else m_busylist = m_dirtylist;
1306 for (Page*
p = m_busylist;
p;
p =
p->next())
p->size() = 0;
1308 if (m_busylist) feedPageLists(m_busylist);
1309 m_busylist = m_dirtylist =
nullptr;
1312BidirMMapPipe::size_type BidirMMapPipe::bytesReadableNonBlocking()
1316 recvpages_nonblock();
1317 size_type retVal = 0;
1318 for (Page*
p = m_busylist;
p;
p =
p->next())
1319 retVal +=
p->size() -
p->pos();
1323BidirMMapPipe::size_type BidirMMapPipe::bytesWritableNonBlocking()
1327 recvpages_nonblock();
1330 bool couldwrite =
false;
1334 fds.events = POLLOUT;
1338 retVal = ::poll(&fds, 1, 0);
1340 if (EINTR == errno)
continue;
1341 throw Exception(
"bytesWritableNonBlocking: poll", errno);
1343 if (1 == retVal && fds.revents & POLLOUT &&
1344 !(fds.revents & (POLLNVAL | POLLERR | POLLHUP)))
1350 size_type retVal = 0;
1351 unsigned npages = 0;
1353 for (Page*
p = m_dirtylist;
p;
p =
p->next()) {
1357 retVal +=
p->free();
1358 if (npages >= FlushThresh && !couldwrite)
break;
1361 for (Page*
p = m_freelist;
p && (!m_dirtylist ||
1362 npages < FlushThresh || couldwrite);
p =
p->next()) {
1364 retVal += Page::capacity();
1369BidirMMapPipe::size_type BidirMMapPipe::read(
void* addr, size_type sz)
1371 assert(!(m_flags & failbit));
1372 size_type nread = 0;
1373 unsigned char *ap =
reinterpret_cast<unsigned char*
>(addr);
1377 Page*
p = busypage();
1382 unsigned char* pp =
p->begin() +
p->pos();
1383 size_type csz = std::min(size_type(
p->remaining()), sz);
1384 std::copy(pp, pp + csz, ap);
1389 assert(
p->size() >=
p->pos());
1390 if (
p->size() ==
p->pos()) {
1392 m_busylist =
p->next();
1393 p->setNext(
nullptr);
1399 m_flags |= rderrbit;
1400 if (m_flags & exceptionsbit)
throw;
1405BidirMMapPipe::size_type BidirMMapPipe::write(
const void* addr, size_type sz)
1407 assert(!(m_flags & failbit));
1408 size_type written = 0;
1409 const unsigned char *ap =
reinterpret_cast<const unsigned char*
>(addr);
1413 Page*
p = dirtypage();
1418 unsigned char* pp =
p->begin() +
p->size();
1419 size_type csz = std::min(size_type(
p->free()), sz);
1420 std::copy(ap, ap + csz, pp);
1425 assert(
p->capacity() >=
p->size());
1429 if (lenPageList(m_dirtylist) >= FlushThresh)
1434 m_flags |= wrerrbit;
1435 if (m_flags & exceptionsbit)
throw;
1440int BidirMMapPipe::poll(BidirMMapPipe::PollVector& pipes,
int timeout)
1445 bool canskiptimeout =
false;
1446 std::vector<unsigned>
masks(pipes.size(), ~(Readable | Writable));
1447 std::vector<unsigned>::iterator mit =
masks.begin();
1448 for (PollVector::iterator it = pipes.begin(); pipes.end() != it;
1450 PollEntry& pe = *it;
1455 canskiptimeout =
true;
1459 if (pe.pipe->closed()) pe.revents |= Invalid;
1461 if (pe.pipe->bad()) pe.revents |=
Error;
1463 if (pe.pipe->eof()) pe.revents |= EndOfFile;
1465 if (pe.events & Readable) {
1467 if (pe.pipe->m_busylist) pe.revents |= Readable;
1470 if (pe.events & Writable) {
1472 if (pe.pipe->m_freelist) {
1473 pe.revents |= Writable;
1475 Page *dl = pe.pipe->m_dirtylist;
1476 while (dl && dl->next()) dl = dl->next();
1477 if (dl && dl->pos() < Page::capacity())
1478 pe.revents |= Writable;
1481 if (pe.revents) canskiptimeout =
true;
1484 std::vector<pollfd> fds;
1485 fds.reserve(2 * pipes.size());
1486 std::map<int, PollEntry*> fds2pipes;
1487 for (PollVector::const_iterator it = pipes.begin();
1488 pipes.end() != it; ++it) {
1489 const PollEntry& pe = *it;
1491 fds2pipes.insert(std::make_pair((
tmp.fd = pe.pipe->m_inpipe),
1492 const_cast<PollEntry*
>(&pe)));
1493 tmp.events =
tmp.revents = 0;
1496 tmp.events |= POLLIN;
1497 if (pe.pipe->m_outpipe !=
tmp.fd) {
1500 fds2pipes.insert(std::make_pair(
1501 unsigned(
tmp.fd = pe.pipe->m_outpipe),
1502 const_cast<PollEntry*
>(&pe)));
1506 if (pe.events & Writable)
tmp.events |= POLLOUT;
1512 retVal = ::poll(&fds[0], fds.size(), canskiptimeout ? 0 : timeout);
1514 if (EINTR == errno)
continue;
1520 for (std::vector<pollfd>::iterator it = fds.begin();
1521 fds.end() != it; ++it) {
1525 PollEntry& pe = *fds2pipes[fe.fd];
1527 if (fe.revents & POLLNVAL && fe.fd == pe.pipe->m_inpipe)
1528 pe.revents |= ReadInvalid;
1529 if (fe.revents & POLLNVAL && fe.fd == pe.pipe->m_outpipe)
1530 pe.revents |= WriteInvalid;
1531 if (fe.revents & POLLERR && fe.fd == pe.pipe->m_inpipe)
1532 pe.revents |= ReadError;
1533 if (fe.revents & POLLERR && fe.fd == pe.pipe->m_outpipe)
1534 pe.revents |= WriteError;
1535 if (fe.revents & POLLHUP && fe.fd == pe.pipe->m_inpipe)
1536 pe.revents |= ReadEndOfFile;
1537 if (fe.revents & POLLHUP && fe.fd == pe.pipe->m_outpipe)
1538 pe.revents |= WriteEndOfFile;
1539 if ((fe.revents & POLLIN) && fe.fd == pe.pipe->m_inpipe &&
1540 !(fe.revents & (POLLNVAL | POLLERR))) {
1543 if (0 == pe.pipe->recvpages())
continue;
1546 int tmp = ::poll(&fe, 1, 0);
1547 if (tmp > 0)
goto oncemore;
1549 if (EINTR == errno)
continue;
1555 if (pe.pipe->m_busylist) pe.revents |= Readable;
1556 if (fe.revents & POLLOUT && fe.fd == pe.pipe->m_outpipe) {
1557 if (pe.pipe->m_freelist) {
1558 pe.revents |= Writable;
1560 Page *dl = pe.pipe->m_dirtylist;
1561 while (dl && dl->next()) dl = dl->next();
1562 if (dl && dl->pos() < Page::capacity())
1563 pe.revents |= Writable;
1569 mit =
masks.begin();
1570 for (PollVector::iterator it = pipes.begin();
1571 pipes.end() != it; ++it, ++mit)
1572 if ((it->revents &= *mit)) ++npipes;
1576BidirMMapPipe& BidirMMapPipe::operator<<(
const char* str)
1578 size_t sz = std::strlen(str);
1580 if (sz) write(str, sz);
1584BidirMMapPipe& BidirMMapPipe::operator>>(
char* (&str))
1588 if (good() && !eof()) {
1589 str =
reinterpret_cast<char*
>(std::realloc(str, sz + 1));
1590 if (!str)
throw Exception(
"realloc", errno);
1591 if (sz) read(str, sz);
1597BidirMMapPipe& BidirMMapPipe::operator<<(
const std::string& str)
1599 size_t sz = str.size();
1601 write(str.data(), sz);
1605BidirMMapPipe& BidirMMapPipe::operator>>(std::string& str)
1610 if (good() && !eof()) {
1612 for (
unsigned char c; sz--; str.push_back(
c)) *
this >>
c;
1619#ifdef TEST_BIDIRMMAPPIPE
1622int simplechild(BidirMMapPipe& pipe)
1625 while (pipe.good() && !pipe.eof()) {
1629 if (!pipe)
return -1;
1630 if (pipe.eof())
break;
1632 std::cout <<
"[CHILD] : read: " << str << std::endl;
1633 str =
"... early in the morning?";
1635 pipe << str << BidirMMapPipe::flush;
1637 if (str.empty())
break;
1638 if (!pipe)
return -1;
1639 if (pipe.eof())
break;
1640 std::cout <<
"[CHILD] : wrote: " << str << std::endl;
1647int randomchild(BidirMMapPipe& pipe)
1650 ::srand48(::getpid());
1658 for (
int i = 0; i < 5; ++i) {
1660 ::usleep(
int(1e6 * ::drand48()));
1661 std::ostringstream buf;
1662 buf <<
"child pid " << ::getpid() <<
" sends message " << i;
1663 std::string str = buf.str();
1664 std::cout <<
"[CHILD] : " << str << std::endl;
1665 pipe << str << BidirMMapPipe::flush;
1666 if (!pipe)
return -1;
1667 if (pipe.eof())
break;
1670 pipe <<
"" << BidirMMapPipe::flush;
1678int benchchildrtt(BidirMMapPipe& pipe)
1683 while (pipe && !pipe.eof()) {
1690 if (pipe.eof())
break;
1691 pipe << str << BidirMMapPipe::flush;
1693 if (!std::strlen(str))
break;
1700int benchchildsink(BidirMMapPipe& pipe)
1704 while (pipe && !pipe.eof()) {
1706 if (!std::strlen(str))
break;
1708 pipe <<
"" << BidirMMapPipe::flush;
1714int benchchildsource(BidirMMapPipe& pipe)
1718 for (
unsigned i = 0; i <= 24; ++i) {
1719 str =
reinterpret_cast<char*
>(std::realloc(str, (1 << i) + 1));
1720 std::memset(str,
'4', 1 << i);
1722 for (
unsigned j = 0; j < 1 << 7; ++j) {
1724 if (!pipe || pipe.eof()) {
1731 pipe <<
"" << BidirMMapPipe::flush;
1734 pipe <<
"" << BidirMMapPipe::flush;
1740BidirMMapPipe* spawnChild(
int (*childexec)(BidirMMapPipe&))
1743 BidirMMapPipe *
p =
new BidirMMapPipe();
1745 int retVal = childexec(*
p);
1752#include <sys/time.h>
1758 std::cout <<
"[PARENT]: simple challenge-response test, "
1759 "one child:" << std::endl;
1760 BidirMMapPipe* pipe = spawnChild(simplechild);
1761 for (
int i = 0; i < 5; ++i) {
1762 std::string str(
"What shall we do with a drunken sailor...");
1763 *pipe << str << BidirMMapPipe::flush;
1764 if (!*pipe)
return -1;
1765 std::cout <<
"[PARENT]: wrote: " << str << std::endl;
1767 if (!*pipe)
return -1;
1768 std::cout <<
"[PARENT]: read: " << str << std::endl;
1771 *pipe <<
"" << BidirMMapPipe::flush;
1775 int retVal = pipe->close();
1776 std::cout <<
"[PARENT]: exit status of child: " << retVal <<
1778 if (retVal)
return retVal;
1784 std::cout << std::endl <<
"[PARENT]: polling test, " << nch <<
1785 " children:" << std::endl;
1786 typedef BidirMMapPipe::PollEntry PollEntry;
1788 BidirMMapPipe::PollVector pipes;
1791 for (
unsigned i = 0; i < nch; ++i) {
1792 std::cout <<
"[PARENT]: spawning child " << i << std::endl;
1793 pipes.push_back(PollEntry(spawnChild(randomchild),
1794 BidirMMapPipe::Readable));
1797 std::cout <<
"[PARENT]: waking up children" << std::endl;
1798 for (
unsigned i = 0; i < nch; ++i)
1799 *pipes[i].pipe <<
"" << BidirMMapPipe::flush;
1800 std::cout <<
"[PARENT]: waiting for events on children's pipes" << std::endl;
1802 while (!pipes.empty()) {
1804 int npipes = BidirMMapPipe::poll(pipes, -1);
1806 for (std::vector<PollEntry>::iterator it = pipes.begin();
1807 npipes && pipes.end() != it; ) {
1815 if (it->revents & BidirMMapPipe::Readable) {
1819 std::cout <<
"[PARENT]: Read from pipe " << it->pipe <<
1820 ": " << s << std::endl;
1825 *(it->pipe) <<
"" << BidirMMapPipe::flush;
1830 if (it->revents & (BidirMMapPipe::Error |
1831 BidirMMapPipe::EndOfFile |
1832 BidirMMapPipe::Invalid)) {
1833 std::cerr <<
"[DEBUG]: Event on pipe " << it->pipe <<
1835 ((it->revents & BidirMMapPipe::Readable) ?
" Readable" :
"") <<
1836 ((it->revents & BidirMMapPipe::Writable) ?
" Writable" :
"") <<
1837 ((it->revents & BidirMMapPipe::ReadError) ?
" ReadError" :
"") <<
1838 ((it->revents & BidirMMapPipe::WriteError) ?
" WriteError" :
"") <<
1839 ((it->revents & BidirMMapPipe::ReadEndOfFile) ?
" ReadEndOfFile" :
"") <<
1840 ((it->revents & BidirMMapPipe::WriteEndOfFile) ?
" WriteEndOfFile" :
"") <<
1841 ((it->revents & BidirMMapPipe::ReadInvalid) ?
" ReadInvalid" :
"") <<
1842 ((it->revents & BidirMMapPipe::WriteInvalid) ?
" WriteInvalid" :
"") <<
1845 int retVal = it->pipe->close();
1846 std::cout <<
"[PARENT]: child exit status: " <<
1847 retVal <<
", number of children still alive: " <<
1848 (pipes.size() - 1) << std::endl;
1849 if (retVal)
return retVal;
1851 it = pipes.erase(it);
1859 std::cout << std::endl <<
"[PARENT]: benchmark: round-trip times vs block size" << std::endl;
1860 for (
unsigned i = 0; i <= 24; ++i) {
1861 std::vector<char> s(1 + (1 << i));
1862 std::memset(s,
'A', 1 << i);
1864 const unsigned n = 1 << 7;
1865 double avg = 0., min = 1e42,
max = -1e42;
1866 BidirMMapPipe *pipe = spawnChild(benchchildrtt);
1867 for (
unsigned j =
n; j--; ) {
1869 ::gettimeofday(&
t1, 0);
1870 *pipe << s << BidirMMapPipe::flush;
1871 if (!*pipe || pipe->eof())
break;
1873 if (!*pipe || pipe->eof())
break;
1875 ::gettimeofday(&t2, 0);
1876 t2.tv_sec -=
t1.tv_sec;
1877 t2.tv_usec -=
t1.tv_usec;
1879 if (dt < min) min = dt;
1880 if (dt > max)
max = dt;
1884 *pipe <<
"" << BidirMMapPipe::flush;
1888 avg *= 1e6; min *= 1e6;
max *= 1e6;
1889 int retVal = pipe->close();
1891 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1898 std::cout <<
"block size " << std::setw(9) << (1 << i) <<
1899 " avg " << std::setw(7) << avg <<
" us min " <<
1900 std::setw(7) << min <<
" us max " << std::setw(7) <<
max <<
1901 "us speed " << std::setw(9) <<
1903 " MB/s" << std::endl;
1905 std::cout <<
"[PARENT]: all children had exit code 0" << std::endl;
1909 std::cout << std::endl <<
"[PARENT]: benchmark: raw transfer rate with child as sink" << std::endl;
1910 for (
unsigned i = 0; i <= 24; ++i) {
1911 std::vector<char> s(1 + (1 << i));
1912 std::memset(s,
'A', 1 << i);
1914 const unsigned n = 1 << 7;
1915 double avg = 0., min = 1e42,
max = -1e42;
1916 BidirMMapPipe *pipe = spawnChild(benchchildsink);
1917 for (
unsigned j =
n; j--; ) {
1919 ::gettimeofday(&
t1, 0);
1922 if (!*pipe || pipe->eof())
break;
1924 ::gettimeofday(&t2, 0);
1925 t2.tv_sec -=
t1.tv_sec;
1926 t2.tv_usec -=
t1.tv_usec;
1928 if (dt < min) min = dt;
1929 if (dt > max)
max = dt;
1933 *pipe <<
"" << BidirMMapPipe::flush;
1937 avg *= 1e6; min *= 1e6;
max *= 1e6;
1938 int retVal = pipe->close();
1940 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1944 std::cout <<
"block size " << std::setw(9) << (1 << i) <<
1945 " avg " << std::setw(7) << avg <<
" us min " <<
1946 std::setw(7) << min <<
" us max " << std::setw(7) <<
max <<
1947 "us speed " << std::setw(9) <<
1949 " MB/s" << std::endl;
1951 std::cout <<
"[PARENT]: all children had exit code 0" << std::endl;
1955 std::cout << std::endl <<
"[PARENT]: benchmark: raw transfer rate with child as source" << std::endl;
1957 double avg = 0., min = 1e42,
max = -1e42;
1958 unsigned n = 0, bsz = 0;
1959 BidirMMapPipe *pipe = spawnChild(benchchildsource);
1960 while (*pipe && !pipe->eof()) {
1962 ::gettimeofday(&
t1, 0);
1965 if (!*pipe || pipe->eof())
break;
1967 ::gettimeofday(&t2, 0);
1968 t2.tv_sec -=
t1.tv_sec;
1969 t2.tv_usec -=
t1.tv_usec;
1971 if (std::strlen(s)) {
1973 if (dt < min) min = dt;
1974 if (dt > max)
max = dt;
1976 bsz = std::strlen(s);
1981 avg *= 1e6; min *= 1e6;
max *= 1e6;
1983 std::cout <<
"block size " << std::setw(9) << bsz <<
1984 " avg " << std::setw(7) << avg <<
" us min " <<
1985 std::setw(7) << min <<
" us max " << std::setw(7) <<
1986 max <<
"us speed " << std::setw(9) <<
1988 " MB/s" << std::endl;
1995 int retVal = pipe->close();
1996 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1997 if (retVal)
return retVal;
ROOT::R::TRInterface & Exception()
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
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
Binding & operator=(OUT(*fun)(void))
R__EXTERN TSystem * gSystem
virtual const char * TempDirectory() const
Return a user configured or systemwide directory to create temporary files in.
void(off) SmallVectorTemplateBase< T
void Copy(void *source, void *dest)
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
__device__ AFloat max(AFloat x, AFloat y)
static unsigned long masks[]