1 #ifndef JEMALLOC_INTERNAL_TICKER_H
2 #define JEMALLOC_INTERNAL_TICKER_H
3 
4 #include "jemalloc/internal/util.h"
5 
6 /**
7  * A ticker makes it easy to count-down events until some limit.  You
8  * ticker_init the ticker to trigger every nticks events.  You then notify it
9  * that an event has occurred with calls to ticker_tick (or that nticks events
10  * have occurred with a call to ticker_ticks), which will return true (and reset
11  * the counter) if the countdown hit zero.
12  */
13 
14 typedef struct {
15 	int32_t tick;
16 	int32_t nticks;
17 } ticker_t;
18 
19 static inline void
ticker_init(ticker_t * ticker,int32_t nticks)20 ticker_init(ticker_t *ticker, int32_t nticks) {
21 	ticker->tick = nticks;
22 	ticker->nticks = nticks;
23 }
24 
25 static inline void
ticker_copy(ticker_t * ticker,const ticker_t * other)26 ticker_copy(ticker_t *ticker, const ticker_t *other) {
27 	*ticker = *other;
28 }
29 
30 static inline int32_t
ticker_read(const ticker_t * ticker)31 ticker_read(const ticker_t *ticker) {
32 	return ticker->tick;
33 }
34 
35 /*
36  * Not intended to be a public API.  Unfortunately, on x86, neither gcc nor
37  * clang seems smart enough to turn
38  *   ticker->tick -= nticks;
39  *   if (unlikely(ticker->tick < 0)) {
40  *     fixup ticker
41  *     return true;
42  *   }
43  *   return false;
44  * into
45  *   subq %nticks_reg, (%ticker_reg)
46  *   js fixup ticker
47  *
48  * unless we force "fixup ticker" out of line.  In that case, gcc gets it right,
49  * but clang now does worse than before.  So, on x86 with gcc, we force it out
50  * of line, but otherwise let the inlining occur.  Ordinarily this wouldn't be
51  * worth the hassle, but this is on the fast path of both malloc and free (via
52  * tcache_event).
53  */
54 #if defined(__GNUC__) && !defined(__clang__)				\
55     && (defined(__x86_64__) || defined(__i386__))
56 JEMALLOC_NOINLINE
57 #endif
58 static bool
ticker_fixup(ticker_t * ticker)59 ticker_fixup(ticker_t *ticker) {
60 	ticker->tick = ticker->nticks;
61 	return true;
62 }
63 
64 static inline bool
ticker_ticks(ticker_t * ticker,int32_t nticks)65 ticker_ticks(ticker_t *ticker, int32_t nticks) {
66 	ticker->tick -= nticks;
67 	if (unlikely(ticker->tick < 0)) {
68 		return ticker_fixup(ticker);
69 	}
70 	return false;
71 }
72 
73 static inline bool
ticker_tick(ticker_t * ticker)74 ticker_tick(ticker_t *ticker) {
75 	return ticker_ticks(ticker, 1);
76 }
77 
78 /*
79  * Try to tick.  If ticker would fire, return true, but rely on
80  * slowpath to reset ticker.
81  */
82 static inline bool
ticker_trytick(ticker_t * ticker)83 ticker_trytick(ticker_t *ticker) {
84 	--ticker->tick;
85 	if (unlikely(ticker->tick < 0)) {
86 		return true;
87 	}
88 	return false;
89 }
90 
91 #endif /* JEMALLOC_INTERNAL_TICKER_H */
92