unicorn 5.6.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,23 +8,15 @@
8
8
 
9
9
  #include <unistd.h>
10
10
  #include <assert.h>
11
+ #include <limits.h>
11
12
 
12
13
  #define MIN(a,b) (a < b ? a : b)
13
14
  #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
14
15
 
15
- #ifndef SIZEOF_OFF_T
16
- # define SIZEOF_OFF_T 4
17
- # warning SIZEOF_OFF_T not defined, guessing 4. Did you run extconf.rb?
18
- #endif
19
-
20
- #if SIZEOF_OFF_T == 4
21
- # define UH_OFF_T_MAX 0x7fffffff
22
- #elif SIZEOF_OFF_T == 8
23
- # if SIZEOF_LONG == 4
24
- # define UH_OFF_T_MAX 0x7fffffffffffffffLL
25
- # else
26
- # define UH_OFF_T_MAX 0x7fffffffffffffff
27
- # endif
16
+ #if SIZEOF_OFF_T == SIZEOF_INT
17
+ # define UH_OFF_T_MAX INT_MAX
18
+ #elif SIZEOF_OFF_T == SIZEOF_LONG_LONG
19
+ # define UH_OFF_T_MAX LLONG_MAX
28
20
  #else
29
21
  # error off_t size unknown for this platform!
30
22
  #endif /* SIZEOF_OFF_T check */
@@ -83,7 +83,6 @@ static void init_common_fields(void)
83
83
  struct common_field *cf = common_http_fields;
84
84
  char tmp[64];
85
85
 
86
- id_uminus = rb_intern("-@");
87
86
  memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
88
87
 
