]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sysdeps/posix/profil.c
Update copyright notices with scripts/update-copyrights
[thirdparty/glibc.git] / sysdeps / posix / profil.c
index 8e34b3564f7c19cc6785d178b568bcfdfe733aa2..696c7a6cadde50d9122f975107143cff36b27a0b 100644 (file)
@@ -1,31 +1,31 @@
 /* Low-level statistical profiling support function.  Mostly POSIX.1 version.
-Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
+   Copyright (C) 1996-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #include <sys/types.h>
 #include <unistd.h>
 #include <errno.h>
 #include <signal.h>
 #include <sys/time.h>
+#include <libc-internal.h>
 
 #ifndef SIGPROF
 
-#include_next <profil.c>
+#include <gmon/profil.c>
 
 #else
 
@@ -37,7 +37,13 @@ static u_int pc_scale;
 static inline void
 profil_count (void *pc)
 {
-  size_t i = ((pc - pc_offset - (void *) 0) / 2) * pc_scale / 65536;
+  size_t i = (pc - pc_offset - (void *) 0) / 2;
+
+  if (sizeof (unsigned long long int) > sizeof (size_t))
+    i = (unsigned long long int) i * pc_scale / 65536;
+  else
+    i = i / 65536 * pc_scale + i % 65536 * pc_scale / 65536;
+
   if (i < nsamples)
     ++samples[i];
 }
@@ -54,10 +60,15 @@ profil_count (void *pc)
    disable profiling.  Returns zero on success, -1 on error.  */
 
 int
-profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale)
+__profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale)
 {
-  static struct sigaction act, oact;
-  static struct itimerval timer, otimer;
+  struct sigaction act;
+  struct itimerval timer;
+#ifndef IS_IN_rtld
+  static struct sigaction oact;
+  static struct itimerval otimer;
+# define oact_ptr &oact
+# define otimer_ptr &otimer
 
   if (sample_buffer == NULL)
     {
@@ -65,12 +76,27 @@ profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale)
       if (samples == NULL)
        /* Wasn't turned on.  */
        return 0;
+
+      if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0)
+       return -1;
       samples = NULL;
+      return __sigaction (SIGPROF, &oact, NULL);
+    }
 
-      if (sigaction (SIGPROF, &oact, NULL) < 0)
+ if (samples)
+    {
+      /* Was already turned on.  Restore old timer and signal handler
+        first.  */
+      if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0
+         || __sigaction (SIGPROF, &oact, NULL) < 0)
        return -1;
-      return setitimer (ITIMER_PROF, &otimer, NULL);
     }
+#else
+ /* In ld.so profiling should never be disabled once it runs.  */
+ //assert (sample_buffer != NULL);
+# define oact_ptr NULL
+# define otimer_ptr NULL
+#endif
 
   samples = sample_buffer;
   nsamples = size / sizeof *samples;
@@ -79,14 +105,15 @@ profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale)
 
   act.sa_handler = (sighandler_t) &profil_counter;
   act.sa_flags = SA_RESTART;
-  sigfillset (&act.sa_mask);
-  if (sigaction (SIGPROF, &act, &oact) < 0)
+  __sigfillset (&act.sa_mask);
+  if (__sigaction (SIGPROF, &act, oact_ptr) < 0)
     return -1;
 
   timer.it_value.tv_sec = 0;
-  timer.it_value.tv_usec = 1;
+  timer.it_value.tv_usec = 1000000 / __profile_frequency ();
   timer.it_interval = timer.it_value;
-  return setitimer (ITIMER_PROF, &timer, &otimer);
+  return __setitimer (ITIMER_PROF, &timer, otimer_ptr);
 }
+weak_alias (__profil, profil)
 
 #endif