26#ifndef XTC_CORO_COMMON_H
27#define XTC_CORO_COMMON_H
36#include "preempt_int.h"
50#if defined(XTC_HAVE_VALGRIND_H)
51# include <valgrind/valgrind.h>
57static _Atomic
int __xtc_vg_on = -1;
59__attribute__((noinline, cold))
static unsigned
60__xtc_vg_register_slow(
char *lo,
size_t sz)
62 int on = atomic_load_explicit(&__xtc_vg_on, memory_order_relaxed);
64 on = RUNNING_ON_VALGRIND != 0;
65 atomic_store_explicit(&__xtc_vg_on, on, memory_order_relaxed);
67 return on ? (unsigned)VALGRIND_STACK_REGISTER(lo, lo + sz) : 0u;
72__attribute__((noinline, cold))
static void
73__xtc_vg_deregister_slow(
unsigned id)
75 VALGRIND_STACK_DEREGISTER(
id);
78# define __xtc_vg_stack_register(lo, sz) \
79 (XTC_UNLIKELY(atomic_load_explicit(&__xtc_vg_on, \
80 memory_order_relaxed) != 0) ? \
81 __xtc_vg_register_slow((char *)(lo), (sz)) : 0u)
82# define __xtc_vg_stack_deregister(id) \
84 if (XTC_UNLIKELY(atomic_load_explicit(&__xtc_vg_on, \
85 memory_order_relaxed) > 0)) \
86 __xtc_vg_deregister_slow(id); \
89# define __xtc_vg_stack_register(lo, sz) ((void)(lo), (void)(sz), 0u)
90# define __xtc_vg_stack_deregister(id) ((void)(id))
108#define XTC_STACK_POOL_MAX 64
110 void *slots[XTC_STACK_POOL_MAX];
115static XTC_THREAD_LOCAL
struct stack_pool __stack_pool;
122__stack_pool_drain(
void *arg)
125 long pg = sysconf(_SC_PAGESIZE);
126 size_t guard = pg > 0 ? (size_t)pg : 4096u;
129 (void)munmap(p->slots[--p->n], p->size + guard);
135__stack_pool_get(
size_t stack_sz)
138 if (p->n > 0 && p->size == stack_sz)
139 return p->slots[--p->n];
146__stack_pool_put(
void *base,
size_t stack_sz)
149 if (!p->atexit_armed) {
150 if (__os_thread_atexit(__stack_pool_drain, NULL) != XTC_OK)
154 if (p->n == 0) p->size = stack_sz;
155 if (p->size != stack_sz || p->n == XTC_STACK_POOL_MAX)
157 p->slots[p->n++] = base;
178__stack_spare_lock(xtc_loop_t *l)
180 __xtc_unsafe_enter();
181 while (atomic_exchange_explicit(&l->stack_spare_lock, 1,
182 memory_order_acquire))
183 while (atomic_load_explicit(&l->stack_spare_lock,
184 memory_order_relaxed))
189__stack_spare_unlock(xtc_loop_t *l)
191 atomic_store_explicit(&l->stack_spare_lock, 0, memory_order_release);
192 __xtc_unsafe_leave();
197__stack_spare_get(xtc_loop_t *l,
size_t stack_sz)
201 if (__xtc_current_loop != l &&
202 atomic_load_explicit(&l->stack_spare_want, memory_order_relaxed) <
203 XTC_LOOP_STACK_SPARE)
204 atomic_fetch_add_explicit(&l->stack_spare_want, 1,
205 memory_order_relaxed);
206 if (atomic_load_explicit(&l->stack_spare_n, memory_order_relaxed) == 0)
208 __stack_spare_lock(l);
209 n = atomic_load_explicit(&l->stack_spare_n, memory_order_relaxed);
210 if (n > 0 && l->stack_spare_sz == stack_sz) {
211 base = l->stack_spare[--n];
212 atomic_store_explicit(&l->stack_spare_n, n,
213 memory_order_relaxed);
215 __stack_spare_unlock(l);
222__stack_spare_put(xtc_loop_t *l,
void *base,
size_t stack_sz)
225 if (atomic_load_explicit(&l->stack_spare_want, memory_order_relaxed) <
226 XTC_LOOP_STACK_SPARE ||
227 atomic_load_explicit(&l->stack_spare_n, memory_order_relaxed) >=
228 XTC_LOOP_STACK_SPARE)
230 __stack_spare_lock(l);
231 n = atomic_load_explicit(&l->stack_spare_n, memory_order_relaxed);
233 l->stack_spare_sz = stack_sz;
234 if (l->stack_spare_sz == stack_sz && n < XTC_LOOP_STACK_SPARE) {
235 l->stack_spare[n++] = base;
236 atomic_store_explicit(&l->stack_spare_n, n,
237 memory_order_relaxed);
240 __stack_spare_unlock(l);
246__xtc_coro_stack_spare_fini(xtc_loop_t *l)
248 long pg = sysconf(_SC_PAGESIZE);
249 size_t guard = pg > 0 ? (size_t)pg : 4096u;
250 int n = atomic_load_explicit(&l->stack_spare_n, memory_order_relaxed);
252 (void)munmap(l->stack_spare[--n], l->stack_spare_sz + guard);
253 atomic_store_explicit(&l->stack_spare_n, 0, memory_order_relaxed);
263#if defined(MADV_DONTNEED)
264static _Atomic
int g_reclaim_on = 0;
265static _Atomic
size_t g_reclaim_keep = 0;
266static _Atomic uint64_t g_reclaim_count = 0;
269xtc_stack_reclaim_enable(
size_t keep_bytes)
271 long pg = sysconf(_SC_PAGESIZE);
272 size_t page = (pg > 0) ? (
size_t)pg : 4096u;
275 atomic_store(&g_reclaim_keep, keep_bytes);
276 atomic_store(&g_reclaim_on, 1);
281xtc_stack_reclaim_disable(
void)
283 atomic_store(&g_reclaim_on, 0);
287xtc_stack_reclaim_enabled(
void)
289 return atomic_load(&g_reclaim_on);
293xtc_stack_reclaim_count(
void)
295 return atomic_load(&g_reclaim_count);
308coro_stack_shrink(
struct xtc_coro *c,
void *sp)
312 uintptr_t lo, hi, guard, base;
314 if (c == NULL || c->stack == NULL || !atomic_load(&g_reclaim_on))
316 pgl = sysconf(_SC_PAGESIZE);
317 page = (pgl > 0) ? (
size_t)pgl : 4096u;
319 keep = atomic_load(&g_reclaim_keep);
321 base = (uintptr_t)c->stack + guard;
323 if (hi <= base + keep)
327 hi = (hi - keep) & ~(uintptr_t)(page - 1);
328 lo = (base + page - 1) & ~(uintptr_t)(page - 1);
329 if (hi <= lo || hi - lo < page)
331 if (madvise((
void *)lo, (size_t)(hi - lo), MADV_DONTNEED) == 0)
332 (void)atomic_fetch_add(&g_reclaim_count, 1);
335int xtc_stack_reclaim_enable(
size_t k) { (void)k;
return XTC_E_NOSYS; }
336void xtc_stack_reclaim_disable(
void) { }
337int xtc_stack_reclaim_enabled(
void) {
return 0; }
338uint64_t xtc_stack_reclaim_count(
void) {
return 0; }
339#define coro_stack_shrink(c, sp) ((void)(c), (void)(sp))