0001-thread_pthread-use-eventfd-under-Linux-for-timer-thr.patch

use eventfd on Linux - Eric Wong, 08/17/2013 06:40 AM

Download (9.08 KB)

View differences:

configure.in
1757 1757
AC_CHECK_FUNCS(dup3)
1758 1758
AC_CHECK_FUNCS(eaccess)
1759 1759
AC_CHECK_FUNCS(endgrent)
1760
AC_CHECK_FUNCS(eventfd)
1760 1761
AC_CHECK_FUNCS(fchmod)
1761 1762
AC_CHECK_FUNCS(fchown)
1762 1763
AC_CHECK_FUNCS(fcntl)
thread_pthread.c
1155 1155
#define TIME_QUANTUM_USEC (100 * 1000)
1156 1156

  
1157 1157
#if USE_SLEEPY_TIMER_THREAD
1158
#  ifdef HAVE_EVENTFD
1159
#    include <sys/eventfd.h>
1160
static int timer_thread_efd = -1;
1161
static int timer_thread_efd_low = -1; /* low priority */
1162
static const uint64_t tt_write_buf = 1;
1163
static uint64_t tt_read_buf[1]; /* value ignored */
1164
#    define TT_FDPTR (&timer_thread_efd)
1165
#    define TT_FDPTR_LOW (&timer_thread_efd_low)
1166
#    define TT_READFD timer_thread_efd
1167
#    define TT_READFD_LOW timer_thread_efd_low
1168
#    define TT_WRITEFD timer_thread_efd
1169
#    define TT_WRITEFD_LOW timer_thread_efd_low
1170
#    if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
1171
#      define TT_EFD_FLAGS (EFD_CLOEXEC|EFD_NONBLOCK)
1172
#    else
1173
#      define TT_EFD_FLAGS (0)
1174
#    endif
1175
int
1176
rb_reserved_fd_p(int fd)
1177
{
1178
    return (fd == timer_thread_efd || fd == timer_thread_efd_low);
1179
}
1180
#  else /* use self-pipe */
1158 1181
static int timer_thread_pipe[2] = {-1, -1};
1159 1182
static int timer_thread_pipe_low[2] = {-1, -1}; /* low priority */
1183
static const char tt_write_buf = '!';
1184
/* buffer can be shared because no one refers to them. */
1185
static char tt_read_buf[1024];
1186
#    define TT_FDPTR (timer_thread_pipe)
1187
#    define TT_FDPTR_LOW (timer_thread_pipe_low)
1188
#    define TT_READFD (timer_thread_pipe[0])
1189
#    define TT_READFD_LOW (timer_thread_pipe_low[0])
1190
#    define TT_WRITEFD (timer_thread_pipe[1])
1191
#    define TT_WRITEFD_LOW (timer_thread_pipe_low[1])
1192
int
1193
rb_reserved_fd_p(int fd)
1194
{
1195
    if (fd == timer_thread_pipe[0]     ||
1196
        fd == timer_thread_pipe[1]     ||
1197
        fd == timer_thread_pipe_low[0] ||
1198
        fd == timer_thread_pipe_low[1]) {
1199
        return 1;
1200
    }
1201
    return 0;
1202
}
1203
#  endif /* !HAVE_EVENTFD */
1160 1204
static int timer_thread_pipe_owner_process;
1161 1205

  
1162 1206
/* only use signal-safe system calls here */
......
1167 1211

  
1168 1212
    /* already opened */