89
88
  for(i = ARRAY_SIZE(common_http_fields); --i >= 0; cf++) {
@@ -0,0 +1,124 @@
1
+ /*
2
+ * This is only intended for use inside a unicorn worker, nowhere else.
3
+ * EPOLLEXCLUSIVE somewhat mitigates the thundering herd problem for
4
+ * mostly idle processes since we can't use blocking accept4.
5
+ * This is NOT intended for use with multi-threaded servers, nor
6
+ * single-threaded multi-client ("C10K") servers or anything advanced
7
+ * like that. This use of epoll is only appropriate for a primitive,
8
+ * single-client, single-threaded servers like unicorn that need to
9
+ * support SIGKILL timeouts and parent death detection.
10
+ */
11
+ #if defined(HAVE_EPOLL_CREATE1)
12
+ # include <sys/epoll.h>
13
+ # include <errno.h>
14
+ # include <ruby/io.h>
15
+ # include <ruby/thread.h>
16
+ #endif /* __linux__ */
17
+
18
+ #if defined(EPOLLEXCLUSIVE) && defined(HAVE_EPOLL_CREATE1)
19
+ # define USE_EPOLL (1)
20
+ #else
21
+ # define USE_EPOLL (0)
22
+ #endif
23
+
24
+ #if USE_EPOLL
25
+ /*
26
+ * :nodoc:
27
+ * returns IO object if EPOLLEXCLUSIVE works and arms readers
28
+ */
29
+ static VALUE prep_readers(VALUE cls, VALUE readers)
30
+ {
31
+ long i;
32
+ int epfd = epoll_create1(EPOLL_CLOEXEC);
33
+ VALUE epio;
34
+
35
+ if (epfd < 0) rb_sys_fail("epoll_create1");
36
+
37
+ epio = rb_funcall(cls, rb_intern("for_fd"), 1, INT2NUM(epfd));
38
+
39
+ Check_Type(readers, T_ARRAY);
40
+ for (i = 0; i < RARRAY_LEN(readers); i++) {
41
+ int rc;
42
+ struct epoll_event e;
43
+ rb_io_t *fptr;
44
+ VALUE io = rb_ary_entry(readers, i);
45
+
46
+ e.data.u64 = i; /* the reason readers shouldn't change */
47
+
48
+ /*
49
+ * I wanted to use EPOLLET here, but maintaining our own
50
+ * equivalent of ep->rdllist in Ruby-space doesn't fit
51
+ * our design at all (and the kernel already has it's own
52
+ * code path for doing it). So let the kernel spend
53
+ * cycles on maintaining level-triggering.
54
+ */
55
+ e.events = EPOLLEXCLUSIVE | EPOLLIN;
56
+ io = rb_io_get_io(io);
57
+ GetOpenFile(io, fptr);
58
+ rc = epoll_ctl(epfd, EPOLL_CTL_ADD, fptr->fd, &e);
59
+ if (rc < 0) rb_sys_fail("epoll_ctl");
60
+ }
61
+ return epio;
62
+ }
63
+ #endif /* USE_EPOLL */
64
+
65
+ #if USE_EPOLL
66
+ struct ep_wait {
67
+ struct epoll_event *events;
68
+ rb_io_t *fptr;
69
+ int maxevents;
70
+ int timeout_msec;
71
+ };
72
+
73
+ static void *do_wait(void *ptr) /* runs w/o GVL */
74
+ {
75
+ struct ep_wait *epw = ptr;
76
+
77
+ return (void *)(long)epoll_wait(epw->fptr->fd, epw->events,
78
+ epw->maxevents, epw->timeout_msec);
79
+ }
80
+
81
+ /* :nodoc: */
82
+ /* readers must not change between prepare_readers and get_readers */
83
+ static VALUE
84
+ get_readers(VALUE epio, VALUE ready, VALUE readers, VALUE timeout_msec)
85
+ {
86
+ struct ep_wait epw;
87
+ long i, n;
88
+ VALUE buf;
89
+
90
+ Check_Type(ready, T_ARRAY);
91
+ Check_Type(readers, T_ARRAY);
92
+ epw.maxevents = RARRAY_LENINT(readers);
93
+ buf = rb_str_buf_new(sizeof(struct epoll_event) * epw.maxevents);
94
+ epw.events = (struct epoll_event *)RSTRING_PTR(buf);
95
+ epio = rb_io_get_io(epio);
96
+ GetOpenFile(epio, epw.fptr);
97
+
98
+ epw.timeout_msec = NUM2INT(timeout_msec);
99
+ n = (long)rb_thread_call_without_gvl(do_wait, &epw, RUBY_UBF_IO, NULL);
100
+ if (n < 0) {
101
+ if (errno != EINTR) rb_sys_fail("epoll_wait");
102
+ n = 0;
103
+ }
104
+ /* Linux delivers events in order received */
105
+ for (i = 0; i < n; i++) {
106
+ struct epoll_event *ev = &epw.events[i];
107
+ VALUE obj = rb_ary_entry(readers, ev->data.u64);
108
+
109
+ if (RTEST(obj))
110
+ rb_ary_push(ready, obj);
111
+ }
112
+ rb_str_resize(buf, 0);
113
+ return Qfalse;
114
+ }
115
+ #endif /* USE_EPOLL */
116
+
117
+ static void init_epollexclusive(VALUE mUnicorn)
118
+ {
119
+ #if USE_EPOLL
120
+ VALUE cWaiter = rb_define_class_under(mUnicorn, "Waiter", rb_cIO);
121
+ rb_define_singleton_method(cWaiter, "prep_readers", prep_readers, 1);
122
+ rb_define_method(cWaiter, "get_readers", get_readers, 3);
123
+ #endif
124
+ }
@@ -8,30 +8,6 @@
8
8
  # define assert_frozen(f) do {} while (0)
9
9
  #endif /* !defined(OBJ_FROZEN) */
10
10
 
11
- #if !defined(OFFT2NUM)
12
- # if SIZEOF_OFF_T == SIZEOF_LONG
13
- # define OFFT2NUM(n) LONG2NUM(n)
14
- # else
15
- # define OFFT2NUM(n) LL2NUM(n)
16
- # endif
17
- #endif /* ! defined(OFFT2NUM) */
18
-
19
- #if !defined(SIZET2NUM)
20
- # if SIZEOF_SIZE_T == SIZEOF_LONG
21
- # define SIZET2NUM(n) ULONG2NUM(n)
22
- # else
23
- # define SIZET2NUM(n) ULL2NUM(n)
24
- # endif
25
- #endif /* ! defined(SIZET2NUM) */
26
-
27
- #if !defined(NUM2SIZET)
28
- # if SIZEOF_SIZE_T == SIZEOF_LONG
29
- # define NUM2SIZET(n) ((size_t)NUM2ULONG(n))
30
- # else
31
- # define NUM2SIZET(n) ((size_t)NUM2ULL(n))
32
- # endif
33
- #endif /* ! defined(NUM2SIZET) */
34
-
35
11
  static inline int str_cstr_eq(VALUE val, const char *ptr, long len)
36
12
  {
37
13
  return (RSTRING_LEN(val) == len && !memcmp(ptr, RSTRING_PTR(val), len));
@@ -1,12 +1,7 @@
1
1
  # -*- encoding: binary -*-
2
2
  require 'mkmf'
3
3
 
4
- have_macro("SIZEOF_OFF_T", "ruby.h") or check_sizeof("off_t", "sys/types.h")
5
- have_macro("SIZEOF_SIZE_T", "ruby.h") or check_sizeof("size_t", "sys/types.h")
6
- have_macro("SIZEOF_LONG", "ruby.h") or check_sizeof("long", "sys/types.h")
7
- have_func("rb_str_set_len", "ruby.h") or abort 'Ruby 1.9.3+ required'
8
- have_func("rb_hash_clear", "ruby.h") # Ruby 2.0+
9
- have_func("gmtime_r", "time.h")
4
+ have_func("rb_hash_clear", "ruby.h") or abort 'Ruby 2.0+ required'
10
5
 
11
6
  message('checking if String#-@ (str_uminus) dedupes... ')
12
7
  begin
@@ -38,4 +33,5 @@ else
38
33
  message("no, needs Ruby 2.6+\n")
39
34
  end
40
35
 
36
+ have_func('epoll_create1', %w(sys/epoll.h))
41
37
  create_makefile("unicorn_http")
@@ -55,7 +55,7 @@ NORETURN(static void parser_raise(VALUE klass, const char *));
55
55
 
56
56
  /** Defines global strings in the init method. */
57
57
  #define DEF_GLOBAL(N, val) do { \
58
- g_##N = rb_obj_freeze(rb_str_new(val, sizeof(val) - 1)); \
58
+ g_##N = str_new_dd_freeze(val, (long)sizeof(val) - 1); \
59
59
  rb_gc_register_mark_object(g_##N); \
60
60
  } while (0)
61
61
 
@@ -11,6 +11,7 @@ static const char months[] = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0"
11
11
 
12
12
  /* for people on wonky systems only */
13
13
  #ifndef HAVE_GMTIME_R
14
+ # warning using fake gmtime_r
14
15
  static struct tm * my_gmtime_r(time_t *now, struct tm *tm)
15
16
  {
16
17
  struct tm *global = gmtime(now);