1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997,2008 Oracle.  All rights reserved.
5 *
6 * $Id: os_yield.c,v 12.19 2008/01/08 20:58:43 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#define	__INCLUDE_SELECT_H	1
12#include "db_int.h"
13
14#if defined(HAVE_SYSTEM_INCLUDE_FILES) && defined(HAVE_SCHED_YIELD)
15#include <sched.h>
16#endif
17
18static void __os_sleep __P((ENV *, u_long, u_long));
19
20/*
21 * __os_yield --
22 *	Yield the processor, optionally pausing until running again.
23 *
24 * PUBLIC: void __os_yield __P((ENV *, u_long, u_long));
25 */
26void
27__os_yield(env, secs, usecs)
28	ENV *env;
29	u_long secs, usecs;		/* Seconds and microseconds. */
30{
31	/*
32	 * Don't require the values be normalized (some operating systems
33	 * return an error if the usecs argument to select is too large).
34	 */
35	for (; usecs >= US_PER_SEC; usecs -= US_PER_SEC)
36		++secs;
37
38	if (DB_GLOBAL(j_yield) != NULL) {
39		(void)DB_GLOBAL(j_yield)(secs, usecs);
40		return;
41	}
42
43	/*
44	 * Yield the processor so other processes or threads can run.  Use
45	 * the local yield call if not pausing, otherwise call the select
46	 * function.
47	 */
48	if (secs != 0 || usecs != 0)
49		__os_sleep(env, secs, usecs);
50	else {
51#if defined(HAVE_MUTEX_UI_THREADS)
52		thr_yield();
53#elif defined(HAVE_PTHREAD_YIELD) &&					\
54    (defined(HAVE_MUTEX_PTHREADS) || defined(HAVE_PTHREAD_API))
55		pthread_yield();
56#elif defined(HAVE_SCHED_YIELD)
57		(void)sched_yield();
58#elif defined(HAVE_YIELD)
59		yield();
60#else
61		__os_sleep(dbenv, 0, 0);
62#endif
63	}
64}
65
66/*
67 * __os_sleep --
68 *	Pause the thread of control.
69 */
70static void
71__os_sleep(env, secs, usecs)
72	ENV *env;
73	u_long secs, usecs;		/* Seconds and microseconds. */
74{
75	struct timeval t;
76	int ret;
77
78	/*
79	 * Sheer raving paranoia -- don't select for 0 time, in case some
80	 * implementation doesn't yield the processor in that case.
81	 */
82	t.tv_sec = (long)secs;
83	t.tv_usec = (long)usecs + 1;
84
85	/*
86	 * We don't catch interrupts and restart the system call here, unlike
87	 * other Berkeley DB system calls.  This may be a user attempting to
88	 * interrupt a sleeping DB utility (for example, db_checkpoint), and
89	 * we want the utility to see the signal and quit.  This assumes it's
90	 * always OK for DB to sleep for less time than originally scheduled.
91	 */
92	if (select(0, NULL, NULL, NULL, &t) == -1) {
93		ret = __os_get_syserr();
94		if (__os_posix_err(ret) != EINTR)
95			__db_syserr(env, ret, "select");
96	}
97}
98