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
|
/* vi: set sw=4 ts=4: */
/*
* Copyright (C) 2000-2011 Erik Andersen <andersen@uclibc.org>
*
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
#ifndef _CANCEL_H
#define _CANCEL_H
/*
* Usage of this header:
* 1. define a static or hidden function __NC(NAME) - expands to __NAME_nocancel
* 2. if it is hidden, add the prototype to the appropiate header where NAME has
* it's prototype (guarded by _LIBC)
* 3. add a CANCELLABLE_SYSCALL(...) line at the end, this will create the function
* NAME (as weak) with enabled cancellation for NPTL, for
* LT it will also create a strong_alias to __libc_NAME to be used in libpthread
* 4. if you need libc_hidden_(weak|def) line, use instead lt_libc_hidden, this will
* take care of the correct type, weak or strong depending on the THREADS type
* 5. If the implementation can't be done using CANCELLABLE_SYSCALL (like for fcntl)
* you need to manually add lt_strong_alias() line too, to optionally create the
* __libc_NAME alias
* 6. if functions are needed to implement __NC(NAME), that themselves are cancellable,
* decide how the cancellation should be solved, two variants are possible:
* a. use the other function as __NC(FUNC), this way you access the non-cancellable
* variant and provide by CANCELLABLE_SYSCALL(...) the dedicated cancellation for NAME.
* be aware, that for this case __NC(FUNC) has to be hidden (not static)
* b. use the other function with it's name (FUNC) and add LIBC_CANCEL_HANDLED(); at
* the end of file with a comment telling us which function took care of the cancellation
* Note: LIBC_CANCEL_HANDLED() is noop on uClibc, glibc uses it only for tests, we use
* it only for "documentation".
*
* For now the use of this file is limited to libc, will expand later to support libpthread
* and librt as well.
*/
#include <features.h>
#ifndef NOT_IN_libc
#define __NC(name) _NC(name)
#define _NC(name) __##name##_nocancel
#define __NC_OLD(name) _NC_OLD(name)
#define _NC_OLD(name) __libc_##name
#define __NC_PROTO(name) extern __typeof(name) __NC(name) attribute_hidden;
#define __NC_OLD_PROTO(name) extern __typeof(name) __NC_OLD(name);
#if defined __UCLIBC_HAS_THREADS__ && !defined __UCLIBC_HAS_LINUXTHREADS__
# define __NEW_THREADS 1
#else
# define SINGLE_THREAD_P 1
#endif
#ifdef __NEW_THREADS
# include <sysdep-cancel.h>
# define CANCELLABLE_SYSCALL(res_type, name, param_list, params) \
res_type weak_function name param_list \
{ \
int oldtype; \
res_type result; \
if (SINGLE_THREAD_P) \
return __NC(name) params; \
oldtype = LIBC_CANCEL_ASYNC(); \
result = __NC(name) params; \
LIBC_CANCEL_RESET(oldtype); \
return result; \
}
# define lt_strong_alias(name)
# define lt_libc_hidden(name) libc_hidden_def(name)
#elif defined __UCLIBC_HAS_LINUXTHREADS__
# define CANCELLABLE_SYSCALL(res_type, name, param_list, params) \
weak_alias(__NC(name),name) \
lt_strong_alias(name)
# define lt_strong_alias(name) \
__NC_OLD_PROTO(name) \
strong_alias(name,__NC_OLD(name))
# define lt_libc_hidden(name) libc_hidden_weak(name)
#else
# define CANCELLABLE_SYSCALL(res_type, name, param_list, params) \
strong_alias(__NC(name),name)
# define lt_strong_alias(name)
# define lt_libc_hidden(name) libc_hidden_def(name)
#endif
/* disable it, useless, glibc uses it only for tests */
# undef LIBC_CANCEL_HANDLED
# define LIBC_CANCEL_HANDLED()
#endif /* NOT_IN_libc */
#endif
|