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

PATCH v2 - eventfd_compat should return void - Eric Wong, 08/17/2013 06:53 AM

Download (9.07 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 */
1241 1291

  
1292
#ifdef HAVE_EVENTFD
1293
/* Linux <= 2.6.27 compatibility, emulate EFD_CLOEXEC|EFD_NONBLOCK */
1294
static void
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

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

  
1320
    *efd = eventfd(0, TT_EFD_FLAGS);
1321

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

  
1339
#else /* !HAVE_EVENTFD */
1242 1340
static void
1243 1341
set_nonblock(int fd)
1244 1342
{
......
1255 1353
}
1256 1354

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

  
......
1266 1364

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

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

  
1385
    setup_communication_fds_internal(TT_FDPTR);
1386
    setup_communication_fds_internal(TT_FDPTR_LOW);
1287 1387

  
1288 1388
    /* validate pipe on this process */
1289 1389
    timer_thread_pipe_owner_process = getpid();
......
1302 1402
    int need_polling;
1303 1403
    struct pollfd pollfds[2];
1304 1404

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

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

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

  
1361 1466
static void *
......
1425 1530
#endif
1426 1531

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

  
1431 1536
	/* create timer thread */
......
1517 1622
}
1518 1623
#endif
1519 1624

  
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 1625
rb_nativethread_id_t
1539 1626
rb_nativethread_self(void)
1540 1627
{
1541
-