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;
117 unsigned short m_pos;
124 Page() : m_next(0), m_size(0), m_pos(0)
128 assert(std::numeric_limits<unsigned short>::max() >=
129 PageChunk::pagesize());
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) :
581 m_cursz(minsz), m_nPgPerGrp(nPgPerGroup)
585 if (PageChunk::pagesize() != PageChunk::physPgSz()) {
586 const unsigned mult =
587 PageChunk::physPgSz() / PageChunk::pagesize();
588 const unsigned desired = nPgPerGroup * PageChunk::pagesize();
590 const unsigned actual = mult *
591 (desired / mult +
bool(desired % mult));
592 const unsigned newPgPerGrp = actual / PageChunk::pagesize();
593 if (BidirMMapPipe::debugflag()) {
594 std::cerr <<
" INFO: In " << __func__ <<
" (" <<
595 __FILE__ <<
", line " << __LINE__ <<
596 "): physical page size " << PageChunk::physPgSz() <<
597 ", subdividing into logical pages of size " <<
598 PageChunk::pagesize() <<
", adjusting nPgPerGroup " <<
599 m_nPgPerGrp <<
" -> " << newPgPerGrp <<
602 assert(newPgPerGrp >= m_nPgPerGrp);
603 m_nPgPerGrp = newPgPerGrp;
605 std::fill(m_szmap, m_szmap + ((maxsz - minsz) / szincr), 0);
608 PagePool::~PagePool()
611 for (ChunkList::iterator it = m_chunks.begin(); m_chunks.end() != it; ++it)
616 void PagePool::zap(Pages&
p)
620 for (ChunkList::iterator it = m_chunks.begin(); m_chunks.end() != it; ++it) {
621 if ((*it)->contains(
p)) {
628 std::fill(m_szmap, m_szmap + ((maxsz - minsz) / szincr), 0);
632 Pages PagePool::pop()
634 if (m_freelist.empty()) {
636 const int sz = nextChunkSz();
637 Chunk *
c =
new Chunk(
this,
638 sz * m_nPgPerGrp * pagesize(), m_nPgPerGrp);
639 m_chunks.push_front(
c);
640 m_freelist.push_back(
c);
644 Chunk*
c = m_freelist.front();
647 if (
c->full()) m_freelist.pop_front();
651 void PagePool::release(PageChunk* chunk)
653 assert(chunk->empty());
655 ChunkList::iterator it = std::find(
656 m_freelist.begin(), m_freelist.end(), chunk);
657 if (m_freelist.end() == it)
658 throw Exception(
"PagePool::release(PageChunk*)", EINVAL);
659 m_freelist.erase(it);
661 it = std::find(m_chunks.begin(), m_chunks.end(), chunk);
662 if (m_chunks.end() == it)
663 throw Exception(
"PagePool::release(PageChunk*)", EINVAL);
665 const unsigned sz = chunk->len() / (pagesize() * m_nPgPerGrp);
670 void PagePool::putOnFreeList(PageChunk* chunk)
672 assert(!chunk->full());
673 m_freelist.push_back(chunk);
676 void PagePool::updateCurSz(
int sz,
int incr)
678 m_szmap[(sz - minsz) / szincr] += incr;
680 for (
int i = (maxsz - minsz) / szincr; i--; ) {
682 m_cursz += i * szincr;
688 int PagePool::nextChunkSz()
const
692 if (m_chunks.empty()) {
700 if (1 != m_chunks.size()) {
710 if (sz > maxsz) sz = maxsz;
711 if (sz < minsz) sz = minsz;
717pthread_mutex_t BidirMMapPipe::s_openpipesmutex = PTHREAD_MUTEX_INITIALIZER;
718std::list<BidirMMapPipe*> BidirMMapPipe::s_openpipes;
719BidirMMapPipe_impl::PagePool* BidirMMapPipe::s_pagepool =
nullptr;
720unsigned BidirMMapPipe::s_pagepoolrefcnt = 0;
721int BidirMMapPipe::s_debugflag = 0;
723BidirMMapPipe_impl::PagePool& BidirMMapPipe::pagepool()
726 s_pagepool =
new BidirMMapPipe_impl::PagePool(TotPages);
730void BidirMMapPipe::teardownall(
void)
732 pthread_mutex_lock(&s_openpipesmutex);
733 while (!s_openpipes.empty()) {
734 BidirMMapPipe *
p = s_openpipes.front();
735 pthread_mutex_unlock(&s_openpipesmutex);
736 if (
p->m_childPid) kill(
p->m_childPid, SIGTERM);
737 p->doClose(
true,
true);
738 pthread_mutex_lock(&s_openpipesmutex);
740 pthread_mutex_unlock(&s_openpipesmutex);
743BidirMMapPipe::BidirMMapPipe(
const BidirMMapPipe&) :
744 m_pages(pagepool().pop())
747 { BidirMMapPipe_impl::Pages
p;
p.swap(m_pages); }
748 if (!s_pagepoolrefcnt) {
750 s_pagepool =
nullptr;
754BidirMMapPipe::BidirMMapPipe(
bool useExceptions,
bool useSocketpair) :
755 m_pages(pagepool().pop()), m_busylist(nullptr), m_freelist(nullptr), m_dirtylist(nullptr),
756 m_inpipe(-1), m_outpipe(-1), m_flags(failbit), m_childPid(0),
757 m_parentPid(::getpid())
761 assert(0 < TotPages && 0 == (TotPages & 1) && TotPages <= 256);
762 int fds[4] = { -1, -1, -1, -1 };
764 static bool firstcall =
true;
765 if (useExceptions) m_flags |= exceptionsbit;
772 if (0 != atexit(BidirMMapPipe::teardownall))
777 for (
unsigned i = 1; i < TotPages; ++i)
778 m_pages[i - 1]->setNext(m_pages[i]);
779 m_pages[PagesPerEnd - 1]->setNext(
nullptr);
780 if (!useSocketpair) {
782 if (0 != ::pipe(&fds[0]))
throw Exception(
"pipe", errno);
783 if (0 != ::pipe(&fds[2]))
throw Exception(
"pipe", errno);
785 if (0 != ::socketpair(AF_UNIX, SOCK_STREAM, 0, &fds[0]))
789 pthread_mutex_lock(&s_openpipesmutex);
791 switch ((m_childPid = ::fork())) {
794 pthread_mutex_unlock(&s_openpipesmutex);
801 if (-1 == ::close(fds[0]) || (-1 == ::close(fds[3]))) {
803 pthread_mutex_unlock(&s_openpipesmutex);
806 fds[0] = fds[3] = -1;
811 if (-1 == ::close(fds[0])) {
813 pthread_mutex_unlock(&s_openpipesmutex);
817 m_inpipe = m_outpipe = fds[1];
821 for (std::list<BidirMMapPipe*>::iterator it = s_openpipes.begin();
822 s_openpipes.end() != it; ) {
823 BidirMMapPipe*
p = *it;
824 it = s_openpipes.erase(it);
825 p->doClose(
true,
true);
827 pagepool().zap(m_pages);
828 s_pagepoolrefcnt = 0;
830 s_pagepool =
nullptr;
831 s_openpipes.push_front(
this);
832 pthread_mutex_unlock(&s_openpipesmutex);
834 m_freelist = m_pages[PagesPerEnd];
837 if (1 != xferraw(m_outpipe, &
c, 1, ::write))
838 throw Exception(
"handshake: xferraw write", EPIPE);
839 if (1 != xferraw(m_inpipe, &
c, 1, ::read))
840 throw Exception(
"handshake: xferraw read", EPIPE);
841 if (
'P' !=
c)
throw Exception(
"handshake", EPIPE);
847 if (-1 == ::close(fds[1]) || -1 == ::close(fds[2])) {
849 pthread_mutex_unlock(&s_openpipesmutex);
852 fds[1] = fds[2] = -1;
857 if (-1 == ::close(fds[1])) {
859 pthread_mutex_unlock(&s_openpipesmutex);
863 m_inpipe = m_outpipe = fds[0];
867 s_openpipes.push_front(
this);
868 pthread_mutex_unlock(&s_openpipesmutex);
870 m_freelist = m_pages[0u];
873 if (1 != xferraw(m_outpipe, &
c, 1, ::write))
874 throw Exception(
"handshake: xferraw write", EPIPE);
875 if (1 != xferraw(m_inpipe, &
c, 1, ::read))
876 throw Exception(
"handshake: xferraw read", EPIPE);
877 if (
'C' !=
c)
throw Exception(
"handshake", EPIPE);
883 if (-1 == ::fcntl(m_outpipe, F_GETFD, &fdflags))
885 fdflags |= FD_CLOEXEC;
886 if (-1 == ::fcntl(m_outpipe, F_SETFD, fdflags))
888 if (m_inpipe != m_outpipe) {
889 if (-1 == ::fcntl(m_inpipe, F_GETFD, &fdflags))
891 fdflags |= FD_CLOEXEC;
892 if (-1 == ::fcntl(m_inpipe, F_SETFD, fdflags))
898 }
catch (BidirMMapPipe::Exception&) {
899 if (0 != m_childPid) kill(m_childPid, SIGTERM);
900 for (
int i = 0; i < 4; ++i)
901 if (-1 != fds[i] && 0 != fds[i]) ::close(fds[i]);
904 BidirMMapPipe_impl::Pages
p;
p.swap(m_pages);
906 if (!--s_pagepoolrefcnt) {
908 s_pagepool =
nullptr;
914int BidirMMapPipe::close()
916 assert(!(m_flags & failbit));
917 return doClose(
false);
920int BidirMMapPipe::doClose(
bool force,
bool holdlock)
922 if (m_flags & failbit)
return 0;
924 if (!force && -1 != m_outpipe && -1 != m_inpipe) flush();
926 if (m_inpipe == m_outpipe) {
927 if (-1 != m_outpipe && !force && -1 == ::shutdown(m_outpipe, SHUT_WR))
931 if (-1 != m_outpipe && -1 == ::close(m_outpipe))
932 if (!force)
throw Exception(
"close", errno);
937 if (!force && -1 != m_inpipe) {
954 while ((err = ::poll(&fds, 1, 1 << 20)) >= 0) {
955 if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))
break;
956 if (fds.revents & POLLIN) {
958 if (1 > ::read(m_inpipe, &
c, 1))
break;
961 }
while (0 > err && EINTR == errno);
965 if (-1 != m_inpipe && -1 == ::close(m_inpipe))
966 if (!force)
throw Exception(
"close", errno);
970 { BidirMMapPipe_impl::Pages
p;
p.swap(m_pages); }
971 if (!--s_pagepoolrefcnt) {
973 s_pagepool =
nullptr;
975 }
catch (std::exception&) {
978 m_busylist = m_freelist = m_dirtylist =
nullptr;
984 tmp = waitpid(m_childPid, &retVal, 0);
985 }
while (-1 == tmp && EINTR == errno);
987 if (!force)
throw Exception(
"waitpid", errno);
991 if (!holdlock) pthread_mutex_lock(&s_openpipesmutex);
992 std::list<BidirMMapPipe*>::iterator it = std::find(
993 s_openpipes.begin(), s_openpipes.end(),
this);
994 if (s_openpipes.end() != it) s_openpipes.erase(it);
995 if (!holdlock) pthread_mutex_unlock(&s_openpipesmutex);
1000BidirMMapPipe::~BidirMMapPipe()
1003BidirMMapPipe::size_type BidirMMapPipe::xferraw(
1004 int fd,
void* addr, size_type
len,
1005 ssize_t (*xferfn)(
int,
void*, std::size_t))
1007 size_type xferred = 0;
1008 unsigned char* buf =
reinterpret_cast<unsigned char*
>(addr);
1010 ssize_t tmp = xferfn(fd, buf,
len);
1016 }
else if (0 == tmp) {
1019 }
else if (-1 == tmp) {
1026 if (xferred)
return xferred;
1030#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
1033 std::cerr <<
" ERROR: In " << __func__ <<
" (" <<
1034 __FILE__ <<
", line " << __LINE__ <<
1035 "): expect transfer to block!" << std::endl;
1041 throw Exception(
"xferraw: unexpected return value from read/write",
1048void BidirMMapPipe::sendpages(Page* plist)
1051 unsigned char pg = m_pages[plist];
1052 if (1 == xferraw(m_outpipe, &pg, 1, ::write)) {
1053 if (BidirMMapPipe_impl::PageChunk::Copy ==
1054 BidirMMapPipe_impl::PageChunk::mmapVariety()) {
1056 for (Page*
p = plist;
p;
p =
p->next()) {
1057 if (
sizeof(Page) +
p->size() !=
1058 xferraw(m_outpipe,
p,
sizeof(Page) +
p->size(),
1060 throw Exception(
"sendpages: short write", EPIPE);
1065 throw Exception(
"sendpages: short write", EPIPE);
1067 }
else { assert(plist); }
1070unsigned BidirMMapPipe::recvpages()
1073 unsigned retVal = 0;
1074 Page *plisthead =
nullptr, *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, *sendlisttail =
nullptr;
1149 p->setNext(
nullptr);
1154 if (blend) blend->setNext(
p);
1155 else m_busylist =
p;
1162 if ((isParent() && m_pages[
p] >= PagesPerEnd) ||
1163 (isChild() && m_pages[
p] < PagesPerEnd)) {
1165 if (!sendlisthead) sendlisthead =
p;
1166 if (sendlisttail) sendlisttail->setNext(
p);
1170 p->setNext(m_freelist);
1180 while ((dp = m_dirtylist) && dp->full()) {
1183 m_dirtylist =
p->next();
1185 p->setNext(
nullptr);
1186 sendlisttail->setNext(
p);
1193 const int nfds = (m_outpipe == m_inpipe) ? 1 : 2;
1194 struct pollfd fds[2];
1195 fds[0].fd = m_outpipe;
1196 fds[0].events = fds[0].revents = 0;
1197 if (m_outpipe != m_inpipe) {
1198 fds[1].fd = m_inpipe;
1199 fds[1].events = fds[1].revents = 0;
1201 fds[0].events |= POLLIN;
1205 retVal = ::poll(fds, nfds, 0);
1206 if (0 > retVal && EINTR == errno)
1211 bool ok = !(fds[0].revents & (POLLERR | POLLNVAL | POLLHUP));
1212 if (m_outpipe != m_inpipe) {
1213 ok = ok && !(fds[1].revents & (POLLERR | POLLNVAL | POLLHUP));
1215 if (ok && fds[0].revents & POLLIN) {
1216 unsigned ret = recvpages();
1217 if (!ret) ok =
false;
1221 if (ok) sendpages(sendlisthead);
1226 throw Exception(
"feedPageLists: poll", errno);
1231void BidirMMapPipe::markPageDirty(Page*
p)
1234 assert(
p == m_freelist);
1236 m_freelist =
p->next();
1237 p->setNext(
nullptr);
1239 Page* dl = m_dirtylist;
1240 while (dl && dl->next()) dl = dl->next();
1241 if (dl) dl->setNext(
p);
1242 else m_dirtylist =
p;
1245BidirMMapPipe::Page* BidirMMapPipe::busypage()
1248 recvpages_nonblock();
1252 while (!(
p = m_busylist))
if (!recvpages())
return nullptr;
1256BidirMMapPipe::Page* BidirMMapPipe::dirtypage()
1259 recvpages_nonblock();
1260 Page*
p = m_dirtylist;
1262 if (
p)
while (
p->next())
p =
p->next();
1263 if (!
p ||
p->full()) {
1265 while (!(
p = m_freelist))
if (!recvpages())
return nullptr;
1271void BidirMMapPipe::flush()
1272{
return doFlush(
true); }
1274void BidirMMapPipe::doFlush(
bool forcePartialPages)
1276 assert(!(m_flags & failbit));
1278 Page *flushlisthead =
nullptr, *flushlisttail =
nullptr;
1279 while (m_dirtylist) {
1280 Page*
p = m_dirtylist;
1281 if (!forcePartialPages && !
p->full())
break;
1283 m_dirtylist =
p->next();
1284 p->setNext(
nullptr);
1286 if (!flushlisthead) flushlisthead =
p;
1287 if (flushlisttail) flushlisttail->setNext(
p);
1290 if (flushlisthead) sendpages(flushlisthead);
1293void BidirMMapPipe::purge()
1295 assert(!(m_flags & failbit));
1298 Page *
l = m_busylist;
1299 while (
l &&
l->next())
l =
l->next();
1300 if (
l)
l->setNext(m_dirtylist);
1301 else m_busylist = m_dirtylist;
1304 for (Page*
p = m_busylist;
p;
p =
p->next())
p->size() = 0;
1306 if (m_busylist) feedPageLists(m_busylist);
1307 m_busylist = m_dirtylist =
nullptr;
1310BidirMMapPipe::size_type BidirMMapPipe::bytesReadableNonBlocking()
1314 recvpages_nonblock();
1315 size_type retVal = 0;
1316 for (Page*
p = m_busylist;
p;
p =
p->next())
1317 retVal +=
p->size() -
p->pos();
1321BidirMMapPipe::size_type BidirMMapPipe::bytesWritableNonBlocking()
1325 recvpages_nonblock();
1328 bool couldwrite =
false;
1332 fds.events = POLLOUT;
1336 retVal = ::poll(&fds, 1, 0);
1338 if (EINTR == errno)
continue;
1339 throw Exception(
"bytesWritableNonBlocking: poll", errno);
1341 if (1 == retVal && fds.revents & POLLOUT &&
1342 !(fds.revents & (POLLNVAL | POLLERR | POLLHUP)))
1348 size_type retVal = 0;
1349 unsigned npages = 0;
1351 for (Page*
p = m_dirtylist;
p;
p =
p->next()) {
1355 retVal +=
p->free();
1356 if (npages >= FlushThresh && !couldwrite)
break;
1359 for (Page*
p = m_freelist;
p && (!m_dirtylist ||
1360 npages < FlushThresh || couldwrite);
p =
p->next()) {
1362 retVal += Page::capacity();
1367BidirMMapPipe::size_type BidirMMapPipe::read(
void* addr, size_type sz)
1369 assert(!(m_flags & failbit));
1370 size_type nread = 0;
1371 unsigned char *ap =
reinterpret_cast<unsigned char*
>(addr);
1375 Page*
p = busypage();
1380 unsigned char* pp =
p->begin() +
p->pos();
1381 size_type csz = std::min(size_type(
p->remaining()), sz);
1382 std::copy(pp, pp + csz, ap);
1387 assert(
p->size() >=
p->pos());
1388 if (
p->size() ==
p->pos()) {
1390 m_busylist =
p->next();
1391 p->setNext(
nullptr);
1397 m_flags |= rderrbit;
1398 if (m_flags & exceptionsbit)
throw;
1403BidirMMapPipe::size_type BidirMMapPipe::write(
const void* addr, size_type sz)
1405 assert(!(m_flags & failbit));
1406 size_type written = 0;
1407 const unsigned char *ap =
reinterpret_cast<const unsigned char*
>(addr);
1411 Page*
p = dirtypage();
1416 unsigned char* pp =
p->begin() +
p->size();
1417 size_type csz = std::min(size_type(
p->free()), sz);
1418 std::copy(ap, ap + csz, pp);
1423 assert(
p->capacity() >=
p->size());
1427 if (lenPageList(m_dirtylist) >= FlushThresh)
1432 m_flags |= wrerrbit;
1433 if (m_flags & exceptionsbit)
throw;
1438int BidirMMapPipe::poll(BidirMMapPipe::PollVector& pipes,
int timeout)
1443 bool canskiptimeout =
false;
1444 std::vector<unsigned>
masks(pipes.size(), ~(Readable | Writable));
1445 std::vector<unsigned>::iterator mit =
masks.begin();
1446 for (PollVector::iterator it = pipes.begin(); pipes.end() != it;
1448 PollEntry& pe = *it;
1453 canskiptimeout =
true;
1457 if (pe.pipe->closed()) pe.revents |= Invalid;
1459 if (pe.pipe->bad()) pe.revents |=
Error;
1461 if (pe.pipe->eof()) pe.revents |= EndOfFile;
1463 if (pe.events & Readable) {
1465 if (pe.pipe->m_busylist) pe.revents |= Readable;
1468 if (pe.events & Writable) {
1470 if (pe.pipe->m_freelist) {
1471 pe.revents |= Writable;
1473 Page *dl = pe.pipe->m_dirtylist;
1474 while (dl && dl->next()) dl = dl->next();
1475 if (dl && dl->pos() < Page::capacity())
1476 pe.revents |= Writable;
1479 if (pe.revents) canskiptimeout =
true;
1482 std::vector<pollfd> fds;
1483 fds.reserve(2 * pipes.size());
1484 std::map<int, PollEntry*> fds2pipes;
1485 for (PollVector::const_iterator it = pipes.begin();
1486 pipes.end() != it; ++it) {
1487 const PollEntry& pe = *it;
1489 fds2pipes.insert(std::make_pair((tmp.fd = pe.pipe->m_inpipe),
1490 const_cast<PollEntry*
>(&pe)));
1491 tmp.events = tmp.revents = 0;
1494 tmp.events |= POLLIN;
1495 if (pe.pipe->m_outpipe != tmp.fd) {
1498 fds2pipes.insert(std::make_pair(
1499 unsigned(tmp.fd = pe.pipe->m_outpipe),
1500 const_cast<PollEntry*
>(&pe)));
1504 if (pe.events & Writable) tmp.events |= POLLOUT;
1510 retVal = ::poll(&fds[0], fds.size(), canskiptimeout ? 0 : timeout);
1512 if (EINTR == errno)
continue;
1518 for (std::vector<pollfd>::iterator it = fds.begin();
1519 fds.end() != it; ++it) {
1523 PollEntry& pe = *fds2pipes[fe.fd];
1525 if (fe.revents & POLLNVAL && fe.fd == pe.pipe->m_inpipe)
1526 pe.revents |= ReadInvalid;
1527 if (fe.revents & POLLNVAL && fe.fd == pe.pipe->m_outpipe)
1528 pe.revents |= WriteInvalid;
1529 if (fe.revents & POLLERR && fe.fd == pe.pipe->m_inpipe)
1530 pe.revents |= ReadError;
1531 if (fe.revents & POLLERR && fe.fd == pe.pipe->m_outpipe)
1532 pe.revents |= WriteError;
1533 if (fe.revents & POLLHUP && fe.fd == pe.pipe->m_inpipe)
1534 pe.revents |= ReadEndOfFile;
1535 if (fe.revents & POLLHUP && fe.fd == pe.pipe->m_outpipe)
1536 pe.revents |= WriteEndOfFile;
1537 if ((fe.revents & POLLIN) && fe.fd == pe.pipe->m_inpipe &&
1538 !(fe.revents & (POLLNVAL | POLLERR))) {
1541 if (0 == pe.pipe->recvpages())
continue;
1544 int tmp = ::poll(&fe, 1, 0);
1545 if (tmp > 0)
goto oncemore;
1547 if (EINTR == errno)
continue;
1553 if (pe.pipe->m_busylist) pe.revents |= Readable;
1554 if (fe.revents & POLLOUT && fe.fd == pe.pipe->m_outpipe) {
1555 if (pe.pipe->m_freelist) {
1556 pe.revents |= Writable;
1558 Page *dl = pe.pipe->m_dirtylist;
1559 while (dl && dl->next()) dl = dl->next();
1560 if (dl && dl->pos() < Page::capacity())
1561 pe.revents |= Writable;
1567 mit =
masks.begin();
1568 for (PollVector::iterator it = pipes.begin();
1569 pipes.end() != it; ++it, ++mit)
1570 if ((it->revents &= *mit)) ++npipes;
1574BidirMMapPipe& BidirMMapPipe::operator<<(
const char* str)
1576 size_t sz = std::strlen(str);
1578 if (sz) write(str, sz);
1582BidirMMapPipe& BidirMMapPipe::operator>>(
char* (&str))
1586 if (good() && !eof()) {
1587 str =
reinterpret_cast<char*
>(std::realloc(str, sz + 1));
1588 if (!str)
throw Exception(
"realloc", errno);
1589 if (sz) read(str, sz);
1595BidirMMapPipe& BidirMMapPipe::operator<<(
const std::string& str)
1597 size_t sz = str.size();
1599 write(str.data(), sz);
1603BidirMMapPipe& BidirMMapPipe::operator>>(std::string& str)
1608 if (good() && !eof()) {
1610 for (
unsigned char c; sz--; str.push_back(
c)) *
this >>
c;
1617#ifdef TEST_BIDIRMMAPPIPE
1620int simplechild(BidirMMapPipe& pipe)
1623 while (pipe.good() && !pipe.eof()) {
1627 if (!pipe)
return -1;
1628 if (pipe.eof())
break;
1630 std::cout <<
"[CHILD] : read: " << str << std::endl;
1631 str =
"... early in the morning?";
1633 pipe << str << BidirMMapPipe::flush;
1635 if (str.empty())
break;
1636 if (!pipe)
return -1;
1637 if (pipe.eof())
break;
1638 std::cout <<
"[CHILD] : wrote: " << str << std::endl;
1645int randomchild(BidirMMapPipe& pipe)
1648 ::srand48(::getpid());
1656 for (
int i = 0; i < 5; ++i) {
1658 ::usleep(
int(1e6 * ::drand48()));
1659 std::ostringstream buf;
1660 buf <<
"child pid " << ::getpid() <<
" sends message " << i;
1661 std::string str = buf.str();
1662 std::cout <<
"[CHILD] : " << str << std::endl;
1663 pipe << str << BidirMMapPipe::flush;
1664 if (!pipe)
return -1;
1665 if (pipe.eof())
break;
1668 pipe <<
"" << BidirMMapPipe::flush;
1676int benchchildrtt(BidirMMapPipe& pipe)
1681 while (pipe && !pipe.eof()) {
1688 if (pipe.eof())
break;
1689 pipe << str << BidirMMapPipe::flush;
1691 if (!std::strlen(str))
break;
1698int benchchildsink(BidirMMapPipe& pipe)
1702 while (pipe && !pipe.eof()) {
1704 if (!std::strlen(str))
break;
1706 pipe <<
"" << BidirMMapPipe::flush;
1712int benchchildsource(BidirMMapPipe& pipe)
1716 for (
unsigned i = 0; i <= 24; ++i) {
1717 str =
reinterpret_cast<char*
>(std::realloc(str, (1 << i) + 1));
1718 std::memset(str,
'4', 1 << i);
1720 for (
unsigned j = 0; j < 1 << 7; ++j) {
1722 if (!pipe || pipe.eof()) {
1729 pipe <<
"" << BidirMMapPipe::flush;
1732 pipe <<
"" << BidirMMapPipe::flush;
1738BidirMMapPipe* spawnChild(
int (*childexec)(BidirMMapPipe&))
1741 BidirMMapPipe *
p =
new BidirMMapPipe();
1743 int retVal = childexec(*
p);
1750#include <sys/time.h>
1756 std::cout <<
"[PARENT]: simple challenge-response test, "
1757 "one child:" << std::endl;
1758 BidirMMapPipe* pipe = spawnChild(simplechild);
1759 for (
int i = 0; i < 5; ++i) {
1760 std::string str(
"What shall we do with a drunken sailor...");
1761 *pipe << str << BidirMMapPipe::flush;
1762 if (!*pipe)
return -1;
1763 std::cout <<
"[PARENT]: wrote: " << str << std::endl;
1765 if (!*pipe)
return -1;
1766 std::cout <<
"[PARENT]: read: " << str << std::endl;
1769 *pipe <<
"" << BidirMMapPipe::flush;
1773 int retVal = pipe->close();
1774 std::cout <<
"[PARENT]: exit status of child: " << retVal <<
1776 if (retVal)
return retVal;
1782 std::cout << std::endl <<
"[PARENT]: polling test, " << nch <<
1783 " children:" << std::endl;
1784 typedef BidirMMapPipe::PollEntry PollEntry;
1786 BidirMMapPipe::PollVector pipes;
1789 for (
unsigned i = 0; i < nch; ++i) {
1790 std::cout <<
"[PARENT]: spawning child " << i << std::endl;
1791 pipes.push_back(PollEntry(spawnChild(randomchild),
1792 BidirMMapPipe::Readable));
1795 std::cout <<
"[PARENT]: waking up children" << std::endl;
1796 for (
unsigned i = 0; i < nch; ++i)
1797 *pipes[i].pipe <<
"" << BidirMMapPipe::flush;
1798 std::cout <<
"[PARENT]: waiting for events on children's pipes" << std::endl;
1800 while (!pipes.empty()) {
1802 int npipes = BidirMMapPipe::poll(pipes, -1);
1804 for (std::vector<PollEntry>::iterator it = pipes.begin();
1805 npipes && pipes.end() != it; ) {
1813 if (it->revents & BidirMMapPipe::Readable) {
1817 std::cout <<
"[PARENT]: Read from pipe " << it->pipe <<
1818 ": " << s << std::endl;
1823 *(it->pipe) <<
"" << BidirMMapPipe::flush;
1828 if (it->revents & (BidirMMapPipe::Error |
1829 BidirMMapPipe::EndOfFile |
1830 BidirMMapPipe::Invalid)) {
1831 std::cerr <<
"[DEBUG]: Event on pipe " << it->pipe <<
1833 ((it->revents & BidirMMapPipe::Readable) ?
" Readable" :
"") <<
1834 ((it->revents & BidirMMapPipe::Writable) ?
" Writable" :
"") <<
1835 ((it->revents & BidirMMapPipe::ReadError) ?
" ReadError" :
"") <<
1836 ((it->revents & BidirMMapPipe::WriteError) ?
" WriteError" :
"") <<
1837 ((it->revents & BidirMMapPipe::ReadEndOfFile) ?
" ReadEndOfFile" :
"") <<
1838 ((it->revents & BidirMMapPipe::WriteEndOfFile) ?
" WriteEndOfFile" :
"") <<
1839 ((it->revents & BidirMMapPipe::ReadInvalid) ?
" ReadInvalid" :
"") <<
1840 ((it->revents & BidirMMapPipe::WriteInvalid) ?
" WriteInvalid" :
"") <<
1843 int retVal = it->pipe->close();
1844 std::cout <<
"[PARENT]: child exit status: " <<
1845 retVal <<
", number of children still alive: " <<
1846 (pipes.size() - 1) << std::endl;
1847 if (retVal)
return retVal;
1849 it = pipes.erase(it);
1857 std::cout << std::endl <<
"[PARENT]: benchmark: round-trip times vs block size" << std::endl;
1858 for (
unsigned i = 0; i <= 24; ++i) {
1859 std::vector<char> s(1 + (1 << i));
1860 std::memset(s,
'A', 1 << i);
1862 const unsigned n = 1 << 7;
1863 double avg = 0.,
min = 1e42,
max = -1e42;
1864 BidirMMapPipe *pipe = spawnChild(benchchildrtt);
1865 for (
unsigned j =
n; j--; ) {
1867 ::gettimeofday(&
t1, 0);
1868 *pipe << s << BidirMMapPipe::flush;
1869 if (!*pipe || pipe->eof())
break;
1871 if (!*pipe || pipe->eof())
break;
1873 ::gettimeofday(&t2, 0);
1874 t2.tv_sec -=
t1.tv_sec;
1875 t2.tv_usec -=
t1.tv_usec;
1877 if (dt < min)
min = dt;
1878 if (dt > max)
max = dt;
1882 *pipe <<
"" << BidirMMapPipe::flush;
1886 avg *= 1e6;
min *= 1e6;
max *= 1e6;
1887 int retVal = pipe->close();
1889 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1896 std::cout <<
"block size " << std::setw(9) << (1 << i) <<
1897 " avg " << std::setw(7) << avg <<
" us min " <<
1898 std::setw(7) <<
min <<
" us max " << std::setw(7) <<
max <<
1899 "us speed " << std::setw(9) <<
1901 " MB/s" << std::endl;
1903 std::cout <<
"[PARENT]: all children had exit code 0" << std::endl;
1907 std::cout << std::endl <<
"[PARENT]: benchmark: raw transfer rate with child as sink" << std::endl;
1908 for (
unsigned i = 0; i <= 24; ++i) {
1909 std::vector<char> s(1 + (1 << i));
1910 std::memset(s,
'A', 1 << i);
1912 const unsigned n = 1 << 7;
1913 double avg = 0.,
min = 1e42,
max = -1e42;
1914 BidirMMapPipe *pipe = spawnChild(benchchildsink);
1915 for (
unsigned j =
n; j--; ) {
1917 ::gettimeofday(&
t1, 0);
1920 if (!*pipe || pipe->eof())
break;
1922 ::gettimeofday(&t2, 0);
1923 t2.tv_sec -=
t1.tv_sec;
1924 t2.tv_usec -=
t1.tv_usec;
1926 if (dt < min)
min = dt;
1927 if (dt > max)
max = dt;
1931 *pipe <<
"" << BidirMMapPipe::flush;
1935 avg *= 1e6;
min *= 1e6;
max *= 1e6;
1936 int retVal = pipe->close();
1938 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1942 std::cout <<
"block size " << std::setw(9) << (1 << i) <<
1943 " avg " << std::setw(7) << avg <<
" us min " <<
1944 std::setw(7) <<
min <<
" us max " << std::setw(7) <<
max <<
1945 "us speed " << std::setw(9) <<
1947 " MB/s" << std::endl;
1949 std::cout <<
"[PARENT]: all children had exit code 0" << std::endl;
1953 std::cout << std::endl <<
"[PARENT]: benchmark: raw transfer rate with child as source" << std::endl;
1955 double avg = 0.,
min = 1e42,
max = -1e42;
1956 unsigned n = 0, bsz = 0;
1957 BidirMMapPipe *pipe = spawnChild(benchchildsource);
1958 while (*pipe && !pipe->eof()) {
1960 ::gettimeofday(&
t1, 0);
1963 if (!*pipe || pipe->eof())
break;
1965 ::gettimeofday(&t2, 0);
1966 t2.tv_sec -=
t1.tv_sec;
1967 t2.tv_usec -=
t1.tv_usec;
1969 if (std::strlen(s)) {
1971 if (dt < min)
min = dt;
1972 if (dt > max)
max = dt;
1974 bsz = std::strlen(s);
1979 avg *= 1e6;
min *= 1e6;
max *= 1e6;
1981 std::cout <<
"block size " << std::setw(9) << bsz <<
1982 " avg " << std::setw(7) << avg <<
" us min " <<
1983 std::setw(7) <<
min <<
" us max " << std::setw(7) <<
1984 max <<
"us speed " << std::setw(9) <<
1986 " MB/s" << std::endl;
1993 int retVal = pipe->close();
1994 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1995 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)
double min(double x, double y)
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[]