File: compat_futex.c

package info (click to toggle)
liburcu 0.6.7-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 2,784 kB
  • sloc: ansic: 11,459; sh: 10,312; makefile: 184
file content (115 lines) | stat: -rw-r--r-- 2,865 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
 * compat_futex.c
 *
 * Userspace RCU library - sys_futex compatibility code
 *
 * Copyright (c) 2009 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <stdint.h>

#include <urcu/arch.h>
#include <urcu/futex.h>

static pthread_mutex_t compat_futex_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t compat_futex_cond = PTHREAD_COND_INITIALIZER;

/*
 * _NOT SIGNAL-SAFE_. pthread_cond is not signal-safe anyway. Though.
 * For now, timeout, uaddr2 and val3 are unused.
 * Waiter will relinquish the CPU until woken up.
 */

int compat_futex_noasync(int32_t *uaddr, int op, int32_t val,
	const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
{
	int ret, i, gret = 0;

	/*
	 * Check if NULL. Don't let users expect that they are taken into
	 * account. 
	 */
	assert(!timeout);
	assert(!uaddr2);
	assert(!val3);

	/*
	 * memory barriers to serialize with the previous uaddr modification.
	 */
	cmm_smp_mb();

	ret = pthread_mutex_lock(&compat_futex_lock);
	assert(!ret);
	switch (op) {
	case FUTEX_WAIT:
		if (*uaddr != val)
			goto end;
		pthread_cond_wait(&compat_futex_cond, &compat_futex_lock);
		break;
	case FUTEX_WAKE:
		for (i = 0; i < val; i++)
			pthread_cond_signal(&compat_futex_cond);
		break;
	default:
		gret = -EINVAL;
	}
end:
	ret = pthread_mutex_unlock(&compat_futex_lock);
	assert(!ret);
	return gret;
}

/*
 * _ASYNC SIGNAL-SAFE_.
 * For now, timeout, uaddr2 and val3 are unused.
 * Waiter will busy-loop trying to read the condition.
 */

int compat_futex_async(int32_t *uaddr, int op, int32_t val,
	const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
{
	/*
	 * Check if NULL. Don't let users expect that they are taken into
	 * account. 
	 */
	assert(!timeout);
	assert(!uaddr2);
	assert(!val3);

	/*
	 * Ensure previous memory operations on uaddr have completed.
	 */
	cmm_smp_mb();

	switch (op) {
	case FUTEX_WAIT:
		while (*uaddr == val)
			poll(NULL, 0, 10);
		break;
	case FUTEX_WAKE:
		break;
	default:
		return -EINVAL;
	}
	return 0;
}