3 # define _GNU_SOURCE /* TODO: confirm this is needed */
9 #include "git_version.h"
10 #include "sleepy_penguin.h"
11 #define L1_CACHE_LINE_MAX 128 /* largest I've seen (Pentium 4) */
12 size_t rb_sp_l1_cache_line_size
;
13 static pthread_key_t rb_sp_key
;
14 enum rb_sp_tls_buf_type
{
17 RB_SP_TLS_MALLOCED
= 1
22 enum rb_sp_tls_buf_type buf_type
;
23 unsigned char ptr
[FLEX_ARRAY
];
26 #ifdef HAVE_SYS_EVENT_H
27 void sleepy_penguin_init_kqueue(void);
29 # define sleepy_penguin_init_kqueue() for(;0;)
32 #ifdef HAVE_SYS_EPOLL_H
33 void sleepy_penguin_init_epoll(void);
35 # define sleepy_penguin_init_epoll() for(;0;)
38 #ifdef HAVE_SYS_TIMERFD_H
39 void sleepy_penguin_init_timerfd(void);
41 # define sleepy_penguin_init_timerfd() for(;0;)
44 #ifdef HAVE_SYS_EVENTFD_H
45 void sleepy_penguin_init_eventfd(void);
47 # define sleepy_penguin_init_eventfd() for(;0;)
50 #ifdef HAVE_SYS_INOTIFY_H
51 void sleepy_penguin_init_inotify(void);
53 # define sleepy_penguin_init_inotify() for(;0;)
56 #ifdef HAVE_SYS_SIGNALFD_H
57 void sleepy_penguin_init_signalfd(void);
59 # define sleepy_penguin_init_signalfd() for(;0;)
63 void sleepy_penguin_init_splice(void);
65 # define sleepy_penguin_init_splice() for(;0;)
68 #if defined(HAVE_COPY_FILE_RANGE) || \
69 (defined(__linux__) && defined(__NR_copy_file_range))
70 void sleepy_penguin_init_cfr(void);
72 # define sleepy_penguin_init_cfr() for (;0;)
76 void sleepy_penguin_init_sendfile(void);
78 static size_t l1_cache_line_size_detect(void)
80 #ifdef _SC_LEVEL1_DCACHE_LINESIZE
81 long tmp
= sysconf(_SC_LEVEL1_DCACHE_LINESIZE
);
83 if (tmp
> 0 && tmp
<= L1_CACHE_LINE_MAX
)
85 #endif /* _SC_LEVEL1_DCACHE_LINESIZE */
86 return L1_CACHE_LINE_MAX
;
89 static void sp_once(void)
91 int err
= pthread_key_create(&rb_sp_key
, free
);
95 rb_sys_fail( "pthread_key_create");
99 static struct rb_sp_tlsbuf
*alloc_tlsbuf(size_t size
)
101 size_t bytes
= size
+ sizeof(struct rb_sp_tlsbuf
);
102 struct rb_sp_tlsbuf
*buf
;
105 if (size
>= UINT32_MAX
||
106 posix_memalign(&ptr
, rb_sp_l1_cache_line_size
, bytes
))
107 rb_memerror(); /* fatal */
110 buf
->capa
= (uint32_t)size
;
115 void *rb_sp_gettlsbuf(size_t *size
)
117 struct rb_sp_tlsbuf
*buf
= pthread_getspecific(rb_sp_key
);
120 assert(buf
? buf
->buf_type
!= RB_SP_TLS_MALLOCED
: 1);
122 if (buf
&& buf
->buf_type
!= RB_SP_TLS_READY
) {
123 buf
= alloc_tlsbuf(*size
);
124 buf
->buf_type
= RB_SP_TLS_MALLOCED
;
128 if (buf
&& buf
->capa
>= *size
) {
134 buf
= alloc_tlsbuf(*size
);
135 err
= pthread_setspecific(rb_sp_key
, buf
);
139 rb_sys_fail("BUG: pthread_setspecific");
142 buf
->buf_type
= RB_SP_TLS_INUSE
;
146 #define container_of(ptr, type, member) \
147 (type *)((uintptr_t)(ptr) - offsetof(type, member))
149 VALUE
rb_sp_puttlsbuf(VALUE p
)
151 struct rb_sp_tlsbuf
*tls
= pthread_getspecific(rb_sp_key
);
152 void *ptr
= (void *)p
;
153 struct rb_sp_tlsbuf
*buf
;
158 buf
= container_of(ptr
, struct rb_sp_tlsbuf
, ptr
);
160 switch (buf
->buf_type
) {
161 case RB_SP_TLS_INUSE
:
162 assert(tls
== buf
&& "rb_sp_puttlsbuf mismatch");
163 buf
->buf_type
= RB_SP_TLS_READY
;
165 case RB_SP_TLS_READY
:
166 assert(0 && "rb_sp_gettlsbuf not called");
167 case RB_SP_TLS_MALLOCED
:
173 void Init_sleepy_penguin_ext(void)
175 VALUE mSleepyPenguin
;
176 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
177 int err
= pthread_once(&once
, sp_once
);
181 rb_sys_fail("pthread_once");
184 rb_sp_l1_cache_line_size
= l1_cache_line_size_detect();
186 mSleepyPenguin
= rb_define_module("SleepyPenguin");
187 rb_define_const(mSleepyPenguin
, "SLEEPY_PENGUIN_VERSION",
188 rb_str_new2(MY_GIT_VERSION
));
190 sleepy_penguin_init_kqueue();
191 sleepy_penguin_init_epoll();
192 sleepy_penguin_init_timerfd();
193 sleepy_penguin_init_eventfd();
194 sleepy_penguin_init_inotify();
195 sleepy_penguin_init_signalfd();
196 sleepy_penguin_init_splice();
197 sleepy_penguin_init_cfr();
198 sleepy_penguin_init_sendfile();