HPCToolkit
safe-sampling.h
Go to the documentation of this file.
1 // -*-Mode: C++;-*- // technically C99
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 //***************************************************************************
48 //
49 // File:
50 // $HeadURL$
51 //
52 // Purpose:
53 // This file implements the "safe sampling" rules.
54 //
55 // Safe sampling extends the async blocks by tracking all entry and
56 // exit points in and out of the hpcrun code. Every thread keeps an
57 // 'inside_hpcrun' bit in the thread data struct. Set this bit via
58 // hpcrun_safe_enter() when entering hpcrun code and unset it via
59 // hpcrun_safe_exit() when returning to the application. Thus, at
60 // every entry point, we know if we just came from inside our own
61 // code.
62 //
63 // A synchronous override that was called from inside our code should
64 // call the real function and return (see IO overrides). An async
65 // interrupt that interrupted our code should restart the next signal
66 // (if needed) and return (see PAPI handler). In both cases, if
67 // coming from inside our code, then don't take a sample and don't
68 // call MSG.
69 //
70 // Notes:
71 // 1. Put the safe enter and exit functions in the first, top-level
72 // function that enters our code. Don't use them deep in the middle
73 // of our code.
74 //
75 // 2. Don't call MSG before hpcrun_safe_enter().
76 //
77 // 3. Check the return value of hpcrun_safe_enter() and don't call
78 // hpcrun_safe_exit() if safe enter returned false (unsafe).
79 //
80 // 4. In a sync override, it's ok to call safe exit and enter
81 // surrounding the call to the real function. For example,
82 //
83 // hpcrun_safe_exit();
84 // ret = real_function(...);
85 // hpcrun_safe_enter();
86 //
87 // 5. Be sure to #include <safe-sampling.h> in any file using these
88 // functions or else you'll get 'undefined reference' at runtime.
89 //
90 // 6. Technically, we don't need atomic test and set here. There is
91 // no race condition between threads. And if an interrupt happens
92 // inside hpcrun_safe_enter(), then the signal handler will restore
93 // inside_hpcrun to whatever it was when the interrupt happened.
94 //
95 // "Welcome to the Joe Hackett Flight School where our motto is,
96 // 'safety first, fun second.'" -- Joe Hackett in "Wings"
97 //
98 //***************************************************************************
99 
100 #ifndef _HPCRUN_SAFE_SAMPLING_H_
101 #define _HPCRUN_SAFE_SAMPLING_H_
102 
103 #include <hpcrun/main.h>
104 #include <hpcrun/thread_data.h>
106 
107 
108 // Use hpcrun_safe_enter() at entry into our code in a synchronous
109 // override. If unsafe (false), then call the real function and
110 // return.
111 //
112 // A sync override can occur anywhere, including before hpcrun init.
113 // So, if uninit or if thread data is not set up, then assume we're in
114 // our init code and return unsafe.
115 //
116 // Returns: true if safe, ie, not already inside our code.
117 //
118 static inline int
120 {
121  thread_data_t *td;
122  int prev;
123 
124  if (! hpcrun_is_initialized() || ! hpcrun_td_avail()) {
125  return 0;
126  }
127  td = hpcrun_get_thread_data();
128  prev = td->inside_hpcrun;
129  td->inside_hpcrun = 1;
130 
131  return (prev == 0);
132 }
133 
134 
135 // Use hpcrun_safe_enter_async() at entry into our code in an async
136 // interrupt. If unsafe (false), then restart the next interrupt and
137 // return.
138 //
139 // Use the program counter address (pc) to test if the interrupt came
140 // from inside the trampoline assembler code.
141 //
142 // Returns: true if safe, ie, not already inside our code.
143 //
144 static inline int
146 {
147  thread_data_t *td;
148  int prev;
149 
151  || ! hpcrun_td_avail()) {
152  return 0;
153  }
154 
155  td = hpcrun_get_thread_data();
156  prev = td->inside_hpcrun;
157  td->inside_hpcrun = 1;
158 
159  return (prev == 0);
160 }
161 
162 
163 // Use hpcrun_safe_exit() at return from our code back to the
164 // application. But call this only if the previous safe enter
165 // returned true.
166 //
167 static inline void
169 {
171 
172  td->inside_hpcrun = 0;
173 }
174 
175 
176 #endif // _HPCRUN_SAFE_SAMPLING_H_
static void hpcrun_safe_exit(void)
bool hpcrun_is_initialized()
Definition: main.c:272
bool(* hpcrun_td_avail)(void)
Definition: thread_data.c:169
bool hpcrun_trampoline_at_entry(void *addr)
Definition: trampoline.c:118
static int hpcrun_safe_enter_async(void *pc)
bool hpcrun_trampoline_interior(void *addr)
Definition: trampoline.c:109
static int hpcrun_safe_enter(void)
thread_data_t *(* hpcrun_get_thread_data)(void)
Definition: thread_data.c:168