tools/jprof/stub/libmalloc.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 // vim:cindent:sw=4:et:ts=8:
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 // The linux glibc hides part of sigaction if _POSIX_SOURCE is defined
     8 #if defined(linux)
     9 #undef _POSIX_SOURCE
    10 #undef _SVID_SOURCE
    11 #ifndef _GNU_SOURCE
    12 #define _GNU_SOURCE
    13 #endif
    14 #endif
    16 #include <errno.h>
    17 #if defined(linux)
    18 #include <linux/rtc.h>
    19 #include <pthread.h>
    20 #endif
    21 #include <unistd.h>
    22 #include <fcntl.h>
    23 #include <stdio.h>
    24 #include <stdlib.h>
    25 #include <signal.h>
    26 #include <sys/time.h>
    27 #include <sys/types.h>
    28 #include <sys/ioctl.h>
    29 #include <sys/stat.h>
    30 #include <sys/syscall.h>
    31 #include <ucontext.h>
    32 #include <execinfo.h>
    34 #include "libmalloc.h"
    35 #include "jprof.h"
    36 #include <string.h>
    37 #include <errno.h>
    38 #include <dlfcn.h>
    40 // Must define before including jprof.h
    41 void *moz_xmalloc(size_t size)
    42 {
    43     return malloc(size);
    44 }
    46 void moz_xfree(void *mem)
    47 {
    48     free(mem);
    49 }
    51 #ifdef NTO
    52 #include <sys/link.h>
    53 extern r_debug _r_debug;
    54 #else
    55 #include <link.h>
    56 #endif
    58 #define USE_GLIBC_BACKTRACE 1
    59 // To debug, use #define JPROF_STATIC
    60 #define JPROF_STATIC //static
    62 static int gLogFD = -1;
    63 static pthread_t main_thread;
    65 static void startSignalCounter(unsigned long millisec);
    66 static int enableRTCSignals(bool enable);
    69 //----------------------------------------------------------------------
    70 // replace use of atexit()
    72 static void DumpAddressMap();
    74 struct JprofShutdown {
    75     JprofShutdown() {}
    76     ~JprofShutdown() {
    77         DumpAddressMap();
    78     }
    79 };
    81 static void RegisterJprofShutdown() {
    82     // This instanciates the dummy class above, and will trigger the class
    83     // destructor when libxul is unloaded. This is equivalent to atexit(),
    84     // but gracefully handles dlclose().
    85     static JprofShutdown t;
    86 }
    88 #if defined(i386) || defined(_i386) || defined(__x86_64__)
    89 JPROF_STATIC void CrawlStack(malloc_log_entry* me,
    90                              void* stack_top, void* top_instr_ptr)
    91 {
    92 #if USE_GLIBC_BACKTRACE
    93     // This probably works on more than x86!  But we need a way to get the
    94     // top instruction pointer, which is kindof arch-specific
    95     void *array[500];
    96     int cnt, i;
    97     u_long numpcs = 0;
    98     bool tracing = false;
   100     // This is from glibc.  A more generic version might use
   101     // libunwind and/or CaptureStackBackTrace() on Windows
   102     cnt = backtrace(&array[0],sizeof(array)/sizeof(array[0]));
   104     // StackHook->JprofLog->CrawlStack
   105     // Then we have sigaction, which replaced top_instr_ptr
   106     array[3] = top_instr_ptr;
   107     for (i = 3; i < cnt; i++)
   108     {
   109         me->pcs[numpcs++] = (char *) array[i];
   110     }
   111     me->numpcs = numpcs;
   113 #else
   114   // original code - this breaks on many platforms
   115   void **bp;
   116 #if defined(__i386)
   117   __asm__( "movl %%ebp, %0" : "=g"(bp));
   118 #elif defined(__x86_64__)
   119   __asm__( "movq %%rbp, %0" : "=g"(bp));
   120 #else
   121   // It would be nice if this worked uniformly, but at least on i386 and
   122   // x86_64, it stopped working with gcc 4.1, because it points to the
   123   // end of the saved registers instead of the start.
   124   bp = __builtin_frame_address(0);
   125 #endif
   126   u_long numpcs = 0;
   127   bool tracing = false;
   129   me->pcs[numpcs++] = (char*) top_instr_ptr;
   131   while (numpcs < MAX_STACK_CRAWL) {
   132     void** nextbp = (void**) *bp++;
   133     void* pc = *bp;
   134     if (nextbp < bp) {
   135       break;
   136     }
   137     if (tracing) {
   138       // Skip the signal handling.
   139       me->pcs[numpcs++] = (char*) pc;
   140     }
   141     else if (pc == top_instr_ptr) {
   142       tracing = true;
   143     }
   144     bp = nextbp;
   145   }
   146   me->numpcs = numpcs;
   147 #endif
   148 }
   149 #endif
   151 //----------------------------------------------------------------------
   153 static int rtcHz;
   154 static int rtcFD = -1;
   155 static bool circular = false;
   157 #if defined(linux) || defined(NTO)
   158 static void DumpAddressMap()
   159 {
   160   // Turn off the timer so we don't get interrupts during shutdown
   161 #if defined(linux)
   162   if (rtcHz) {
   163     enableRTCSignals(false);
   164   } else
   165 #endif
   166   {
   167     startSignalCounter(0);
   168   }
   170   int mfd = open(M_MAPFILE, O_CREAT|O_WRONLY|O_TRUNC, 0666);
   171   if (mfd >= 0) {
   172     malloc_map_entry mme;
   173     link_map* map = _r_debug.r_map;
   174     while (nullptr != map) {
   175       if (map->l_name && *map->l_name) {
   176 	mme.nameLen = strlen(map->l_name);
   177 	mme.address = map->l_addr;
   178 	write(mfd, &mme, sizeof(mme));
   179 	write(mfd, map->l_name, mme.nameLen);
   180 #if 0
   181 	write(1, map->l_name, mme.nameLen);
   182 	write(1, "\n", 1);
   183 #endif
   184       }
   185       map = map->l_next;
   186     }
   187     close(mfd);
   188   }
   189 }
   190 #endif
   192 static bool was_paused = true;
   194 JPROF_STATIC void JprofBufferDump();
   195 JPROF_STATIC void JprofBufferClear();
   197 static void ClearProfilingHook(int signum)
   198 {
   199     if (circular) {
   200         JprofBufferClear();
   201         puts("Jprof: cleared circular buffer.");
   202     }
   203 }
   205 static void EndProfilingHook(int signum)
   206 {
   207     if (circular)
   208         JprofBufferDump();
   210     DumpAddressMap();
   211     was_paused = true;
   212     puts("Jprof: profiling paused.");
   213 }
   217 //----------------------------------------------------------------------
   218 // proper usage would be a template, including the function to find the
   219 // size of an entry, or include a size header explicitly to each entry.
   220 #if defined(linux)
   221 #define DUMB_LOCK()   pthread_mutex_lock(&mutex);
   222 #define DUMB_UNLOCK() pthread_mutex_unlock(&mutex);
   223 #else
   224 #define DUMB_LOCK()   FIXME()
   225 #define DUMB_UNLOCK() FIXME()
   226 #endif
   229 class DumbCircularBuffer
   230 {
   231 public:
   232     DumbCircularBuffer(size_t init_buffer_size) {
   233         used = 0;
   234         buffer_size = init_buffer_size;
   235         buffer = (unsigned char *) malloc(buffer_size);
   236         head = tail = buffer;
   238 #if defined(linux)
   239         pthread_mutexattr_t mAttr;
   240         pthread_mutexattr_settype(&mAttr, PTHREAD_MUTEX_RECURSIVE_NP);
   241         pthread_mutex_init(&mutex, &mAttr);
   242         pthread_mutexattr_destroy(&mAttr);
   243 #endif
   244     }
   245     ~DumbCircularBuffer() {
   246         free(buffer);
   247 #if defined(linux)
   248         pthread_mutex_destroy (&mutex);
   249 #endif
   250     }
   252     void clear() {
   253         DUMB_LOCK();
   254         head = tail;
   255         used = 0;
   256         DUMB_UNLOCK();
   257     }
   259     bool empty() {
   260         return head == tail;
   261     }
   263     size_t space_available() {
   264         size_t result;
   265         DUMB_LOCK();
   266         if (tail > head)
   267             result = buffer_size - (tail-head) - 1;
   268         else
   269             result = head-tail - 1;
   270         DUMB_UNLOCK();
   271         return result;
   272     }
   274     void drop(size_t size) {
   275         // assumes correctness!
   276         DUMB_LOCK();
   277         head += size;
   278         if (head >= &buffer[buffer_size])
   279             head -= buffer_size;
   280         used--;
   281         DUMB_UNLOCK();
   282     }
   284     bool insert(void *data, size_t size) {
   285         // can fail if not enough space in the entire buffer
   286         DUMB_LOCK();
   287         if (space_available() < size)
   288             return false;
   290         size_t max_without_wrap = &buffer[buffer_size] - tail;
   291         size_t initial = size > max_without_wrap ? max_without_wrap : size;
   292 #if DEBUG_CIRCULAR
   293         fprintf(stderr,"insert(%d): max_without_wrap %d, size %d, initial %d\n",used,max_without_wrap,size,initial);
   294 #endif
   295         memcpy(tail,data,initial);
   296         tail += initial;
   297         data = ((char *)data)+initial;
   298         size -= initial;
   299         if (size != 0) {
   300 #if DEBUG_CIRCULAR
   301             fprintf(stderr,"wrapping by %d bytes\n",size);
   302 #endif
   303             memcpy(buffer,data,size);
   304             tail = &(((unsigned char *)buffer)[size]);
   305         }
   307         used++;
   308         DUMB_UNLOCK();
   310         return true;
   311     }
   313     // for external access to the buffer (saving)
   314     void lock() {
   315         DUMB_LOCK();
   316     }
   318     void unlock() {
   319         DUMB_UNLOCK();
   320     }
   322     // XXX These really shouldn't be public...
   323     unsigned char *head;
   324     unsigned char *tail;
   325     unsigned int used;
   326     unsigned char *buffer;
   327     size_t buffer_size;
   329 private:
   330     pthread_mutex_t mutex;
   331 };
   333 class DumbCircularBuffer *JprofBuffer;
   335 JPROF_STATIC void
   336 JprofBufferInit(size_t size)
   337 {
   338     JprofBuffer = new DumbCircularBuffer(size);
   339 }
   341 JPROF_STATIC void
   342 JprofBufferClear()
   343 {
   344     fprintf(stderr,"Told to clear JPROF circular buffer\n");
   345     JprofBuffer->clear();
   346 }
   348 JPROF_STATIC size_t
   349 JprofEntrySizeof(malloc_log_entry *me)
   350 {
   351     return offsetof(malloc_log_entry, pcs) + me->numpcs*sizeof(char*);
   352 }
   354 JPROF_STATIC void
   355 JprofBufferAppend(malloc_log_entry *me)
   356 {
   357     size_t size = JprofEntrySizeof(me);
   359     do {
   360         while (JprofBuffer->space_available() < size &&
   361                JprofBuffer->used > 0) {
   362 #if DEBUG_CIRCULAR
   363             fprintf(stderr,"dropping entry: %d in use, %d free, need %d, size_to_free = %d\n",
   364                     JprofBuffer->used,JprofBuffer->space_available(),size,JprofEntrySizeof((malloc_log_entry *) JprofBuffer->head));
   365 #endif
   366             JprofBuffer->drop(JprofEntrySizeof((malloc_log_entry *) JprofBuffer->head));
   367         }
   368         if (JprofBuffer->space_available() < size)
   369             return;
   371     } while (!JprofBuffer->insert(me,size));
   372 }
   374 JPROF_STATIC void
   375 JprofBufferDump()
   376 {
   377     JprofBuffer->lock();
   378 #if DEBUG_CIRCULAR
   379     fprintf(stderr,"dumping JP_CIRCULAR buffer, %d of %d bytes\n",
   380             JprofBuffer->tail > JprofBuffer->head ? 
   381               JprofBuffer->tail - JprofBuffer->head :
   382               JprofBuffer->buffer_size + JprofBuffer->tail - JprofBuffer->head,
   383             JprofBuffer->buffer_size);
   384 #endif
   385     if (JprofBuffer->tail >= JprofBuffer->head) {
   386         write(gLogFD, JprofBuffer->head, JprofBuffer->tail - JprofBuffer->head);
   387     } else {
   388         write(gLogFD, JprofBuffer->head, &(JprofBuffer->buffer[JprofBuffer->buffer_size]) - JprofBuffer->head);
   389         write(gLogFD, JprofBuffer->buffer, JprofBuffer->tail - JprofBuffer->buffer);
   390     }
   391     JprofBuffer->clear();
   392     JprofBuffer->unlock();
   393 }
   395 //----------------------------------------------------------------------
   397 JPROF_STATIC void
   398 JprofLog(u_long aTime, void* stack_top, void* top_instr_ptr)
   399 {
   400   // Static is simply to make debugging tolerable
   401   static malloc_log_entry me;
   403   me.delTime = aTime;
   404   me.thread = syscall(SYS_gettid); //gettid();
   405   if (was_paused) {
   406       me.flags = JP_FIRST_AFTER_PAUSE;
   407       was_paused = 0;
   408   } else {
   409       me.flags = 0;
   410   }
   412   CrawlStack(&me, stack_top, top_instr_ptr);
   414 #ifndef NTO
   415   if (circular) {
   416       JprofBufferAppend(&me);
   417   } else {
   418       write(gLogFD, &me, JprofEntrySizeof(&me));
   419   }
   420 #else
   421       printf("Neutrino is missing the pcs member of malloc_log_entry!! \n");
   422 #endif
   423 }
   425 static int realTime;
   427 /* Lets interrupt at 10 Hz.  This is so my log files don't get too large.
   428  * This can be changed to a faster value latter.  This timer is not
   429  * programmed to reset, even though it is capable of doing so.  This is
   430  * to keep from getting interrupts from inside of the handler.
   431 */
   432 static void startSignalCounter(unsigned long millisec)
   433 {
   434     struct itimerval tvalue;
   436     tvalue.it_interval.tv_sec = 0;
   437     tvalue.it_interval.tv_usec = 0;
   438     tvalue.it_value.tv_sec = millisec/1000;
   439     tvalue.it_value.tv_usec = (millisec%1000)*1000;
   441     if (realTime) {
   442         setitimer(ITIMER_REAL, &tvalue, nullptr);
   443     } else {
   444         setitimer(ITIMER_PROF, &tvalue, nullptr);
   445     }
   446 }
   448 static long timerMilliSec = 50;
   450 #if defined(linux)
   451 static int setupRTCSignals(int hz, struct sigaction *sap)
   452 {
   453     /* global */ rtcFD = open("/dev/rtc", O_RDONLY);
   454     if (rtcFD < 0) {
   455         perror("JPROF_RTC setup: open(\"/dev/rtc\", O_RDONLY)");
   456         return 0;
   457     }
   459     if (sigaction(SIGIO, sap, nullptr) == -1) {
   460         perror("JPROF_RTC setup: sigaction(SIGIO)");
   461         return 0;
   462     }
   464     if (ioctl(rtcFD, RTC_IRQP_SET, hz) == -1) {
   465         perror("JPROF_RTC setup: ioctl(/dev/rtc, RTC_IRQP_SET, $JPROF_RTC_HZ)");
   466         return 0;
   467     }
   469     if (ioctl(rtcFD, RTC_PIE_ON, 0) == -1) {
   470         perror("JPROF_RTC setup: ioctl(/dev/rtc, RTC_PIE_ON)");
   471         return 0;
   472     }
   474     if (fcntl(rtcFD, F_SETSIG, 0) == -1) {
   475         perror("JPROF_RTC setup: fcntl(/dev/rtc, F_SETSIG, 0)");
   476         return 0;
   477     }
   479     if (fcntl(rtcFD, F_SETOWN, getpid()) == -1) {
   480         perror("JPROF_RTC setup: fcntl(/dev/rtc, F_SETOWN, getpid())");
   481         return 0;
   482     }
   484     return 1;
   485 }
   487 static int enableRTCSignals(bool enable)
   488 {
   489     static bool enabled = false;
   490     if (enabled == enable) {
   491         return 0;
   492     }
   493     enabled = enable;
   495     int flags = fcntl(rtcFD, F_GETFL);
   496     if (flags < 0) {
   497         perror("JPROF_RTC setup: fcntl(/dev/rtc, F_GETFL)");
   498         return 0;
   499     }
   501     if (enable) {
   502         flags |= FASYNC;
   503     } else {
   504         flags &= ~FASYNC;
   505     }
   507     if (fcntl(rtcFD, F_SETFL, flags) == -1) {
   508         if (enable) {
   509             perror("JPROF_RTC setup: fcntl(/dev/rtc, F_SETFL, flags | FASYNC)");
   510         } else {
   511             perror("JPROF_RTC setup: fcntl(/dev/rtc, F_SETFL, flags & ~FASYNC)");
   512         }            
   513         return 0;
   514     }
   516     return 1;
   517 }
   518 #endif
   520 JPROF_STATIC void StackHook(
   521 int signum,
   522 siginfo_t *info,
   523 void *ucontext)
   524 {
   525     static struct timeval tFirst;
   526     static int first=1;
   527     size_t millisec = 0;
   529 #if defined(linux)
   530     if (rtcHz && pthread_self() != main_thread) {
   531       // Only collect stack data on the main thread, for now.
   532       return;
   533     }
   534 #endif
   536     if(first && !(first=0)) {
   537         puts("Jprof: received first signal");
   538 #if defined(linux)
   539         if (rtcHz) {
   540             enableRTCSignals(true);
   541         } else
   542 #endif
   543         {
   544             gettimeofday(&tFirst, 0);
   545             millisec = 0;
   546         }
   547     } else {
   548 #if defined(linux)
   549         if (rtcHz) {
   550             enableRTCSignals(true);
   551         } else
   552 #endif
   553         {
   554             struct timeval tNow;
   555             gettimeofday(&tNow, 0);
   556             double usec = 1e6*(tNow.tv_sec - tFirst.tv_sec);
   557             usec += (tNow.tv_usec - tFirst.tv_usec);
   558             millisec = static_cast<size_t>(usec*1e-3);
   559         }
   560     }
   562     gregset_t &gregs = ((ucontext_t*)ucontext)->uc_mcontext.gregs;
   563 #ifdef __x86_64__
   564     JprofLog(millisec, (void*)gregs[REG_RSP], (void*)gregs[REG_RIP]);
   565 #else
   566     JprofLog(millisec, (void*)gregs[REG_ESP], (void*)gregs[REG_EIP]);
   567 #endif
   569     if (!rtcHz)
   570         startSignalCounter(timerMilliSec);
   571 }
   573 NS_EXPORT_(void) setupProfilingStuff(void)
   574 {
   575     static int gFirstTime = 1;
   576     char filename[2048]; // XXX fix
   578     if(gFirstTime && !(gFirstTime=0)) {
   579 	int  startTimer = 1;
   580 	int  doNotStart = 1;
   581 	int  firstDelay = 0;
   582         int  append = O_TRUNC;
   583         char *tst  = getenv("JPROF_FLAGS");
   585 	/* Options from JPROF_FLAGS environment variable:
   586 	 *   JP_DEFER  -> Wait for a SIGPROF (or SIGALRM, if JP_REALTIME
   587 	 *               is set) from userland before starting
   588 	 *               to generate them internally
   589 	 *   JP_START  -> Install the signal handler
   590 	 *   JP_PERIOD -> Time between profiler ticks
   591 	 *   JP_FIRST  -> Extra delay before starting
   592 	 *   JP_REALTIME -> Take stack traces in intervals of real time
   593 	 *               rather than time used by the process (and the
   594 	 *               system for the process).  This is useful for
   595 	 *               finding time spent by the X server.
   596          *   JP_APPEND -> Append to jprof-log rather than overwriting it.
   597          *               This is somewhat risky since it depends on the
   598          *               address map staying constant across multiple runs.
   599          *   JP_FILENAME -> base filename to use when saving logs.  Note that
   600          *               this does not affect the mapfile.
   601          *   JP_CIRCULAR -> use a circular buffer of size N, write/clear on SIGUSR1
   602          *
   603          * JPROF_SLAVE is set if this is not the first process.
   604 	*/
   606         circular = false;
   608 	if(tst) {
   609 	    if(strstr(tst, "JP_DEFER"))
   610 	    {
   611 		doNotStart = 0;
   612 		startTimer = 0;
   613 	    }
   614 	    if(strstr(tst, "JP_START")) doNotStart = 0;
   615 	    if(strstr(tst, "JP_REALTIME")) realTime = 1;
   616 	    if(strstr(tst, "JP_APPEND")) append = O_APPEND;
   618 	    char *delay = strstr(tst,"JP_PERIOD=");
   619 	    if(delay) {
   620                 double tmp = strtod(delay+strlen("JP_PERIOD="), nullptr);
   621                 if (tmp>=1e-3) {
   622 		    timerMilliSec = static_cast<unsigned long>(1000 * tmp);
   623                 } else {
   624                     fprintf(stderr,
   625                             "JP_PERIOD of %g less than 0.001 (1ms), using 1ms\n",
   626                             tmp);
   627                     timerMilliSec = 1;
   628                 }
   629 	    }
   631 	    char *circular_op = strstr(tst,"JP_CIRCULAR=");
   632 	    if(circular_op) {
   633                 size_t size = atol(circular_op+strlen("JP_CIRCULAR="));
   634                 if (size < 1000) {
   635                     fprintf(stderr,
   636                             "JP_CIRCULAR of %d less than 1000, using 10000\n",
   637                             size);
   638                     size = 10000;
   639                 }
   640                 JprofBufferInit(size);
   641                 fprintf(stderr,"JP_CIRCULAR buffer of %d bytes\n",size);
   642                 circular = true;
   643 	    }
   645 	    char *first = strstr(tst, "JP_FIRST=");
   646 	    if(first) {
   647                 firstDelay = atol(first+strlen("JP_FIRST="));
   648 	    }
   650             char *rtc = strstr(tst, "JP_RTC_HZ=");
   651             if (rtc) {
   652 #if defined(linux)
   653                 rtcHz = atol(rtc+strlen("JP_RTC_HZ="));
   654                 timerMilliSec = 0; /* This makes JP_FIRST work right. */
   655                 realTime = 1; /* It's the _R_TC and all.  ;) */
   657 #define IS_POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0)
   659                 if (!IS_POWER_OF_TWO(rtcHz) || rtcHz < 2) {
   660                     fprintf(stderr, "JP_RTC_HZ must be power of two and >= 2, "
   661                             "but %d was provided; using default of 2048\n",
   662                             rtcHz);
   663                     rtcHz = 2048;
   664                 }
   665 #else
   666                 fputs("JP_RTC_HZ found, but RTC profiling only supported on "
   667                       "Linux!\n", stderr);
   669 #endif
   670             }
   671             char *f = strstr(tst,"JP_FILENAME=");
   672             if (f)
   673                 f = f + strlen("JP_FILENAME=");
   674             else
   675                 f = M_LOGFILE;
   677             char *is_slave = getenv("JPROF_SLAVE");
   678             if (!is_slave)
   679                 setenv("JPROF_SLAVE","", 0);
   681             int pid = syscall(SYS_gettid); //gettid();
   682             if (is_slave)
   683                 snprintf(filename,sizeof(filename),"%s-%d",f,pid);
   684             else
   685                 snprintf(filename,sizeof(filename),"%s",f);
   687             // XXX FIX! inherit current capture state!
   688 	}
   690 	if(!doNotStart) {
   692 	    if(gLogFD<0) {
   693 		gLogFD = open(filename, O_CREAT | O_WRONLY | append, 0666);
   694 		if(gLogFD<0) {
   695 		    fprintf(stderr, "Unable to create " M_LOGFILE);
   696 		    perror(":");
   697 		} else {
   698 		    struct sigaction action;
   699 		    sigset_t mset;
   701 		    // Dump out the address map when we terminate
   702 		    RegisterJprofShutdown();
   704 		    main_thread = pthread_self();
   705                     //fprintf(stderr,"jprof: main_thread = %u\n",
   706                     //        (unsigned int)main_thread);
   708                     // FIX!  probably should block these against each other
   709                     // Very unlikely.
   710 		    sigemptyset(&mset);
   711 		    action.sa_handler = nullptr;
   712 		    action.sa_sigaction = StackHook;
   713 		    action.sa_mask  = mset;
   714 		    action.sa_flags = SA_RESTART | SA_SIGINFO;
   715 #if defined(linux)
   716                     if (rtcHz) {
   717                         if (!setupRTCSignals(rtcHz, &action)) {
   718                             fputs("jprof: Error initializing RTC, NOT "
   719                                   "profiling\n", stderr);
   720                             return;
   721                         }
   722                     }
   724                     if (!rtcHz || firstDelay != 0)
   725 #endif
   726                     {
   727                         if (realTime) {
   728                             sigaction(SIGALRM, &action, nullptr);
   729                         }
   730                     }
   731                     // enable PROF in all cases to simplify JP_DEFER/pause/restart
   732                     sigaction(SIGPROF, &action, nullptr);
   734 		    // make it so a SIGUSR1 will stop the profiling
   735 		    // Note:  It currently does not close the logfile.
   736 		    // This could be configurable (so that it could
   737 		    // later be reopened).
   739 		    struct sigaction stop_action;
   740 		    stop_action.sa_handler = EndProfilingHook;
   741 		    stop_action.sa_mask  = mset;
   742 		    stop_action.sa_flags = SA_RESTART;
   743 		    sigaction(SIGUSR1, &stop_action, nullptr);
   745 		    // make it so a SIGUSR2 will clear the circular buffer
   747 		    stop_action.sa_handler = ClearProfilingHook;
   748 		    stop_action.sa_mask  = mset;
   749 		    stop_action.sa_flags = SA_RESTART;
   750 		    sigaction(SIGUSR2, &stop_action, nullptr);
   752                     printf("Jprof: Initialized signal handler and set "
   753                            "timer for %lu %s, %d s "
   754                            "initial delay\n",
   755                            rtcHz ? rtcHz : timerMilliSec, 
   756                            rtcHz ? "Hz" : "ms",
   757                            firstDelay);
   759 		    if(startTimer) {
   760 #if defined(linux)
   761                         /* If we have an initial delay we can just use
   762                            startSignalCounter to set up a timer to fire the
   763                            first stackHook after that delay.  When that happens
   764                            we'll go and switch to RTC profiling. */
   765                         if (rtcHz && firstDelay == 0) {
   766                             puts("Jprof: enabled RTC signals");
   767                             enableRTCSignals(true);
   768                         } else
   769 #endif
   770                         {
   771                             puts("Jprof: started timer");
   772                             startSignalCounter(firstDelay*1000 + timerMilliSec);
   773                         }
   774 		    }
   775 		}
   776 	    }
   777 	}
   778     } else {
   779         printf("setupProfilingStuff() called multiple times\n");
   780     }
   781 }

mercurial