1169 1213
    if (timer_thread_pipe_owner_process == getpid()) {
1170
	const char *buff = "!";
1171 1214
      retry:
1172
	if ((result = write(fd, buff, 1)) <= 0) {
1215
	if ((result = write(fd, &tt_write_buf, sizeof(tt_write_buf))) <= 0) {
1173 1216
	    switch (errno) {
1174 1217
	      case EINTR: goto retry;
1175 1218
	      case EAGAIN:
......
1191 1234
void
1192 1235
rb_thread_wakeup_timer_thread(void)
1193 1236
{
1194
    rb_thread_wakeup_timer_thread_fd(timer_thread_pipe[1]);
1237
    rb_thread_wakeup_timer_thread_fd(TT_WRITEFD);
1195 1238
}
1196 1239

  
1197 1240
static void
1198 1241
rb_thread_wakeup_timer_thread_low(void)
1199 1242
{
1200
    rb_thread_wakeup_timer_thread_fd(timer_thread_pipe_low[1]);
1243
    rb_thread_wakeup_timer_thread_fd(TT_WRITEFD_LOW);
1201 1244
}
1202 1245

  
1203 1246
/* VM-dependent API is not available for this function */
1204 1247
static void
1205
consume_communication_pipe(int fd)
1248
consume_communication_fd(int fd)
1206 1249
{
1207
#define CCP_READ_BUFF_SIZE 1024
1208
    /* buffer can be shared because no one refers to them. */
1209
    static char buff[CCP_READ_BUFF_SIZE];
1210 1250
    ssize_t result;
1211 1251

  
1212 1252
    while (1) {
1213
	result = read(fd, buff, sizeof(buff));
1253
	result = read(fd, tt_read_buf, sizeof(tt_read_buf));
1214 1254
	if (result == 0) {
1215 1255
	    return;
1216 1256
	}
......
1221 1261
	    case EAGAIN:
1222 1262
		return;
1223 1263
	    default:
1224
		rb_async_bug_errno("consume_communication_pipe: read\n", errno);
1264
		rb_async_bug_errno("consume_communication_fd: read\n", errno);
1225 1265
	    }
1226 1266
	}
1227 1267
    }
1228 1268
}
1229 1269

  
1270
#ifdef HAVE_EVENTFD
1271
static void
1272
close_communication_efd(int *efd)
1273
{
1274
    if (close(*efd) < 0)
1275
	rb_bug_errno("native_stop_timer_thread - close(ttp[0])", errno);
1276
    *efd = -1;
1277
}
1278
#else /* !HAVE_EVENTFD */
1230 1279
static void
1231 1280
close_communication_pipe(int pipes[2])
1232 1281
{
......
1238 1287
    }
1239 1288
    pipes[0] = pipes[1] = -1;
1240 1289
}
1290
#endif /* !HAVE_EVENTFD */
1291

  
1292
#ifdef HAVE_EVENTFD
1293
/* Linux <= 2.6.27 compatibility, emulate EFD_CLOEXEC|EFD_NONBLOCK */
1294
static int
1295
eventfd_compat(int fd)
1296
{
1297
    int flags;
1298

  
1299
    flags = fcntl(fd, F_GETFD);
1300
    if (flags == -1)
1301
	rb_bug_errno("eventfd_compat: failed F_GETFD on eventfd", errno);
1302
    if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
1303
	rb_bug_errno("eventfd_compat: failed F_SETFD on eventfd", errno);
1304

  
1305
    flags = fcntl(fd, F_GETFL);
1306
    if (flags == -1)
1307
	rb_bug_errno("eventfd_compat: failed F_GETFL on eventfd", errno);
1308
    if (fcntl(fd, F_SETFL | O_NONBLOCK) < 0)
1309
	rb_bug_errno("eventfd_compat: failed F_SETFL on eventfd", errno);
1310

  
1311
    return fd;
1312
}
1313

  
1314
static void
1315
setup_communication_fds_internal(int *efd)
1316
{
1317
    if (*efd != -1) {
1318
	/* close eventfd of parent process */
1319
	close_communication_efd(efd);
1320
    }
1321

  
1322
    *efd = eventfd(0, TT_EFD_FLAGS);
1323

  
1324
    if (*efd < 0) {
1325
	if (errno == EINVAL) {
1326
	    /* new glibc headers, old kernel */
1327
	    *efd = eventfd(0, 0);
1328
	    if (*efd < 0)
1329
		rb_sys_fail("eventfd");
1330
	    eventfd_compat(*efd);
1331
	} else {
1332
	    rb_sys_fail("eventfd");
1333
	}
1334
    } else {
1335
	if (TT_EFD_FLAGS == 0)
1336
	    eventfd_compat(*efd);
1337
    }
1338
    rb_update_max_fd(*efd);
1339
}
1241 1340

  
1341
#else /* !HAVE_EVENTFD */
1242 1342
static void
1243 1343
set_nonblock(int fd)
1244 1344
{
......
1255 1355
}
1256 1356

  
1257 1357
static void
1258
setup_communication_pipe_internal(int pipes[2])
1358
setup_communication_fds_internal(int pipes[2])
1259 1359
{
1260 1360
    int err;
1261 1361

  
......
1266 1366

  
1267 1367
    err = rb_cloexec_pipe(pipes);
1268 1368
    if (err != 0) {
1269
	rb_bug_errno("setup_communication_pipe: Failed to create communication pipe for timer thread", errno);
1369
	rb_bug_errno("setup_communication_fds: Failed to create communication pipe for timer thread", errno);
1270 1370
    }
1271 1371
    rb_update_max_fd(pipes[0]);
1272 1372
    rb_update_max_fd(pipes[1]);
1273 1373
    set_nonblock(pipes[0]);
1274 1374
    set_nonblock(pipes[1]);
1275 1375
}
1376
#endif /* !HAVE_EVENTFD */
1276 1377

  
1277 1378
/* communication pipe with timer thread and signal handler */
1278 1379
static void
1279
setup_communication_pipe(void)
1380
setup_communication_fds(void)
1280 1381
{
1281 1382
    if (timer_thread_pipe_owner_process == getpid()) {
1282 1383
	/* already set up. */
1283 1384
	return;
1284 1385
    }
1285
    setup_communication_pipe_internal(timer_thread_pipe);
1286
    setup_communication_pipe_internal(timer_thread_pipe_low);
1386

  
1387
    setup_communication_fds_internal(TT_FDPTR);
1388
    setup_communication_fds_internal(TT_FDPTR_LOW);
1287 1389

  
1288 1390
    /* validate pipe on this process */
1289 1391
    timer_thread_pipe_owner_process = getpid();
......
1302 1404
    int need_polling;
1303 1405
    struct pollfd pollfds[2];
1304 1406

  
1305
    pollfds[0].fd = timer_thread_pipe[0];
1407
    pollfds[0].fd = TT_READFD;
1306 1408
    pollfds[0].events = POLLIN;
1307
    pollfds[1].fd = timer_thread_pipe_low[0];
1409
    pollfds[1].fd = TT_READFD_LOW;
1308 1410
    pollfds[1].events = POLLIN;
1309 1411

  
1310 1412
    need_polling = check_signal_thread_list();
......
1322 1424
	/* maybe timeout */
1323 1425
    }
1324 1426
    else if (result > 0) {
1325
	consume_communication_pipe(timer_thread_pipe[0]);
1326
	consume_communication_pipe(timer_thread_pipe_low[0]);
1427
	consume_communication_fd(TT_READFD);
1428
	consume_communication_fd(TT_READFD_LOW);
1327 1429
    }
1328 1430
    else { /* result < 0 */
1329 1431
	switch (errno) {
......
1356 1458

  
1357 1459
    native_cond_timedwait(&timer_thread_cond, &timer_thread_lock, &ts);
1358 1460
}
1461
int
1462
rb_reserved_fd_p(int fd)
1463
{
1464
    return 0;
1465
}
1359 1466
#endif /* USE_SLEEPY_TIMER_THREAD */
1360 1467

  
1361 1468
static void *
......
1425 1532
#endif
1426 1533

  
1427 1534
#if USE_SLEEPY_TIMER_THREAD
1428
	setup_communication_pipe();
1535
	setup_communication_fds();
1429 1536
#endif /* USE_SLEEPY_TIMER_THREAD */
1430 1537

  
1431 1538
	/* create timer thread */
......
1517 1624
}
1518 1625
#endif
1519 1626

  
1520
int
1521
rb_reserved_fd_p(int fd)
1522
{
1523
#if USE_SLEEPY_TIMER_THREAD
1524
    if (fd == timer_thread_pipe[0]     ||
1525
	fd == timer_thread_pipe[1]     ||
1526
	fd == timer_thread_pipe_low[0] ||
1527
	fd == timer_thread_pipe_low[1]) {
1528
	return 1;
1529
    }
1530
    else {
1531
	return 0;
1532
    }
1533
#else
1534
    return 0;
1535
#endif
1536
}
1537

  
1538 1627
rb_nativethread_id_t
1539 1628
rb_nativethread_self(void)
1540 1629
{
1541
-