1*1208bc7eSAndroid Build Coastguard Worker #define JEMALLOC_BACKGROUND_THREAD_C_
2*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_preamble.h"
3*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_internal_includes.h"
4*1208bc7eSAndroid Build Coastguard Worker
5*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/assert.h"
6*1208bc7eSAndroid Build Coastguard Worker
7*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
8*1208bc7eSAndroid Build Coastguard Worker /* Data. */
9*1208bc7eSAndroid Build Coastguard Worker
10*1208bc7eSAndroid Build Coastguard Worker /* This option should be opt-in only. */
11*1208bc7eSAndroid Build Coastguard Worker #define BACKGROUND_THREAD_DEFAULT false
12*1208bc7eSAndroid Build Coastguard Worker /* Read-only after initialization. */
13*1208bc7eSAndroid Build Coastguard Worker bool opt_background_thread = BACKGROUND_THREAD_DEFAULT;
14*1208bc7eSAndroid Build Coastguard Worker size_t opt_max_background_threads = MAX_BACKGROUND_THREAD_LIMIT;
15*1208bc7eSAndroid Build Coastguard Worker
16*1208bc7eSAndroid Build Coastguard Worker /* Used for thread creation, termination and stats. */
17*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_t background_thread_lock;
18*1208bc7eSAndroid Build Coastguard Worker /* Indicates global state. Atomic because decay reads this w/o locking. */
19*1208bc7eSAndroid Build Coastguard Worker atomic_b_t background_thread_enabled_state;
20*1208bc7eSAndroid Build Coastguard Worker size_t n_background_threads;
21*1208bc7eSAndroid Build Coastguard Worker size_t max_background_threads;
22*1208bc7eSAndroid Build Coastguard Worker /* Thread info per-index. */
23*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *background_thread_info;
24*1208bc7eSAndroid Build Coastguard Worker
25*1208bc7eSAndroid Build Coastguard Worker /* False if no necessary runtime support. */
26*1208bc7eSAndroid Build Coastguard Worker bool can_enable_background_thread;
27*1208bc7eSAndroid Build Coastguard Worker
28*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
29*1208bc7eSAndroid Build Coastguard Worker
30*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
31*1208bc7eSAndroid Build Coastguard Worker #include <dlfcn.h>
32*1208bc7eSAndroid Build Coastguard Worker
33*1208bc7eSAndroid Build Coastguard Worker static int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *,
34*1208bc7eSAndroid Build Coastguard Worker void *(*)(void *), void *__restrict);
35*1208bc7eSAndroid Build Coastguard Worker
36*1208bc7eSAndroid Build Coastguard Worker static void
pthread_create_wrapper_init(void)37*1208bc7eSAndroid Build Coastguard Worker pthread_create_wrapper_init(void) {
38*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_LAZY_LOCK
39*1208bc7eSAndroid Build Coastguard Worker if (!isthreaded) {
40*1208bc7eSAndroid Build Coastguard Worker isthreaded = true;
41*1208bc7eSAndroid Build Coastguard Worker }
42*1208bc7eSAndroid Build Coastguard Worker #endif
43*1208bc7eSAndroid Build Coastguard Worker }
44*1208bc7eSAndroid Build Coastguard Worker
45*1208bc7eSAndroid Build Coastguard Worker int
pthread_create_wrapper(pthread_t * __restrict thread,const pthread_attr_t * attr,void * (* start_routine)(void *),void * __restrict arg)46*1208bc7eSAndroid Build Coastguard Worker pthread_create_wrapper(pthread_t *__restrict thread, const pthread_attr_t *attr,
47*1208bc7eSAndroid Build Coastguard Worker void *(*start_routine)(void *), void *__restrict arg) {
48*1208bc7eSAndroid Build Coastguard Worker pthread_create_wrapper_init();
49*1208bc7eSAndroid Build Coastguard Worker
50*1208bc7eSAndroid Build Coastguard Worker return pthread_create_fptr(thread, attr, start_routine, arg);
51*1208bc7eSAndroid Build Coastguard Worker }
52*1208bc7eSAndroid Build Coastguard Worker #endif /* JEMALLOC_PTHREAD_CREATE_WRAPPER */
53*1208bc7eSAndroid Build Coastguard Worker
54*1208bc7eSAndroid Build Coastguard Worker #ifndef JEMALLOC_BACKGROUND_THREAD
55*1208bc7eSAndroid Build Coastguard Worker #define NOT_REACHED { not_reached(); }
background_thread_create(tsd_t * tsd,unsigned arena_ind)56*1208bc7eSAndroid Build Coastguard Worker bool background_thread_create(tsd_t *tsd, unsigned arena_ind) NOT_REACHED
57*1208bc7eSAndroid Build Coastguard Worker bool background_threads_enable(tsd_t *tsd) NOT_REACHED
58*1208bc7eSAndroid Build Coastguard Worker bool background_threads_disable(tsd_t *tsd) NOT_REACHED
59*1208bc7eSAndroid Build Coastguard Worker void background_thread_interval_check(tsdn_t *tsdn, arena_t *arena,
60*1208bc7eSAndroid Build Coastguard Worker arena_decay_t *decay, size_t npages_new) NOT_REACHED
61*1208bc7eSAndroid Build Coastguard Worker void background_thread_prefork0(tsdn_t *tsdn) NOT_REACHED
62*1208bc7eSAndroid Build Coastguard Worker void background_thread_prefork1(tsdn_t *tsdn) NOT_REACHED
63*1208bc7eSAndroid Build Coastguard Worker void background_thread_postfork_parent(tsdn_t *tsdn) NOT_REACHED
64*1208bc7eSAndroid Build Coastguard Worker void background_thread_postfork_child(tsdn_t *tsdn) NOT_REACHED
65*1208bc7eSAndroid Build Coastguard Worker bool background_thread_stats_read(tsdn_t *tsdn,
66*1208bc7eSAndroid Build Coastguard Worker background_thread_stats_t *stats) NOT_REACHED
67*1208bc7eSAndroid Build Coastguard Worker void background_thread_ctl_init(tsdn_t *tsdn) NOT_REACHED
68*1208bc7eSAndroid Build Coastguard Worker #undef NOT_REACHED
69*1208bc7eSAndroid Build Coastguard Worker #else
70*1208bc7eSAndroid Build Coastguard Worker
71*1208bc7eSAndroid Build Coastguard Worker static bool background_thread_enabled_at_fork;
72*1208bc7eSAndroid Build Coastguard Worker
73*1208bc7eSAndroid Build Coastguard Worker static void
74*1208bc7eSAndroid Build Coastguard Worker background_thread_info_init(tsdn_t *tsdn, background_thread_info_t *info) {
75*1208bc7eSAndroid Build Coastguard Worker background_thread_wakeup_time_set(tsdn, info, 0);
76*1208bc7eSAndroid Build Coastguard Worker info->npages_to_purge_new = 0;
77*1208bc7eSAndroid Build Coastguard Worker if (config_stats) {
78*1208bc7eSAndroid Build Coastguard Worker info->tot_n_runs = 0;
79*1208bc7eSAndroid Build Coastguard Worker nstime_init(&info->tot_sleep_time, 0);
80*1208bc7eSAndroid Build Coastguard Worker }
81*1208bc7eSAndroid Build Coastguard Worker }
82*1208bc7eSAndroid Build Coastguard Worker
83*1208bc7eSAndroid Build Coastguard Worker static inline bool
84*1208bc7eSAndroid Build Coastguard Worker set_current_thread_affinity(UNUSED int cpu) {
85*1208bc7eSAndroid Build Coastguard Worker #if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY)
86*1208bc7eSAndroid Build Coastguard Worker cpu_set_t cpuset;
87*1208bc7eSAndroid Build Coastguard Worker CPU_ZERO(&cpuset);
88*1208bc7eSAndroid Build Coastguard Worker CPU_SET(cpu, &cpuset);
89*1208bc7eSAndroid Build Coastguard Worker int ret = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
90*1208bc7eSAndroid Build Coastguard Worker
91*1208bc7eSAndroid Build Coastguard Worker return (ret != 0);
92*1208bc7eSAndroid Build Coastguard Worker #else
93*1208bc7eSAndroid Build Coastguard Worker return false;
94*1208bc7eSAndroid Build Coastguard Worker #endif
95*1208bc7eSAndroid Build Coastguard Worker }
96*1208bc7eSAndroid Build Coastguard Worker
97*1208bc7eSAndroid Build Coastguard Worker /* Threshold for determining when to wake up the background thread. */
98*1208bc7eSAndroid Build Coastguard Worker #define BACKGROUND_THREAD_NPAGES_THRESHOLD UINT64_C(1024)
99*1208bc7eSAndroid Build Coastguard Worker #define BILLION UINT64_C(1000000000)
100*1208bc7eSAndroid Build Coastguard Worker /* Minimal sleep interval 100 ms. */
101*1208bc7eSAndroid Build Coastguard Worker #define BACKGROUND_THREAD_MIN_INTERVAL_NS (BILLION / 10)
102*1208bc7eSAndroid Build Coastguard Worker
103*1208bc7eSAndroid Build Coastguard Worker static inline size_t
104*1208bc7eSAndroid Build Coastguard Worker decay_npurge_after_interval(arena_decay_t *decay, size_t interval) {
105*1208bc7eSAndroid Build Coastguard Worker size_t i;
106*1208bc7eSAndroid Build Coastguard Worker uint64_t sum = 0;
107*1208bc7eSAndroid Build Coastguard Worker for (i = 0; i < interval; i++) {
108*1208bc7eSAndroid Build Coastguard Worker sum += decay->backlog[i] * h_steps[i];
109*1208bc7eSAndroid Build Coastguard Worker }
110*1208bc7eSAndroid Build Coastguard Worker for (; i < SMOOTHSTEP_NSTEPS; i++) {
111*1208bc7eSAndroid Build Coastguard Worker sum += decay->backlog[i] * (h_steps[i] - h_steps[i - interval]);
112*1208bc7eSAndroid Build Coastguard Worker }
113*1208bc7eSAndroid Build Coastguard Worker
114*1208bc7eSAndroid Build Coastguard Worker return (size_t)(sum >> SMOOTHSTEP_BFP);
115*1208bc7eSAndroid Build Coastguard Worker }
116*1208bc7eSAndroid Build Coastguard Worker
117*1208bc7eSAndroid Build Coastguard Worker static uint64_t
118*1208bc7eSAndroid Build Coastguard Worker arena_decay_compute_purge_interval_impl(tsdn_t *tsdn, arena_decay_t *decay,
119*1208bc7eSAndroid Build Coastguard Worker extents_t *extents) {
120*1208bc7eSAndroid Build Coastguard Worker if (malloc_mutex_trylock(tsdn, &decay->mtx)) {
121*1208bc7eSAndroid Build Coastguard Worker /* Use minimal interval if decay is contended. */
122*1208bc7eSAndroid Build Coastguard Worker return BACKGROUND_THREAD_MIN_INTERVAL_NS;
123*1208bc7eSAndroid Build Coastguard Worker }
124*1208bc7eSAndroid Build Coastguard Worker
125*1208bc7eSAndroid Build Coastguard Worker uint64_t interval;
126*1208bc7eSAndroid Build Coastguard Worker ssize_t decay_time = atomic_load_zd(&decay->time_ms, ATOMIC_RELAXED);
127*1208bc7eSAndroid Build Coastguard Worker if (decay_time <= 0) {
128*1208bc7eSAndroid Build Coastguard Worker /* Purging is eagerly done or disabled currently. */
129*1208bc7eSAndroid Build Coastguard Worker interval = BACKGROUND_THREAD_INDEFINITE_SLEEP;
130*1208bc7eSAndroid Build Coastguard Worker goto label_done;
131*1208bc7eSAndroid Build Coastguard Worker }
132*1208bc7eSAndroid Build Coastguard Worker
133*1208bc7eSAndroid Build Coastguard Worker uint64_t decay_interval_ns = nstime_ns(&decay->interval);
134*1208bc7eSAndroid Build Coastguard Worker assert(decay_interval_ns > 0);
135*1208bc7eSAndroid Build Coastguard Worker size_t npages = extents_npages_get(extents);
136*1208bc7eSAndroid Build Coastguard Worker if (npages == 0) {
137*1208bc7eSAndroid Build Coastguard Worker unsigned i;
138*1208bc7eSAndroid Build Coastguard Worker for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) {
139*1208bc7eSAndroid Build Coastguard Worker if (decay->backlog[i] > 0) {
140*1208bc7eSAndroid Build Coastguard Worker break;
141*1208bc7eSAndroid Build Coastguard Worker }
142*1208bc7eSAndroid Build Coastguard Worker }
143*1208bc7eSAndroid Build Coastguard Worker if (i == SMOOTHSTEP_NSTEPS) {
144*1208bc7eSAndroid Build Coastguard Worker /* No dirty pages recorded. Sleep indefinitely. */
145*1208bc7eSAndroid Build Coastguard Worker interval = BACKGROUND_THREAD_INDEFINITE_SLEEP;
146*1208bc7eSAndroid Build Coastguard Worker goto label_done;
147*1208bc7eSAndroid Build Coastguard Worker }
148*1208bc7eSAndroid Build Coastguard Worker }
149*1208bc7eSAndroid Build Coastguard Worker if (npages <= BACKGROUND_THREAD_NPAGES_THRESHOLD) {
150*1208bc7eSAndroid Build Coastguard Worker /* Use max interval. */
151*1208bc7eSAndroid Build Coastguard Worker interval = decay_interval_ns * SMOOTHSTEP_NSTEPS;
152*1208bc7eSAndroid Build Coastguard Worker goto label_done;
153*1208bc7eSAndroid Build Coastguard Worker }
154*1208bc7eSAndroid Build Coastguard Worker
155*1208bc7eSAndroid Build Coastguard Worker size_t lb = BACKGROUND_THREAD_MIN_INTERVAL_NS / decay_interval_ns;
156*1208bc7eSAndroid Build Coastguard Worker size_t ub = SMOOTHSTEP_NSTEPS;
157*1208bc7eSAndroid Build Coastguard Worker /* Minimal 2 intervals to ensure reaching next epoch deadline. */
158*1208bc7eSAndroid Build Coastguard Worker lb = (lb < 2) ? 2 : lb;
159*1208bc7eSAndroid Build Coastguard Worker if ((decay_interval_ns * ub <= BACKGROUND_THREAD_MIN_INTERVAL_NS) ||
160*1208bc7eSAndroid Build Coastguard Worker (lb + 2 > ub)) {
161*1208bc7eSAndroid Build Coastguard Worker interval = BACKGROUND_THREAD_MIN_INTERVAL_NS;
162*1208bc7eSAndroid Build Coastguard Worker goto label_done;
163*1208bc7eSAndroid Build Coastguard Worker }
164*1208bc7eSAndroid Build Coastguard Worker
165*1208bc7eSAndroid Build Coastguard Worker assert(lb + 2 <= ub);
166*1208bc7eSAndroid Build Coastguard Worker size_t npurge_lb, npurge_ub;
167*1208bc7eSAndroid Build Coastguard Worker npurge_lb = decay_npurge_after_interval(decay, lb);
168*1208bc7eSAndroid Build Coastguard Worker if (npurge_lb > BACKGROUND_THREAD_NPAGES_THRESHOLD) {
169*1208bc7eSAndroid Build Coastguard Worker interval = decay_interval_ns * lb;
170*1208bc7eSAndroid Build Coastguard Worker goto label_done;
171*1208bc7eSAndroid Build Coastguard Worker }
172*1208bc7eSAndroid Build Coastguard Worker npurge_ub = decay_npurge_after_interval(decay, ub);
173*1208bc7eSAndroid Build Coastguard Worker if (npurge_ub < BACKGROUND_THREAD_NPAGES_THRESHOLD) {
174*1208bc7eSAndroid Build Coastguard Worker interval = decay_interval_ns * ub;
175*1208bc7eSAndroid Build Coastguard Worker goto label_done;
176*1208bc7eSAndroid Build Coastguard Worker }
177*1208bc7eSAndroid Build Coastguard Worker
178*1208bc7eSAndroid Build Coastguard Worker unsigned n_search = 0;
179*1208bc7eSAndroid Build Coastguard Worker size_t target, npurge;
180*1208bc7eSAndroid Build Coastguard Worker while ((npurge_lb + BACKGROUND_THREAD_NPAGES_THRESHOLD < npurge_ub)
181*1208bc7eSAndroid Build Coastguard Worker && (lb + 2 < ub)) {
182*1208bc7eSAndroid Build Coastguard Worker target = (lb + ub) / 2;
183*1208bc7eSAndroid Build Coastguard Worker npurge = decay_npurge_after_interval(decay, target);
184*1208bc7eSAndroid Build Coastguard Worker if (npurge > BACKGROUND_THREAD_NPAGES_THRESHOLD) {
185*1208bc7eSAndroid Build Coastguard Worker ub = target;
186*1208bc7eSAndroid Build Coastguard Worker npurge_ub = npurge;
187*1208bc7eSAndroid Build Coastguard Worker } else {
188*1208bc7eSAndroid Build Coastguard Worker lb = target;
189*1208bc7eSAndroid Build Coastguard Worker npurge_lb = npurge;
190*1208bc7eSAndroid Build Coastguard Worker }
191*1208bc7eSAndroid Build Coastguard Worker assert(n_search++ < lg_floor(SMOOTHSTEP_NSTEPS) + 1);
192*1208bc7eSAndroid Build Coastguard Worker }
193*1208bc7eSAndroid Build Coastguard Worker interval = decay_interval_ns * (ub + lb) / 2;
194*1208bc7eSAndroid Build Coastguard Worker label_done:
195*1208bc7eSAndroid Build Coastguard Worker interval = (interval < BACKGROUND_THREAD_MIN_INTERVAL_NS) ?
196*1208bc7eSAndroid Build Coastguard Worker BACKGROUND_THREAD_MIN_INTERVAL_NS : interval;
197*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &decay->mtx);
198*1208bc7eSAndroid Build Coastguard Worker
199*1208bc7eSAndroid Build Coastguard Worker return interval;
200*1208bc7eSAndroid Build Coastguard Worker }
201*1208bc7eSAndroid Build Coastguard Worker
202*1208bc7eSAndroid Build Coastguard Worker /* Compute purge interval for background threads. */
203*1208bc7eSAndroid Build Coastguard Worker static uint64_t
204*1208bc7eSAndroid Build Coastguard Worker arena_decay_compute_purge_interval(tsdn_t *tsdn, arena_t *arena) {
205*1208bc7eSAndroid Build Coastguard Worker uint64_t i1, i2;
206*1208bc7eSAndroid Build Coastguard Worker i1 = arena_decay_compute_purge_interval_impl(tsdn, &arena->decay_dirty,
207*1208bc7eSAndroid Build Coastguard Worker &arena->extents_dirty);
208*1208bc7eSAndroid Build Coastguard Worker if (i1 == BACKGROUND_THREAD_MIN_INTERVAL_NS) {
209*1208bc7eSAndroid Build Coastguard Worker return i1;
210*1208bc7eSAndroid Build Coastguard Worker }
211*1208bc7eSAndroid Build Coastguard Worker i2 = arena_decay_compute_purge_interval_impl(tsdn, &arena->decay_muzzy,
212*1208bc7eSAndroid Build Coastguard Worker &arena->extents_muzzy);
213*1208bc7eSAndroid Build Coastguard Worker
214*1208bc7eSAndroid Build Coastguard Worker return i1 < i2 ? i1 : i2;
215*1208bc7eSAndroid Build Coastguard Worker }
216*1208bc7eSAndroid Build Coastguard Worker
217*1208bc7eSAndroid Build Coastguard Worker static void
218*1208bc7eSAndroid Build Coastguard Worker background_thread_sleep(tsdn_t *tsdn, background_thread_info_t *info,
219*1208bc7eSAndroid Build Coastguard Worker uint64_t interval) {
220*1208bc7eSAndroid Build Coastguard Worker if (config_stats) {
221*1208bc7eSAndroid Build Coastguard Worker info->tot_n_runs++;
222*1208bc7eSAndroid Build Coastguard Worker }
223*1208bc7eSAndroid Build Coastguard Worker info->npages_to_purge_new = 0;
224*1208bc7eSAndroid Build Coastguard Worker
225*1208bc7eSAndroid Build Coastguard Worker struct timeval tv;
226*1208bc7eSAndroid Build Coastguard Worker /* Specific clock required by timedwait. */
227*1208bc7eSAndroid Build Coastguard Worker gettimeofday(&tv, NULL);
228*1208bc7eSAndroid Build Coastguard Worker nstime_t before_sleep;
229*1208bc7eSAndroid Build Coastguard Worker nstime_init2(&before_sleep, tv.tv_sec, tv.tv_usec * 1000);
230*1208bc7eSAndroid Build Coastguard Worker
231*1208bc7eSAndroid Build Coastguard Worker int ret;
232*1208bc7eSAndroid Build Coastguard Worker if (interval == BACKGROUND_THREAD_INDEFINITE_SLEEP) {
233*1208bc7eSAndroid Build Coastguard Worker assert(background_thread_indefinite_sleep(info));
234*1208bc7eSAndroid Build Coastguard Worker ret = pthread_cond_wait(&info->cond, &info->mtx.lock);
235*1208bc7eSAndroid Build Coastguard Worker assert(ret == 0);
236*1208bc7eSAndroid Build Coastguard Worker } else {
237*1208bc7eSAndroid Build Coastguard Worker assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS &&
238*1208bc7eSAndroid Build Coastguard Worker interval <= BACKGROUND_THREAD_INDEFINITE_SLEEP);
239*1208bc7eSAndroid Build Coastguard Worker /* We need malloc clock (can be different from tv). */
240*1208bc7eSAndroid Build Coastguard Worker nstime_t next_wakeup;
241*1208bc7eSAndroid Build Coastguard Worker nstime_init(&next_wakeup, 0);
242*1208bc7eSAndroid Build Coastguard Worker nstime_update(&next_wakeup);
243*1208bc7eSAndroid Build Coastguard Worker nstime_iadd(&next_wakeup, interval);
244*1208bc7eSAndroid Build Coastguard Worker assert(nstime_ns(&next_wakeup) <
245*1208bc7eSAndroid Build Coastguard Worker BACKGROUND_THREAD_INDEFINITE_SLEEP);
246*1208bc7eSAndroid Build Coastguard Worker background_thread_wakeup_time_set(tsdn, info,
247*1208bc7eSAndroid Build Coastguard Worker nstime_ns(&next_wakeup));
248*1208bc7eSAndroid Build Coastguard Worker
249*1208bc7eSAndroid Build Coastguard Worker nstime_t ts_wakeup;
250*1208bc7eSAndroid Build Coastguard Worker nstime_copy(&ts_wakeup, &before_sleep);
251*1208bc7eSAndroid Build Coastguard Worker nstime_iadd(&ts_wakeup, interval);
252*1208bc7eSAndroid Build Coastguard Worker struct timespec ts;
253*1208bc7eSAndroid Build Coastguard Worker ts.tv_sec = (size_t)nstime_sec(&ts_wakeup);
254*1208bc7eSAndroid Build Coastguard Worker ts.tv_nsec = (size_t)nstime_nsec(&ts_wakeup);
255*1208bc7eSAndroid Build Coastguard Worker
256*1208bc7eSAndroid Build Coastguard Worker assert(!background_thread_indefinite_sleep(info));
257*1208bc7eSAndroid Build Coastguard Worker ret = pthread_cond_timedwait(&info->cond, &info->mtx.lock, &ts);
258*1208bc7eSAndroid Build Coastguard Worker assert(ret == ETIMEDOUT || ret == 0);
259*1208bc7eSAndroid Build Coastguard Worker background_thread_wakeup_time_set(tsdn, info,
260*1208bc7eSAndroid Build Coastguard Worker BACKGROUND_THREAD_INDEFINITE_SLEEP);
261*1208bc7eSAndroid Build Coastguard Worker }
262*1208bc7eSAndroid Build Coastguard Worker if (config_stats) {
263*1208bc7eSAndroid Build Coastguard Worker gettimeofday(&tv, NULL);
264*1208bc7eSAndroid Build Coastguard Worker nstime_t after_sleep;
265*1208bc7eSAndroid Build Coastguard Worker nstime_init2(&after_sleep, tv.tv_sec, tv.tv_usec * 1000);
266*1208bc7eSAndroid Build Coastguard Worker if (nstime_compare(&after_sleep, &before_sleep) > 0) {
267*1208bc7eSAndroid Build Coastguard Worker nstime_subtract(&after_sleep, &before_sleep);
268*1208bc7eSAndroid Build Coastguard Worker nstime_add(&info->tot_sleep_time, &after_sleep);
269*1208bc7eSAndroid Build Coastguard Worker }
270*1208bc7eSAndroid Build Coastguard Worker }
271*1208bc7eSAndroid Build Coastguard Worker }
272*1208bc7eSAndroid Build Coastguard Worker
273*1208bc7eSAndroid Build Coastguard Worker static bool
274*1208bc7eSAndroid Build Coastguard Worker background_thread_pause_check(tsdn_t *tsdn, background_thread_info_t *info) {
275*1208bc7eSAndroid Build Coastguard Worker if (unlikely(info->state == background_thread_paused)) {
276*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &info->mtx);
277*1208bc7eSAndroid Build Coastguard Worker /* Wait on global lock to update status. */
278*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &background_thread_lock);
279*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &background_thread_lock);
280*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &info->mtx);
281*1208bc7eSAndroid Build Coastguard Worker return true;
282*1208bc7eSAndroid Build Coastguard Worker }
283*1208bc7eSAndroid Build Coastguard Worker
284*1208bc7eSAndroid Build Coastguard Worker return false;
285*1208bc7eSAndroid Build Coastguard Worker }
286*1208bc7eSAndroid Build Coastguard Worker
287*1208bc7eSAndroid Build Coastguard Worker static inline void
288*1208bc7eSAndroid Build Coastguard Worker background_work_sleep_once(tsdn_t *tsdn, background_thread_info_t *info, unsigned ind) {
289*1208bc7eSAndroid Build Coastguard Worker uint64_t min_interval = BACKGROUND_THREAD_INDEFINITE_SLEEP;
290*1208bc7eSAndroid Build Coastguard Worker unsigned narenas = narenas_total_get();
291*1208bc7eSAndroid Build Coastguard Worker
292*1208bc7eSAndroid Build Coastguard Worker for (unsigned i = ind; i < narenas; i += max_background_threads) {
293*1208bc7eSAndroid Build Coastguard Worker arena_t *arena = arena_get(tsdn, i, false);
294*1208bc7eSAndroid Build Coastguard Worker if (!arena) {
295*1208bc7eSAndroid Build Coastguard Worker continue;
296*1208bc7eSAndroid Build Coastguard Worker }
297*1208bc7eSAndroid Build Coastguard Worker arena_decay(tsdn, arena, true, false);
298*1208bc7eSAndroid Build Coastguard Worker if (min_interval == BACKGROUND_THREAD_MIN_INTERVAL_NS) {
299*1208bc7eSAndroid Build Coastguard Worker /* Min interval will be used. */
300*1208bc7eSAndroid Build Coastguard Worker continue;
301*1208bc7eSAndroid Build Coastguard Worker }
302*1208bc7eSAndroid Build Coastguard Worker uint64_t interval = arena_decay_compute_purge_interval(tsdn,
303*1208bc7eSAndroid Build Coastguard Worker arena);
304*1208bc7eSAndroid Build Coastguard Worker assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS);
305*1208bc7eSAndroid Build Coastguard Worker if (min_interval > interval) {
306*1208bc7eSAndroid Build Coastguard Worker min_interval = interval;
307*1208bc7eSAndroid Build Coastguard Worker }
308*1208bc7eSAndroid Build Coastguard Worker }
309*1208bc7eSAndroid Build Coastguard Worker background_thread_sleep(tsdn, info, min_interval);
310*1208bc7eSAndroid Build Coastguard Worker }
311*1208bc7eSAndroid Build Coastguard Worker
312*1208bc7eSAndroid Build Coastguard Worker static bool
313*1208bc7eSAndroid Build Coastguard Worker background_threads_disable_single(tsd_t *tsd, background_thread_info_t *info) {
314*1208bc7eSAndroid Build Coastguard Worker if (info == &background_thread_info[0]) {
315*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsd_tsdn(tsd),
316*1208bc7eSAndroid Build Coastguard Worker &background_thread_lock);
317*1208bc7eSAndroid Build Coastguard Worker } else {
318*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_not_owner(tsd_tsdn(tsd),
319*1208bc7eSAndroid Build Coastguard Worker &background_thread_lock);
320*1208bc7eSAndroid Build Coastguard Worker }
321*1208bc7eSAndroid Build Coastguard Worker
322*1208bc7eSAndroid Build Coastguard Worker pre_reentrancy(tsd, NULL);
323*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
324*1208bc7eSAndroid Build Coastguard Worker bool has_thread;
325*1208bc7eSAndroid Build Coastguard Worker assert(info->state != background_thread_paused);
326*1208bc7eSAndroid Build Coastguard Worker if (info->state == background_thread_started) {
327*1208bc7eSAndroid Build Coastguard Worker has_thread = true;
328*1208bc7eSAndroid Build Coastguard Worker info->state = background_thread_stopped;
329*1208bc7eSAndroid Build Coastguard Worker pthread_cond_signal(&info->cond);
330*1208bc7eSAndroid Build Coastguard Worker } else {
331*1208bc7eSAndroid Build Coastguard Worker has_thread = false;
332*1208bc7eSAndroid Build Coastguard Worker }
333*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
334*1208bc7eSAndroid Build Coastguard Worker
335*1208bc7eSAndroid Build Coastguard Worker if (!has_thread) {
336*1208bc7eSAndroid Build Coastguard Worker post_reentrancy(tsd);
337*1208bc7eSAndroid Build Coastguard Worker return false;
338*1208bc7eSAndroid Build Coastguard Worker }
339*1208bc7eSAndroid Build Coastguard Worker void *ret;
340*1208bc7eSAndroid Build Coastguard Worker if (pthread_join(info->thread, &ret)) {
341*1208bc7eSAndroid Build Coastguard Worker post_reentrancy(tsd);
342*1208bc7eSAndroid Build Coastguard Worker return true;
343*1208bc7eSAndroid Build Coastguard Worker }
344*1208bc7eSAndroid Build Coastguard Worker assert(ret == NULL);
345*1208bc7eSAndroid Build Coastguard Worker n_background_threads--;
346*1208bc7eSAndroid Build Coastguard Worker post_reentrancy(tsd);
347*1208bc7eSAndroid Build Coastguard Worker
348*1208bc7eSAndroid Build Coastguard Worker return false;
349*1208bc7eSAndroid Build Coastguard Worker }
350*1208bc7eSAndroid Build Coastguard Worker
351*1208bc7eSAndroid Build Coastguard Worker static void *background_thread_entry(void *ind_arg);
352*1208bc7eSAndroid Build Coastguard Worker
353*1208bc7eSAndroid Build Coastguard Worker static int
354*1208bc7eSAndroid Build Coastguard Worker background_thread_create_signals_masked(pthread_t *thread,
355*1208bc7eSAndroid Build Coastguard Worker const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) {
356*1208bc7eSAndroid Build Coastguard Worker /*
357*1208bc7eSAndroid Build Coastguard Worker * Mask signals during thread creation so that the thread inherits
358*1208bc7eSAndroid Build Coastguard Worker * an empty signal set.
359*1208bc7eSAndroid Build Coastguard Worker */
360*1208bc7eSAndroid Build Coastguard Worker sigset_t set;
361*1208bc7eSAndroid Build Coastguard Worker sigfillset(&set);
362*1208bc7eSAndroid Build Coastguard Worker sigset_t oldset;
363*1208bc7eSAndroid Build Coastguard Worker int mask_err = pthread_sigmask(SIG_SETMASK, &set, &oldset);
364*1208bc7eSAndroid Build Coastguard Worker if (mask_err != 0) {
365*1208bc7eSAndroid Build Coastguard Worker return mask_err;
366*1208bc7eSAndroid Build Coastguard Worker }
367*1208bc7eSAndroid Build Coastguard Worker int create_err = pthread_create_wrapper(thread, attr, start_routine,
368*1208bc7eSAndroid Build Coastguard Worker arg);
369*1208bc7eSAndroid Build Coastguard Worker /*
370*1208bc7eSAndroid Build Coastguard Worker * Restore the signal mask. Failure to restore the signal mask here
371*1208bc7eSAndroid Build Coastguard Worker * changes program behavior.
372*1208bc7eSAndroid Build Coastguard Worker */
373*1208bc7eSAndroid Build Coastguard Worker int restore_err = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
374*1208bc7eSAndroid Build Coastguard Worker if (restore_err != 0) {
375*1208bc7eSAndroid Build Coastguard Worker malloc_printf("<jemalloc>: background thread creation "
376*1208bc7eSAndroid Build Coastguard Worker "failed (%d), and signal mask restoration failed "
377*1208bc7eSAndroid Build Coastguard Worker "(%d)\n", create_err, restore_err);
378*1208bc7eSAndroid Build Coastguard Worker if (opt_abort) {
379*1208bc7eSAndroid Build Coastguard Worker abort();
380*1208bc7eSAndroid Build Coastguard Worker }
381*1208bc7eSAndroid Build Coastguard Worker }
382*1208bc7eSAndroid Build Coastguard Worker return create_err;
383*1208bc7eSAndroid Build Coastguard Worker }
384*1208bc7eSAndroid Build Coastguard Worker
385*1208bc7eSAndroid Build Coastguard Worker static bool
386*1208bc7eSAndroid Build Coastguard Worker check_background_thread_creation(tsd_t *tsd, unsigned *n_created,
387*1208bc7eSAndroid Build Coastguard Worker bool *created_threads) {
388*1208bc7eSAndroid Build Coastguard Worker bool ret = false;
389*1208bc7eSAndroid Build Coastguard Worker if (likely(*n_created == n_background_threads)) {
390*1208bc7eSAndroid Build Coastguard Worker return ret;
391*1208bc7eSAndroid Build Coastguard Worker }
392*1208bc7eSAndroid Build Coastguard Worker
393*1208bc7eSAndroid Build Coastguard Worker tsdn_t *tsdn = tsd_tsdn(tsd);
394*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &background_thread_info[0].mtx);
395*1208bc7eSAndroid Build Coastguard Worker for (unsigned i = 1; i < max_background_threads; i++) {
396*1208bc7eSAndroid Build Coastguard Worker if (created_threads[i]) {
397*1208bc7eSAndroid Build Coastguard Worker continue;
398*1208bc7eSAndroid Build Coastguard Worker }
399*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *info = &background_thread_info[i];
400*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &info->mtx);
401*1208bc7eSAndroid Build Coastguard Worker /*
402*1208bc7eSAndroid Build Coastguard Worker * In case of the background_thread_paused state because of
403*1208bc7eSAndroid Build Coastguard Worker * arena reset, delay the creation.
404*1208bc7eSAndroid Build Coastguard Worker */
405*1208bc7eSAndroid Build Coastguard Worker bool create = (info->state == background_thread_started);
406*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &info->mtx);
407*1208bc7eSAndroid Build Coastguard Worker if (!create) {
408*1208bc7eSAndroid Build Coastguard Worker continue;
409*1208bc7eSAndroid Build Coastguard Worker }
410*1208bc7eSAndroid Build Coastguard Worker
411*1208bc7eSAndroid Build Coastguard Worker pre_reentrancy(tsd, NULL);
412*1208bc7eSAndroid Build Coastguard Worker int err = background_thread_create_signals_masked(&info->thread,
413*1208bc7eSAndroid Build Coastguard Worker NULL, background_thread_entry, (void *)(uintptr_t)i);
414*1208bc7eSAndroid Build Coastguard Worker post_reentrancy(tsd);
415*1208bc7eSAndroid Build Coastguard Worker
416*1208bc7eSAndroid Build Coastguard Worker if (err == 0) {
417*1208bc7eSAndroid Build Coastguard Worker (*n_created)++;
418*1208bc7eSAndroid Build Coastguard Worker created_threads[i] = true;
419*1208bc7eSAndroid Build Coastguard Worker } else {
420*1208bc7eSAndroid Build Coastguard Worker malloc_printf("<jemalloc>: background thread "
421*1208bc7eSAndroid Build Coastguard Worker "creation failed (%d)\n", err);
422*1208bc7eSAndroid Build Coastguard Worker if (opt_abort) {
423*1208bc7eSAndroid Build Coastguard Worker abort();
424*1208bc7eSAndroid Build Coastguard Worker }
425*1208bc7eSAndroid Build Coastguard Worker }
426*1208bc7eSAndroid Build Coastguard Worker /* Return to restart the loop since we unlocked. */
427*1208bc7eSAndroid Build Coastguard Worker ret = true;
428*1208bc7eSAndroid Build Coastguard Worker break;
429*1208bc7eSAndroid Build Coastguard Worker }
430*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &background_thread_info[0].mtx);
431*1208bc7eSAndroid Build Coastguard Worker
432*1208bc7eSAndroid Build Coastguard Worker return ret;
433*1208bc7eSAndroid Build Coastguard Worker }
434*1208bc7eSAndroid Build Coastguard Worker
435*1208bc7eSAndroid Build Coastguard Worker static void
436*1208bc7eSAndroid Build Coastguard Worker background_thread0_work(tsd_t *tsd) {
437*1208bc7eSAndroid Build Coastguard Worker /* Thread0 is also responsible for launching / terminating threads. */
438*1208bc7eSAndroid Build Coastguard Worker VARIABLE_ARRAY(bool, created_threads, max_background_threads);
439*1208bc7eSAndroid Build Coastguard Worker unsigned i;
440*1208bc7eSAndroid Build Coastguard Worker for (i = 1; i < max_background_threads; i++) {
441*1208bc7eSAndroid Build Coastguard Worker created_threads[i] = false;
442*1208bc7eSAndroid Build Coastguard Worker }
443*1208bc7eSAndroid Build Coastguard Worker /* Start working, and create more threads when asked. */
444*1208bc7eSAndroid Build Coastguard Worker unsigned n_created = 1;
445*1208bc7eSAndroid Build Coastguard Worker while (background_thread_info[0].state != background_thread_stopped) {
446*1208bc7eSAndroid Build Coastguard Worker if (background_thread_pause_check(tsd_tsdn(tsd),
447*1208bc7eSAndroid Build Coastguard Worker &background_thread_info[0])) {
448*1208bc7eSAndroid Build Coastguard Worker continue;
449*1208bc7eSAndroid Build Coastguard Worker }
450*1208bc7eSAndroid Build Coastguard Worker if (check_background_thread_creation(tsd, &n_created,
451*1208bc7eSAndroid Build Coastguard Worker (bool *)&created_threads)) {
452*1208bc7eSAndroid Build Coastguard Worker continue;
453*1208bc7eSAndroid Build Coastguard Worker }
454*1208bc7eSAndroid Build Coastguard Worker background_work_sleep_once(tsd_tsdn(tsd),
455*1208bc7eSAndroid Build Coastguard Worker &background_thread_info[0], 0);
456*1208bc7eSAndroid Build Coastguard Worker }
457*1208bc7eSAndroid Build Coastguard Worker
458*1208bc7eSAndroid Build Coastguard Worker /*
459*1208bc7eSAndroid Build Coastguard Worker * Shut down other threads at exit. Note that the ctl thread is holding
460*1208bc7eSAndroid Build Coastguard Worker * the global background_thread mutex (and is waiting) for us.
461*1208bc7eSAndroid Build Coastguard Worker */
462*1208bc7eSAndroid Build Coastguard Worker assert(!background_thread_enabled());
463*1208bc7eSAndroid Build Coastguard Worker for (i = 1; i < max_background_threads; i++) {
464*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *info = &background_thread_info[i];
465*1208bc7eSAndroid Build Coastguard Worker assert(info->state != background_thread_paused);
466*1208bc7eSAndroid Build Coastguard Worker if (created_threads[i]) {
467*1208bc7eSAndroid Build Coastguard Worker background_threads_disable_single(tsd, info);
468*1208bc7eSAndroid Build Coastguard Worker } else {
469*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
470*1208bc7eSAndroid Build Coastguard Worker if (info->state != background_thread_stopped) {
471*1208bc7eSAndroid Build Coastguard Worker /* The thread was not created. */
472*1208bc7eSAndroid Build Coastguard Worker assert(info->state ==
473*1208bc7eSAndroid Build Coastguard Worker background_thread_started);
474*1208bc7eSAndroid Build Coastguard Worker n_background_threads--;
475*1208bc7eSAndroid Build Coastguard Worker info->state = background_thread_stopped;
476*1208bc7eSAndroid Build Coastguard Worker }
477*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
478*1208bc7eSAndroid Build Coastguard Worker }
479*1208bc7eSAndroid Build Coastguard Worker }
480*1208bc7eSAndroid Build Coastguard Worker background_thread_info[0].state = background_thread_stopped;
481*1208bc7eSAndroid Build Coastguard Worker assert(n_background_threads == 1);
482*1208bc7eSAndroid Build Coastguard Worker }
483*1208bc7eSAndroid Build Coastguard Worker
484*1208bc7eSAndroid Build Coastguard Worker static void
485*1208bc7eSAndroid Build Coastguard Worker background_work(tsd_t *tsd, unsigned ind) {
486*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *info = &background_thread_info[ind];
487*1208bc7eSAndroid Build Coastguard Worker
488*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
489*1208bc7eSAndroid Build Coastguard Worker background_thread_wakeup_time_set(tsd_tsdn(tsd), info,
490*1208bc7eSAndroid Build Coastguard Worker BACKGROUND_THREAD_INDEFINITE_SLEEP);
491*1208bc7eSAndroid Build Coastguard Worker if (ind == 0) {
492*1208bc7eSAndroid Build Coastguard Worker background_thread0_work(tsd);
493*1208bc7eSAndroid Build Coastguard Worker } else {
494*1208bc7eSAndroid Build Coastguard Worker while (info->state != background_thread_stopped) {
495*1208bc7eSAndroid Build Coastguard Worker if (background_thread_pause_check(tsd_tsdn(tsd),
496*1208bc7eSAndroid Build Coastguard Worker info)) {
497*1208bc7eSAndroid Build Coastguard Worker continue;
498*1208bc7eSAndroid Build Coastguard Worker }
499*1208bc7eSAndroid Build Coastguard Worker background_work_sleep_once(tsd_tsdn(tsd), info, ind);
500*1208bc7eSAndroid Build Coastguard Worker }
501*1208bc7eSAndroid Build Coastguard Worker }
502*1208bc7eSAndroid Build Coastguard Worker assert(info->state == background_thread_stopped);
503*1208bc7eSAndroid Build Coastguard Worker background_thread_wakeup_time_set(tsd_tsdn(tsd), info, 0);
504*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
505*1208bc7eSAndroid Build Coastguard Worker }
506*1208bc7eSAndroid Build Coastguard Worker
507*1208bc7eSAndroid Build Coastguard Worker static void *
508*1208bc7eSAndroid Build Coastguard Worker background_thread_entry(void *ind_arg) {
509*1208bc7eSAndroid Build Coastguard Worker unsigned thread_ind = (unsigned)(uintptr_t)ind_arg;
510*1208bc7eSAndroid Build Coastguard Worker assert(thread_ind < max_background_threads);
511*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_HAVE_PTHREAD_SETNAME_NP
512*1208bc7eSAndroid Build Coastguard Worker pthread_setname_np(pthread_self(), "jemalloc_bg_thd");
513*1208bc7eSAndroid Build Coastguard Worker #endif
514*1208bc7eSAndroid Build Coastguard Worker if (opt_percpu_arena != percpu_arena_disabled) {
515*1208bc7eSAndroid Build Coastguard Worker set_current_thread_affinity((int)thread_ind);
516*1208bc7eSAndroid Build Coastguard Worker }
517*1208bc7eSAndroid Build Coastguard Worker /*
518*1208bc7eSAndroid Build Coastguard Worker * Start periodic background work. We use internal tsd which avoids
519*1208bc7eSAndroid Build Coastguard Worker * side effects, for example triggering new arena creation (which in
520*1208bc7eSAndroid Build Coastguard Worker * turn triggers another background thread creation).
521*1208bc7eSAndroid Build Coastguard Worker */
522*1208bc7eSAndroid Build Coastguard Worker background_work(tsd_internal_fetch(), thread_ind);
523*1208bc7eSAndroid Build Coastguard Worker assert(pthread_equal(pthread_self(),
524*1208bc7eSAndroid Build Coastguard Worker background_thread_info[thread_ind].thread));
525*1208bc7eSAndroid Build Coastguard Worker
526*1208bc7eSAndroid Build Coastguard Worker return NULL;
527*1208bc7eSAndroid Build Coastguard Worker }
528*1208bc7eSAndroid Build Coastguard Worker
529*1208bc7eSAndroid Build Coastguard Worker static void
530*1208bc7eSAndroid Build Coastguard Worker background_thread_init(tsd_t *tsd, background_thread_info_t *info) {
531*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
532*1208bc7eSAndroid Build Coastguard Worker info->state = background_thread_started;
533*1208bc7eSAndroid Build Coastguard Worker background_thread_info_init(tsd_tsdn(tsd), info);
534*1208bc7eSAndroid Build Coastguard Worker n_background_threads++;
535*1208bc7eSAndroid Build Coastguard Worker }
536*1208bc7eSAndroid Build Coastguard Worker
537*1208bc7eSAndroid Build Coastguard Worker /* Create a new background thread if needed. */
538*1208bc7eSAndroid Build Coastguard Worker bool
539*1208bc7eSAndroid Build Coastguard Worker background_thread_create(tsd_t *tsd, unsigned arena_ind) {
540*1208bc7eSAndroid Build Coastguard Worker assert(have_background_thread);
541*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
542*1208bc7eSAndroid Build Coastguard Worker
543*1208bc7eSAndroid Build Coastguard Worker /* We create at most NCPUs threads. */
544*1208bc7eSAndroid Build Coastguard Worker size_t thread_ind = arena_ind % max_background_threads;
545*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *info = &background_thread_info[thread_ind];
546*1208bc7eSAndroid Build Coastguard Worker
547*1208bc7eSAndroid Build Coastguard Worker bool need_new_thread;
548*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
549*1208bc7eSAndroid Build Coastguard Worker need_new_thread = background_thread_enabled() &&
550*1208bc7eSAndroid Build Coastguard Worker (info->state == background_thread_stopped);
551*1208bc7eSAndroid Build Coastguard Worker if (need_new_thread) {
552*1208bc7eSAndroid Build Coastguard Worker background_thread_init(tsd, info);
553*1208bc7eSAndroid Build Coastguard Worker }
554*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
555*1208bc7eSAndroid Build Coastguard Worker if (!need_new_thread) {
556*1208bc7eSAndroid Build Coastguard Worker return false;
557*1208bc7eSAndroid Build Coastguard Worker }
558*1208bc7eSAndroid Build Coastguard Worker if (arena_ind != 0) {
559*1208bc7eSAndroid Build Coastguard Worker /* Threads are created asynchronously by Thread 0. */
560*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *t0 = &background_thread_info[0];
561*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsd_tsdn(tsd), &t0->mtx);
562*1208bc7eSAndroid Build Coastguard Worker assert(t0->state == background_thread_started);
563*1208bc7eSAndroid Build Coastguard Worker pthread_cond_signal(&t0->cond);
564*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsd_tsdn(tsd), &t0->mtx);
565*1208bc7eSAndroid Build Coastguard Worker
566*1208bc7eSAndroid Build Coastguard Worker return false;
567*1208bc7eSAndroid Build Coastguard Worker }
568*1208bc7eSAndroid Build Coastguard Worker
569*1208bc7eSAndroid Build Coastguard Worker pre_reentrancy(tsd, NULL);
570*1208bc7eSAndroid Build Coastguard Worker /*
571*1208bc7eSAndroid Build Coastguard Worker * To avoid complications (besides reentrancy), create internal
572*1208bc7eSAndroid Build Coastguard Worker * background threads with the underlying pthread_create.
573*1208bc7eSAndroid Build Coastguard Worker */
574*1208bc7eSAndroid Build Coastguard Worker int err = background_thread_create_signals_masked(&info->thread, NULL,
575*1208bc7eSAndroid Build Coastguard Worker background_thread_entry, (void *)thread_ind);
576*1208bc7eSAndroid Build Coastguard Worker post_reentrancy(tsd);
577*1208bc7eSAndroid Build Coastguard Worker
578*1208bc7eSAndroid Build Coastguard Worker if (err != 0) {
579*1208bc7eSAndroid Build Coastguard Worker malloc_printf("<jemalloc>: arena 0 background thread creation "
580*1208bc7eSAndroid Build Coastguard Worker "failed (%d)\n", err);
581*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
582*1208bc7eSAndroid Build Coastguard Worker info->state = background_thread_stopped;
583*1208bc7eSAndroid Build Coastguard Worker n_background_threads--;
584*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
585*1208bc7eSAndroid Build Coastguard Worker
586*1208bc7eSAndroid Build Coastguard Worker return true;
587*1208bc7eSAndroid Build Coastguard Worker }
588*1208bc7eSAndroid Build Coastguard Worker
589*1208bc7eSAndroid Build Coastguard Worker return false;
590*1208bc7eSAndroid Build Coastguard Worker }
591*1208bc7eSAndroid Build Coastguard Worker
592*1208bc7eSAndroid Build Coastguard Worker bool
593*1208bc7eSAndroid Build Coastguard Worker background_threads_enable(tsd_t *tsd) {
594*1208bc7eSAndroid Build Coastguard Worker assert(n_background_threads == 0);
595*1208bc7eSAndroid Build Coastguard Worker assert(background_thread_enabled());
596*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
597*1208bc7eSAndroid Build Coastguard Worker
598*1208bc7eSAndroid Build Coastguard Worker VARIABLE_ARRAY(bool, marked, max_background_threads);
599*1208bc7eSAndroid Build Coastguard Worker unsigned i, nmarked;
600*1208bc7eSAndroid Build Coastguard Worker for (i = 0; i < max_background_threads; i++) {
601*1208bc7eSAndroid Build Coastguard Worker marked[i] = false;
602*1208bc7eSAndroid Build Coastguard Worker }
603*1208bc7eSAndroid Build Coastguard Worker nmarked = 0;
604*1208bc7eSAndroid Build Coastguard Worker /* Thread 0 is required and created at the end. */
605*1208bc7eSAndroid Build Coastguard Worker marked[0] = true;
606*1208bc7eSAndroid Build Coastguard Worker /* Mark the threads we need to create for thread 0. */
607*1208bc7eSAndroid Build Coastguard Worker unsigned n = narenas_total_get();
608*1208bc7eSAndroid Build Coastguard Worker for (i = 1; i < n; i++) {
609*1208bc7eSAndroid Build Coastguard Worker if (marked[i % max_background_threads] ||
610*1208bc7eSAndroid Build Coastguard Worker arena_get(tsd_tsdn(tsd), i, false) == NULL) {
611*1208bc7eSAndroid Build Coastguard Worker continue;
612*1208bc7eSAndroid Build Coastguard Worker }
613*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *info = &background_thread_info[
614*1208bc7eSAndroid Build Coastguard Worker i % max_background_threads];
615*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
616*1208bc7eSAndroid Build Coastguard Worker assert(info->state == background_thread_stopped);
617*1208bc7eSAndroid Build Coastguard Worker background_thread_init(tsd, info);
618*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
619*1208bc7eSAndroid Build Coastguard Worker marked[i % max_background_threads] = true;
620*1208bc7eSAndroid Build Coastguard Worker if (++nmarked == max_background_threads) {
621*1208bc7eSAndroid Build Coastguard Worker break;
622*1208bc7eSAndroid Build Coastguard Worker }
623*1208bc7eSAndroid Build Coastguard Worker }
624*1208bc7eSAndroid Build Coastguard Worker
625*1208bc7eSAndroid Build Coastguard Worker return background_thread_create(tsd, 0);
626*1208bc7eSAndroid Build Coastguard Worker }
627*1208bc7eSAndroid Build Coastguard Worker
628*1208bc7eSAndroid Build Coastguard Worker bool
629*1208bc7eSAndroid Build Coastguard Worker background_threads_disable(tsd_t *tsd) {
630*1208bc7eSAndroid Build Coastguard Worker assert(!background_thread_enabled());
631*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
632*1208bc7eSAndroid Build Coastguard Worker
633*1208bc7eSAndroid Build Coastguard Worker /* Thread 0 will be responsible for terminating other threads. */
634*1208bc7eSAndroid Build Coastguard Worker if (background_threads_disable_single(tsd,
635*1208bc7eSAndroid Build Coastguard Worker &background_thread_info[0])) {
636*1208bc7eSAndroid Build Coastguard Worker return true;
637*1208bc7eSAndroid Build Coastguard Worker }
638*1208bc7eSAndroid Build Coastguard Worker assert(n_background_threads == 0);
639*1208bc7eSAndroid Build Coastguard Worker
640*1208bc7eSAndroid Build Coastguard Worker return false;
641*1208bc7eSAndroid Build Coastguard Worker }
642*1208bc7eSAndroid Build Coastguard Worker
643*1208bc7eSAndroid Build Coastguard Worker /* Check if we need to signal the background thread early. */
644*1208bc7eSAndroid Build Coastguard Worker void
645*1208bc7eSAndroid Build Coastguard Worker background_thread_interval_check(tsdn_t *tsdn, arena_t *arena,
646*1208bc7eSAndroid Build Coastguard Worker arena_decay_t *decay, size_t npages_new) {
647*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *info = arena_background_thread_info_get(
648*1208bc7eSAndroid Build Coastguard Worker arena);
649*1208bc7eSAndroid Build Coastguard Worker if (malloc_mutex_trylock(tsdn, &info->mtx)) {
650*1208bc7eSAndroid Build Coastguard Worker /*
651*1208bc7eSAndroid Build Coastguard Worker * Background thread may hold the mutex for a long period of
652*1208bc7eSAndroid Build Coastguard Worker * time. We'd like to avoid the variance on application
653*1208bc7eSAndroid Build Coastguard Worker * threads. So keep this non-blocking, and leave the work to a
654*1208bc7eSAndroid Build Coastguard Worker * future epoch.
655*1208bc7eSAndroid Build Coastguard Worker */
656*1208bc7eSAndroid Build Coastguard Worker return;
657*1208bc7eSAndroid Build Coastguard Worker }
658*1208bc7eSAndroid Build Coastguard Worker
659*1208bc7eSAndroid Build Coastguard Worker if (info->state != background_thread_started) {
660*1208bc7eSAndroid Build Coastguard Worker goto label_done;
661*1208bc7eSAndroid Build Coastguard Worker }
662*1208bc7eSAndroid Build Coastguard Worker if (malloc_mutex_trylock(tsdn, &decay->mtx)) {
663*1208bc7eSAndroid Build Coastguard Worker goto label_done;
664*1208bc7eSAndroid Build Coastguard Worker }
665*1208bc7eSAndroid Build Coastguard Worker
666*1208bc7eSAndroid Build Coastguard Worker ssize_t decay_time = atomic_load_zd(&decay->time_ms, ATOMIC_RELAXED);
667*1208bc7eSAndroid Build Coastguard Worker if (decay_time <= 0) {
668*1208bc7eSAndroid Build Coastguard Worker /* Purging is eagerly done or disabled currently. */
669*1208bc7eSAndroid Build Coastguard Worker goto label_done_unlock2;
670*1208bc7eSAndroid Build Coastguard Worker }
671*1208bc7eSAndroid Build Coastguard Worker uint64_t decay_interval_ns = nstime_ns(&decay->interval);
672*1208bc7eSAndroid Build Coastguard Worker assert(decay_interval_ns > 0);
673*1208bc7eSAndroid Build Coastguard Worker
674*1208bc7eSAndroid Build Coastguard Worker nstime_t diff;
675*1208bc7eSAndroid Build Coastguard Worker nstime_init(&diff, background_thread_wakeup_time_get(info));
676*1208bc7eSAndroid Build Coastguard Worker if (nstime_compare(&diff, &decay->epoch) <= 0) {
677*1208bc7eSAndroid Build Coastguard Worker goto label_done_unlock2;
678*1208bc7eSAndroid Build Coastguard Worker }
679*1208bc7eSAndroid Build Coastguard Worker nstime_subtract(&diff, &decay->epoch);
680*1208bc7eSAndroid Build Coastguard Worker if (nstime_ns(&diff) < BACKGROUND_THREAD_MIN_INTERVAL_NS) {
681*1208bc7eSAndroid Build Coastguard Worker goto label_done_unlock2;
682*1208bc7eSAndroid Build Coastguard Worker }
683*1208bc7eSAndroid Build Coastguard Worker
684*1208bc7eSAndroid Build Coastguard Worker if (npages_new > 0) {
685*1208bc7eSAndroid Build Coastguard Worker size_t n_epoch = (size_t)(nstime_ns(&diff) / decay_interval_ns);
686*1208bc7eSAndroid Build Coastguard Worker /*
687*1208bc7eSAndroid Build Coastguard Worker * Compute how many new pages we would need to purge by the next
688*1208bc7eSAndroid Build Coastguard Worker * wakeup, which is used to determine if we should signal the
689*1208bc7eSAndroid Build Coastguard Worker * background thread.
690*1208bc7eSAndroid Build Coastguard Worker */
691*1208bc7eSAndroid Build Coastguard Worker uint64_t npurge_new;
692*1208bc7eSAndroid Build Coastguard Worker if (n_epoch >= SMOOTHSTEP_NSTEPS) {
693*1208bc7eSAndroid Build Coastguard Worker npurge_new = npages_new;
694*1208bc7eSAndroid Build Coastguard Worker } else {
695*1208bc7eSAndroid Build Coastguard Worker uint64_t h_steps_max = h_steps[SMOOTHSTEP_NSTEPS - 1];
696*1208bc7eSAndroid Build Coastguard Worker assert(h_steps_max >=
697*1208bc7eSAndroid Build Coastguard Worker h_steps[SMOOTHSTEP_NSTEPS - 1 - n_epoch]);
698*1208bc7eSAndroid Build Coastguard Worker npurge_new = npages_new * (h_steps_max -
699*1208bc7eSAndroid Build Coastguard Worker h_steps[SMOOTHSTEP_NSTEPS - 1 - n_epoch]);
700*1208bc7eSAndroid Build Coastguard Worker npurge_new >>= SMOOTHSTEP_BFP;
701*1208bc7eSAndroid Build Coastguard Worker }
702*1208bc7eSAndroid Build Coastguard Worker info->npages_to_purge_new += npurge_new;
703*1208bc7eSAndroid Build Coastguard Worker }
704*1208bc7eSAndroid Build Coastguard Worker
705*1208bc7eSAndroid Build Coastguard Worker bool should_signal;
706*1208bc7eSAndroid Build Coastguard Worker if (info->npages_to_purge_new > BACKGROUND_THREAD_NPAGES_THRESHOLD) {
707*1208bc7eSAndroid Build Coastguard Worker should_signal = true;
708*1208bc7eSAndroid Build Coastguard Worker } else if (unlikely(background_thread_indefinite_sleep(info)) &&
709*1208bc7eSAndroid Build Coastguard Worker (extents_npages_get(&arena->extents_dirty) > 0 ||
710*1208bc7eSAndroid Build Coastguard Worker extents_npages_get(&arena->extents_muzzy) > 0 ||
711*1208bc7eSAndroid Build Coastguard Worker info->npages_to_purge_new > 0)) {
712*1208bc7eSAndroid Build Coastguard Worker should_signal = true;
713*1208bc7eSAndroid Build Coastguard Worker } else {
714*1208bc7eSAndroid Build Coastguard Worker should_signal = false;
715*1208bc7eSAndroid Build Coastguard Worker }
716*1208bc7eSAndroid Build Coastguard Worker
717*1208bc7eSAndroid Build Coastguard Worker if (should_signal) {
718*1208bc7eSAndroid Build Coastguard Worker info->npages_to_purge_new = 0;
719*1208bc7eSAndroid Build Coastguard Worker pthread_cond_signal(&info->cond);
720*1208bc7eSAndroid Build Coastguard Worker }
721*1208bc7eSAndroid Build Coastguard Worker label_done_unlock2:
722*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &decay->mtx);
723*1208bc7eSAndroid Build Coastguard Worker label_done:
724*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &info->mtx);
725*1208bc7eSAndroid Build Coastguard Worker }
726*1208bc7eSAndroid Build Coastguard Worker
727*1208bc7eSAndroid Build Coastguard Worker void
728*1208bc7eSAndroid Build Coastguard Worker background_thread_prefork0(tsdn_t *tsdn) {
729*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_prefork(tsdn, &background_thread_lock);
730*1208bc7eSAndroid Build Coastguard Worker background_thread_enabled_at_fork = background_thread_enabled();
731*1208bc7eSAndroid Build Coastguard Worker }
732*1208bc7eSAndroid Build Coastguard Worker
733*1208bc7eSAndroid Build Coastguard Worker void
734*1208bc7eSAndroid Build Coastguard Worker background_thread_prefork1(tsdn_t *tsdn) {
735*1208bc7eSAndroid Build Coastguard Worker for (unsigned i = 0; i < max_background_threads; i++) {
736*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_prefork(tsdn, &background_thread_info[i].mtx);
737*1208bc7eSAndroid Build Coastguard Worker }
738*1208bc7eSAndroid Build Coastguard Worker }
739*1208bc7eSAndroid Build Coastguard Worker
740*1208bc7eSAndroid Build Coastguard Worker void
741*1208bc7eSAndroid Build Coastguard Worker background_thread_postfork_parent(tsdn_t *tsdn) {
742*1208bc7eSAndroid Build Coastguard Worker for (unsigned i = 0; i < max_background_threads; i++) {
743*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_postfork_parent(tsdn,
744*1208bc7eSAndroid Build Coastguard Worker &background_thread_info[i].mtx);
745*1208bc7eSAndroid Build Coastguard Worker }
746*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_postfork_parent(tsdn, &background_thread_lock);
747*1208bc7eSAndroid Build Coastguard Worker }
748*1208bc7eSAndroid Build Coastguard Worker
749*1208bc7eSAndroid Build Coastguard Worker void
750*1208bc7eSAndroid Build Coastguard Worker background_thread_postfork_child(tsdn_t *tsdn) {
751*1208bc7eSAndroid Build Coastguard Worker for (unsigned i = 0; i < max_background_threads; i++) {
752*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_postfork_child(tsdn,
753*1208bc7eSAndroid Build Coastguard Worker &background_thread_info[i].mtx);
754*1208bc7eSAndroid Build Coastguard Worker }
755*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_postfork_child(tsdn, &background_thread_lock);
756*1208bc7eSAndroid Build Coastguard Worker if (!background_thread_enabled_at_fork) {
757*1208bc7eSAndroid Build Coastguard Worker return;
758*1208bc7eSAndroid Build Coastguard Worker }
759*1208bc7eSAndroid Build Coastguard Worker
760*1208bc7eSAndroid Build Coastguard Worker /* Clear background_thread state (reset to disabled for child). */
761*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &background_thread_lock);
762*1208bc7eSAndroid Build Coastguard Worker n_background_threads = 0;
763*1208bc7eSAndroid Build Coastguard Worker background_thread_enabled_set(tsdn, false);
764*1208bc7eSAndroid Build Coastguard Worker for (unsigned i = 0; i < max_background_threads; i++) {
765*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *info = &background_thread_info[i];
766*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &info->mtx);
767*1208bc7eSAndroid Build Coastguard Worker info->state = background_thread_stopped;
768*1208bc7eSAndroid Build Coastguard Worker int ret = pthread_cond_init(&info->cond, NULL);
769*1208bc7eSAndroid Build Coastguard Worker assert(ret == 0);
770*1208bc7eSAndroid Build Coastguard Worker background_thread_info_init(tsdn, info);
771*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &info->mtx);
772*1208bc7eSAndroid Build Coastguard Worker }
773*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &background_thread_lock);
774*1208bc7eSAndroid Build Coastguard Worker }
775*1208bc7eSAndroid Build Coastguard Worker
776*1208bc7eSAndroid Build Coastguard Worker bool
777*1208bc7eSAndroid Build Coastguard Worker background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) {
778*1208bc7eSAndroid Build Coastguard Worker assert(config_stats);
779*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &background_thread_lock);
780*1208bc7eSAndroid Build Coastguard Worker if (!background_thread_enabled()) {
781*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &background_thread_lock);
782*1208bc7eSAndroid Build Coastguard Worker return true;
783*1208bc7eSAndroid Build Coastguard Worker }
784*1208bc7eSAndroid Build Coastguard Worker
785*1208bc7eSAndroid Build Coastguard Worker stats->num_threads = n_background_threads;
786*1208bc7eSAndroid Build Coastguard Worker uint64_t num_runs = 0;
787*1208bc7eSAndroid Build Coastguard Worker nstime_init(&stats->run_interval, 0);
788*1208bc7eSAndroid Build Coastguard Worker for (unsigned i = 0; i < max_background_threads; i++) {
789*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *info = &background_thread_info[i];
790*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &info->mtx);
791*1208bc7eSAndroid Build Coastguard Worker if (info->state != background_thread_stopped) {
792*1208bc7eSAndroid Build Coastguard Worker num_runs += info->tot_n_runs;
793*1208bc7eSAndroid Build Coastguard Worker nstime_add(&stats->run_interval, &info->tot_sleep_time);
794*1208bc7eSAndroid Build Coastguard Worker }
795*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &info->mtx);
796*1208bc7eSAndroid Build Coastguard Worker }
797*1208bc7eSAndroid Build Coastguard Worker stats->num_runs = num_runs;
798*1208bc7eSAndroid Build Coastguard Worker if (num_runs > 0) {
799*1208bc7eSAndroid Build Coastguard Worker nstime_idivide(&stats->run_interval, num_runs);
800*1208bc7eSAndroid Build Coastguard Worker }
801*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &background_thread_lock);
802*1208bc7eSAndroid Build Coastguard Worker
803*1208bc7eSAndroid Build Coastguard Worker return false;
804*1208bc7eSAndroid Build Coastguard Worker }
805*1208bc7eSAndroid Build Coastguard Worker
806*1208bc7eSAndroid Build Coastguard Worker #undef BACKGROUND_THREAD_NPAGES_THRESHOLD
807*1208bc7eSAndroid Build Coastguard Worker #undef BILLION
808*1208bc7eSAndroid Build Coastguard Worker #undef BACKGROUND_THREAD_MIN_INTERVAL_NS
809*1208bc7eSAndroid Build Coastguard Worker
810*1208bc7eSAndroid Build Coastguard Worker static bool
811*1208bc7eSAndroid Build Coastguard Worker pthread_create_fptr_init(void) {
812*1208bc7eSAndroid Build Coastguard Worker if (pthread_create_fptr != NULL) {
813*1208bc7eSAndroid Build Coastguard Worker return false;
814*1208bc7eSAndroid Build Coastguard Worker }
815*1208bc7eSAndroid Build Coastguard Worker pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create");
816*1208bc7eSAndroid Build Coastguard Worker if (pthread_create_fptr == NULL) {
817*1208bc7eSAndroid Build Coastguard Worker can_enable_background_thread = false;
818*1208bc7eSAndroid Build Coastguard Worker if (config_lazy_lock || opt_background_thread) {
819*1208bc7eSAndroid Build Coastguard Worker malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, "
820*1208bc7eSAndroid Build Coastguard Worker "\"pthread_create\")\n");
821*1208bc7eSAndroid Build Coastguard Worker abort();
822*1208bc7eSAndroid Build Coastguard Worker }
823*1208bc7eSAndroid Build Coastguard Worker } else {
824*1208bc7eSAndroid Build Coastguard Worker can_enable_background_thread = true;
825*1208bc7eSAndroid Build Coastguard Worker }
826*1208bc7eSAndroid Build Coastguard Worker
827*1208bc7eSAndroid Build Coastguard Worker return false;
828*1208bc7eSAndroid Build Coastguard Worker }
829*1208bc7eSAndroid Build Coastguard Worker
830*1208bc7eSAndroid Build Coastguard Worker /*
831*1208bc7eSAndroid Build Coastguard Worker * When lazy lock is enabled, we need to make sure setting isthreaded before
832*1208bc7eSAndroid Build Coastguard Worker * taking any background_thread locks. This is called early in ctl (instead of
833*1208bc7eSAndroid Build Coastguard Worker * wait for the pthread_create calls to trigger) because the mutex is required
834*1208bc7eSAndroid Build Coastguard Worker * before creating background threads.
835*1208bc7eSAndroid Build Coastguard Worker */
836*1208bc7eSAndroid Build Coastguard Worker void
837*1208bc7eSAndroid Build Coastguard Worker background_thread_ctl_init(tsdn_t *tsdn) {
838*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_not_owner(tsdn, &background_thread_lock);
839*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
840*1208bc7eSAndroid Build Coastguard Worker pthread_create_fptr_init();
841*1208bc7eSAndroid Build Coastguard Worker pthread_create_wrapper_init();
842*1208bc7eSAndroid Build Coastguard Worker #endif
843*1208bc7eSAndroid Build Coastguard Worker }
844*1208bc7eSAndroid Build Coastguard Worker
845*1208bc7eSAndroid Build Coastguard Worker #endif /* defined(JEMALLOC_BACKGROUND_THREAD) */
846*1208bc7eSAndroid Build Coastguard Worker
847*1208bc7eSAndroid Build Coastguard Worker bool
848*1208bc7eSAndroid Build Coastguard Worker background_thread_boot0(void) {
849*1208bc7eSAndroid Build Coastguard Worker if (!have_background_thread && opt_background_thread) {
850*1208bc7eSAndroid Build Coastguard Worker malloc_printf("<jemalloc>: option background_thread currently "
851*1208bc7eSAndroid Build Coastguard Worker "supports pthread only\n");
852*1208bc7eSAndroid Build Coastguard Worker return true;
853*1208bc7eSAndroid Build Coastguard Worker }
854*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
855*1208bc7eSAndroid Build Coastguard Worker if ((config_lazy_lock || opt_background_thread) &&
856*1208bc7eSAndroid Build Coastguard Worker pthread_create_fptr_init()) {
857*1208bc7eSAndroid Build Coastguard Worker return true;
858*1208bc7eSAndroid Build Coastguard Worker }
859*1208bc7eSAndroid Build Coastguard Worker #endif
860*1208bc7eSAndroid Build Coastguard Worker return false;
861*1208bc7eSAndroid Build Coastguard Worker }
862*1208bc7eSAndroid Build Coastguard Worker
863*1208bc7eSAndroid Build Coastguard Worker bool
background_thread_boot1(tsdn_t * tsdn)864*1208bc7eSAndroid Build Coastguard Worker background_thread_boot1(tsdn_t *tsdn) {
865*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_BACKGROUND_THREAD
866*1208bc7eSAndroid Build Coastguard Worker assert(have_background_thread);
867*1208bc7eSAndroid Build Coastguard Worker assert(narenas_total_get() > 0);
868*1208bc7eSAndroid Build Coastguard Worker
869*1208bc7eSAndroid Build Coastguard Worker if (opt_max_background_threads == MAX_BACKGROUND_THREAD_LIMIT &&
870*1208bc7eSAndroid Build Coastguard Worker ncpus < MAX_BACKGROUND_THREAD_LIMIT) {
871*1208bc7eSAndroid Build Coastguard Worker opt_max_background_threads = ncpus;
872*1208bc7eSAndroid Build Coastguard Worker }
873*1208bc7eSAndroid Build Coastguard Worker max_background_threads = opt_max_background_threads;
874*1208bc7eSAndroid Build Coastguard Worker
875*1208bc7eSAndroid Build Coastguard Worker background_thread_enabled_set(tsdn, opt_background_thread);
876*1208bc7eSAndroid Build Coastguard Worker if (malloc_mutex_init(&background_thread_lock,
877*1208bc7eSAndroid Build Coastguard Worker "background_thread_global",
878*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_BACKGROUND_THREAD_GLOBAL,
879*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_rank_exclusive)) {
880*1208bc7eSAndroid Build Coastguard Worker return true;
881*1208bc7eSAndroid Build Coastguard Worker }
882*1208bc7eSAndroid Build Coastguard Worker
883*1208bc7eSAndroid Build Coastguard Worker background_thread_info = (background_thread_info_t *)base_alloc(tsdn,
884*1208bc7eSAndroid Build Coastguard Worker b0get(), opt_max_background_threads *
885*1208bc7eSAndroid Build Coastguard Worker sizeof(background_thread_info_t), CACHELINE);
886*1208bc7eSAndroid Build Coastguard Worker if (background_thread_info == NULL) {
887*1208bc7eSAndroid Build Coastguard Worker return true;
888*1208bc7eSAndroid Build Coastguard Worker }
889*1208bc7eSAndroid Build Coastguard Worker
890*1208bc7eSAndroid Build Coastguard Worker for (unsigned i = 0; i < max_background_threads; i++) {
891*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *info = &background_thread_info[i];
892*1208bc7eSAndroid Build Coastguard Worker /* Thread mutex is rank_inclusive because of thread0. */
893*1208bc7eSAndroid Build Coastguard Worker if (malloc_mutex_init(&info->mtx, "background_thread",
894*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_BACKGROUND_THREAD,
895*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_address_ordered)) {
896*1208bc7eSAndroid Build Coastguard Worker return true;
897*1208bc7eSAndroid Build Coastguard Worker }
898*1208bc7eSAndroid Build Coastguard Worker if (pthread_cond_init(&info->cond, NULL)) {
899*1208bc7eSAndroid Build Coastguard Worker return true;
900*1208bc7eSAndroid Build Coastguard Worker }
901*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &info->mtx);
902*1208bc7eSAndroid Build Coastguard Worker info->state = background_thread_stopped;
903*1208bc7eSAndroid Build Coastguard Worker background_thread_info_init(tsdn, info);
904*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &info->mtx);
905*1208bc7eSAndroid Build Coastguard Worker }
906*1208bc7eSAndroid Build Coastguard Worker #endif
907*1208bc7eSAndroid Build Coastguard Worker
908*1208bc7eSAndroid Build Coastguard Worker return false;
909*1208bc7eSAndroid Build Coastguard Worker }
910