Skip to content

Commit 2daf944

Browse files
committed
unix: add flag for blocking SIGPROF during poll
Add a per-event loop flag for blocking SIGPROF signals when polling for events. The motivation for this addition is to reduce the number of wakeups and subsequent clock_gettime() system calls when using a sampling profiler. On Linux, this switches from epoll_wait() to epoll_pwait() when enabled. Other platforms bracket the poll syscall with pthread_sigmask() calls. Refs strongloop/strong-agent#3 and strongloop-internal/scrum-cs#37. PR-URL: #15 Reviewed-By: Saúl Ibarra Corretgé <[email protected]>
1 parent 0bcac64 commit 2daf944

4 files changed

Lines changed: 62 additions & 13 deletions

File tree

src/unix/internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ enum {
111111
UV_TCP_SINGLE_ACCEPT = 0x400 /* Only accept() when idle. */
112112
};
113113

114+
/* loop flags */
115+
enum {
116+
UV_LOOP_BLOCK_SIGPROF = 1
117+
};
118+
114119
/* core */
115120
int uv__nonblock(int fd, int set);
116121
int uv__cloexec(int fd, int set);

src/unix/kqueue.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
5656
unsigned int nevents;
5757
unsigned int revents;
5858
ngx_queue_t* q;
59+
uv__io_t* w;
60+
sigset_t* pset;
61+
sigset_t set;
5962
uint64_t base;
6063
uint64_t diff;
61-
uv__io_t* w;
6264
int filter;
6365
int fflags;
6466
int count;
@@ -118,6 +120,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
118120
w->events = w->pevents;
119121
}
120122

123+
pset = NULL;
124+
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
125+
pset = &set;
126+
sigemptyset(pset);
127+
sigaddset(pset, SIGPROF);
128+
}
129+
121130
assert(timeout >= -1);
122131
base = loop->time;
123132
count = 48; /* Benchmarks suggest this gives the best throughput. */
@@ -128,13 +137,19 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
128137
spec.tv_nsec = (timeout % 1000) * 1000000;
129138
}
130139

140+
if (pset != NULL)
141+
pthread_sigmask(SIG_BLOCK, pset, NULL);
142+
131143
nfds = kevent(loop->backend_fd,
132144
events,
133145
nevents,
134146
events,
135147
ARRAY_SIZE(events),
136148
timeout == -1 ? NULL : &spec);
137149

150+
if (pset != NULL)
151+
pthread_sigmask(SIG_UNBLOCK, pset, NULL);
152+
138153
/* Update loop->time unconditionally. It's tempting to skip the update when
139154
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
140155
* operating system didn't reschedule our process while in the syscall.

src/unix/linux-core.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <sys/prctl.h>
3434
#include <sys/sysinfo.h>
3535
#include <unistd.h>
36+
#include <signal.h>
3637
#include <fcntl.h>
3738
#include <time.h>
3839

@@ -130,6 +131,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
130131
struct uv__epoll_event e;
131132
ngx_queue_t* q;
132133
uv__io_t* w;
134+
sigset_t* pset;
135+
sigset_t set;
133136
uint64_t base;
134137
uint64_t diff;
135138
int nevents;
@@ -180,12 +183,25 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
180183
w->events = w->pevents;
181184
}
182185

186+
pset = NULL;
187+
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
188+
pset = &set;
189+
sigemptyset(pset);
190+
sigaddset(pset, SIGPROF);
191+
}
192+
183193
assert(timeout >= -1);
184194
base = loop->time;
185195
count = 48; /* Benchmarks suggest this gives the best throughput. */
186196

187197
for (;;) {
188-
if (!no_epoll_wait) {
198+
if (no_epoll_wait || pset != NULL) {
199+
nfds = uv__epoll_pwait(loop->backend_fd,
200+
events,
201+
ARRAY_SIZE(events),
202+
timeout,
203+
pset);
204+
} else {
189205
nfds = uv__epoll_wait(loop->backend_fd,
190206
events,
191207
ARRAY_SIZE(events),
@@ -194,12 +210,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
194210
no_epoll_wait = 1;
195211
continue;
196212
}
197-
} else {
198-
nfds = uv__epoll_pwait(loop->backend_fd,
199-
events,
200-
ARRAY_SIZE(events),
201-
timeout,
202-
NULL);
203213
}
204214

205215
/* Update loop->time unconditionally. It's tempting to skip the update when

src/unix/sunos.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
112112
struct timespec spec;
113113
ngx_queue_t* q;
114114
uv__io_t* w;
115+
sigset_t* pset;
116+
sigset_t set;
115117
uint64_t base;
116118
uint64_t diff;
117119
unsigned int nfds;
118120
unsigned int i;
119121
int saved_errno;
120122
int nevents;
121123
int count;
124+
int err;
122125
int fd;
123126

124127
if (loop->nfds == 0) {
@@ -140,6 +143,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
140143
w->events = w->pevents;
141144
}
142145

146+
pset = NULL;
147+
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
148+
pset = &set;
149+
sigemptyset(pset);
150+
sigaddset(pset, SIGPROF);
151+
}
152+
143153
assert(timeout >= -1);
144154
base = loop->time;
145155
count = 48; /* Benchmarks suggest this gives the best throughput. */
@@ -155,11 +165,20 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
155165

156166
nfds = 1;
157167
saved_errno = 0;
158-
if (port_getn(loop->backend_fd,
159-
events,
160-
ARRAY_SIZE(events),
161-
&nfds,
162-
timeout == -1 ? NULL : &spec)) {
168+
169+
if (pset != NULL)
170+
pthread_sigmask(SIG_BLOCK, pset, NULL);
171+
172+
err = port_getn(loop->backend_fd,
173+
events,
174+
ARRAY_SIZE(events),
175+
&nfds,
176+
timeout == -1 ? NULL : &spec);
177+
178+
if (pset != NULL)
179+
pthread_sigmask(SIG_UNBLOCK, pset, NULL);
180+
181+
if (err) {
163182
/* Work around another kernel bug: port_getn() may return events even
164183
* on error.
165184
*/

0 commit comments

Comments
 (0)