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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
/******************************************************
A fast mutex for interprocess synchronization.
mutex_t can be used only within single process,
but ip_mutex_t also between processes.
(c) 1995 Innobase Oy
Created 9/30/1995 Heikki Tuuri
*******************************************************/
/* An extra structure created in the private address space of each process
which creates or opens the ip mutex. */
struct ip_mutex_hdl_struct {
ip_mutex_t* ip_mutex; /* pointer to ip mutex */
os_event_t released; /* event which signals that the mutex
is released; this is obtained from
create or open of an ip mutex */
os_mutex_t exclude; /* os mutex obtained when ip mutex is
created or opened */
};
UNIV_INLINE
ulint
ip_mutex_get_waiters(
volatile ip_mutex_t* ipm);
UNIV_INLINE
void
ip_mutex_set_waiters(
volatile ip_mutex_t* ipm,
ulint flag);
UNIV_INLINE
mutex_t*
ip_mutex_get_mutex(
ip_mutex_t* ipm);
/******************************************************************
Accessor functions for ip mutex. */
UNIV_INLINE
ulint
ip_mutex_get_waiters(
volatile ip_mutex_t* ipm)
{
return(ipm->waiters);
}
UNIV_INLINE
void
ip_mutex_set_waiters(
volatile ip_mutex_t* ipm,
ulint flag)
{
ipm->waiters = flag;
}
UNIV_INLINE
mutex_t*
ip_mutex_get_mutex(
ip_mutex_t* ipm)
{
return(&(ipm->mutex));
}
/******************************************************************
Reserves an ip mutex. */
UNIV_INLINE
ulint
ip_mutex_enter(
/*===========*/
/* out: 0 if success,
SYNC_TIME_EXCEEDED if timeout */
ip_mutex_hdl_t* ip_mutex_hdl, /* in: pointer to ip mutex handle */
ulint time) /* in: maximum time to wait, in
microseconds, or
SYNC_INFINITE_TIME */
{
mutex_t* mutex;
os_event_t released;
os_mutex_t exclude;
ip_mutex_t* ip_mutex;
ulint loop_count;
ulint ret;
ip_mutex = ip_mutex_hdl->ip_mutex;
released = ip_mutex_hdl->released;
exclude = ip_mutex_hdl->exclude;
mutex = ip_mutex_get_mutex(ip_mutex);
loop_count = 0;
loop:
loop_count++;
ut_ad(loop_count < 15);
if (mutex_enter_nowait(mutex, IB__FILE__, __LINE__) == 0) {
/* Succeeded! */
return(0);
}
ip_mutex_system_call_count++;
os_event_reset(released);
/* Order is important here: FIRST reset event, then set waiters */
ip_mutex_set_waiters(ip_mutex, 1);
if (mutex_enter_nowait(mutex, IB__FILE__, __LINE__) == 0) {
/* Succeeded! */
return(0);
}
if (time == SYNC_INFINITE_TIME) {
time = OS_SYNC_INFINITE_TIME;
}
/* Suspend to wait for release */
ip_mutex_system_call_count++;
ret = os_event_wait_time(released, time);
ip_mutex_system_call_count++;
os_mutex_enter(exclude);
ip_mutex_system_call_count++;
os_mutex_exit(exclude);
if (ret != 0) {
ut_a(ret == OS_SYNC_TIME_EXCEEDED);
return(SYNC_TIME_EXCEEDED);
}
goto loop;
}
/******************************************************************
Releases an ip mutex. */
UNIV_INLINE
void
ip_mutex_exit(
/*==========*/
ip_mutex_hdl_t* ip_mutex_hdl) /* in: pointer to ip mutex handle */
{
mutex_t* mutex;
os_event_t released;
os_mutex_t exclude;
ip_mutex_t* ip_mutex;
ip_mutex = ip_mutex_hdl->ip_mutex;
released = ip_mutex_hdl->released;
exclude = ip_mutex_hdl->exclude;
mutex = ip_mutex_get_mutex(ip_mutex);
mutex_exit(mutex);
if (ip_mutex_get_waiters(ip_mutex) != 0) {
ip_mutex_set_waiters(ip_mutex, 0);
/* Order is important here: FIRST reset waiters,
then set event */
ip_mutex_system_call_count++;
os_mutex_enter(exclude);
/* The use of the exclude mutex seems to prevent some
kind of a convoy problem in the test tsproc.c. We do
not know why. */
ip_mutex_system_call_count++;
os_event_set(released);
ip_mutex_system_call_count++;
os_mutex_exit(exclude);
}
}
|