sleepy_penguin.git  about / heads / tags
Linux I/O events for Ruby
blob 776d6e0d2b5b4ba4f6e957dec695c19a575a0fa8 2781 bytes (raw)
$ git show v3.4.1:ext/sleepy_penguin/init.c	# shows this blob on the CLI

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
 
#include <ruby.h>
#ifndef _GNU_SOURCE
#  define _GNU_SOURCE /* TODO: confirm this is needed */
#endif

#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include "git_version.h"
#include "sleepy_penguin.h"
#define L1_CACHE_LINE_MAX 128 /* largest I've seen (Pentium 4) */
size_t rb_sp_l1_cache_line_size;
static pthread_key_t rb_sp_key;
struct rb_sp_tlsbuf {
	size_t capa;
	unsigned char ptr[FLEX_ARRAY];
};

#ifdef HAVE_SYS_EVENT_H
void sleepy_penguin_init_kqueue(void);
#else
#  define sleepy_penguin_init_kqueue() for(;0;)
#endif

#ifdef HAVE_SYS_EPOLL_H
void sleepy_penguin_init_epoll(void);
#else
#  define sleepy_penguin_init_epoll() for(;0;)
#endif

#ifdef HAVE_SYS_TIMERFD_H
void sleepy_penguin_init_timerfd(void);
#else
#  define sleepy_penguin_init_timerfd() for(;0;)
#endif

#ifdef HAVE_SYS_EVENTFD_H
void sleepy_penguin_init_eventfd(void);
#else
#  define sleepy_penguin_init_eventfd() for(;0;)
#endif

#ifdef HAVE_SYS_INOTIFY_H
void sleepy_penguin_init_inotify(void);
#else
#  define sleepy_penguin_init_inotify() for(;0;)
#endif

#ifdef HAVE_SYS_SIGNALFD_H
void sleepy_penguin_init_signalfd(void);
#else
#  define sleepy_penguin_init_signalfd() for(;0;)
#endif

static size_t l1_cache_line_size_detect(void)
{
#ifdef _SC_LEVEL1_DCACHE_LINESIZE
	long tmp = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);

	if (tmp > 0 && tmp <= L1_CACHE_LINE_MAX)
		return (size_t)tmp;
#endif /* _SC_LEVEL1_DCACHE_LINESIZE */
	return L1_CACHE_LINE_MAX;
}

static void sp_once(void)
{
	int err = pthread_key_create(&rb_sp_key, free);

	if (err) {
		errno = err;
		rb_sys_fail( "pthread_key_create");
	}
}

void *rb_sp_gettlsbuf(size_t *size)
{
	struct rb_sp_tlsbuf *buf = pthread_getspecific(rb_sp_key);
	void *ptr;
	int err;
	size_t bytes;

	if (buf && buf->capa >= *size) {
		*size = buf->capa;
		goto out;
	}

	free(buf);
	bytes = *size + sizeof(struct rb_sp_tlsbuf);
	err = posix_memalign(&ptr, rb_sp_l1_cache_line_size, bytes);
	if (err) {
		errno = err;
		rb_memerror(); /* fatal */
	}

	buf = ptr;
	buf->capa = *size;
	err = pthread_setspecific(rb_sp_key, buf);
	if (err != 0) {
		errno = err;
		rb_sys_fail("BUG: pthread_setspecific");
	}
out:
	return buf->ptr;
}

void Init_sleepy_penguin_ext(void)
{
	VALUE mSleepyPenguin;
	static pthread_once_t once = PTHREAD_ONCE_INIT;
	int err = pthread_once(&once, sp_once);

	if (err) {
		errno = err;
		rb_sys_fail("pthread_once");
	}

	rb_sp_l1_cache_line_size = l1_cache_line_size_detect();

	mSleepyPenguin = rb_define_module("SleepyPenguin");
	rb_define_const(mSleepyPenguin, "SLEEPY_PENGUIN_VERSION",
			rb_str_new2(MY_GIT_VERSION));

	sleepy_penguin_init_kqueue();
	sleepy_penguin_init_epoll();
	sleepy_penguin_init_timerfd();
	sleepy_penguin_init_eventfd();
	sleepy_penguin_init_inotify();
	sleepy_penguin_init_signalfd();
}

git clone https://yhbt.net/sleepy_penguin.git