Leaving a dangling Ruby object around is suboptimal since it
adds to GC pressure.
`__attribute__((__cleanup__(foo)))' is an old gcc extension to
provide automatic cleanup functionality by running a pre-declared
function at the end of scope.
gcc introduced this two decades ago and clang's had it for over
a decade. Even tinycc supports it since 2019, and I expect it
to be easy to support in any C compiler since they're already
required to do cleanup for on-stack allocations.
So no, it's not standardized in C, but it makes life significantly
easier for C hackers.
---
ext/unicorn_http/epollexclusive.h | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/ext/unicorn_http/epollexclusive.h
b/ext/unicorn_http/epollexclusive.h
index 677e1fe..67a9ba6 100644
--- a/ext/unicorn_http/epollexclusive.h
+++ b/ext/unicorn_http/epollexclusive.h
@@ -78,6 +78,14 @@ static void *do_wait(void *ptr) /* runs w/o GVL */
epw->maxevents, epw->timeout_msec);
}
+/* cleanup is supported since 2003 (gcc), 2009 (clang), tinycc: 2019 */
+#define AUTO_XFREE __attribute__((__cleanup__(cleanup_xfree)))
+static void cleanup_xfree(void *any)
+{
+ void **p = any;
+ xfree(*p);
+}
+
/* :nodoc: */
/* readers must not change between prepare_readers and get_readers */
static VALUE
@@ -85,22 +93,18 @@ get_readers(VALUE epio, VALUE ready, VALUE readers, VALUE
timeout_msec)
{
struct ep_wait epw;
long i, n;
- VALUE buf;
+ AUTO_XFREE void *buf = NULL;
Check_Type(ready, T_ARRAY);
Check_Type(readers, T_ARRAY);
epw.maxevents = RARRAY_LENINT(readers);
- buf = rb_str_buf_new(sizeof(struct epoll_event) * epw.maxevents);
- epw.events = (struct epoll_event *)RSTRING_PTR(buf);
+ epw.events = buf = ALLOC_N(struct epoll_event, epw.maxevents);
epio = rb_io_get_io(epio);
GetOpenFile(epio, epw.fptr);
epw.timeout_msec = NUM2INT(timeout_msec);
n = (long)rb_thread_call_without_gvl(do_wait, &epw, RUBY_UBF_IO, NULL);
- if (n < 0) {
- if (errno != EINTR) rb_sys_fail("epoll_wait");
- n = 0;
- }
+ if (n < 0 && errno != EINTR) rb_sys_fail("epoll_wait");
/* Linux delivers events in order received */
for (i = 0; i < n; i++) {
struct epoll_event *ev = &epw.events[i];
@@ -109,7 +113,6 @@ get_readers(VALUE epio, VALUE ready, VALUE readers, VALUE
timeout_msec)
if (RTEST(obj))
rb_ary_push(ready, obj);
}
- rb_str_resize(buf, 0);
return Qfalse;
}
#endif /* USE_EPOLL */