1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4  *
5  * This library is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library. If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18 
19 #include "e-flag.h"
20 
21 struct _EFlag {
22 	GCond cond;
23 	GMutex mutex;
24 	gboolean is_set;
25 };
26 
27 /* This is to keep e_flag_timed_wait() building, since
28  * it relies on g_cond_timed_wait() which is deprecated. */
29 #ifdef G_DISABLE_DEPRECATED
30 gboolean	g_cond_timed_wait		(GCond *cond,
31 						 GMutex *mutex,
32 						 GTimeVal *timeval);
33 #endif /* G_DISABLE_DEPRECATED */
34 
35 /**
36  * e_flag_new: (skip)
37  *
38  * Creates a new #EFlag object.  It is initially unset.
39  *
40  * Returns: a new #EFlag
41  *
42  * Since: 1.12
43  **/
44 EFlag *
e_flag_new(void)45 e_flag_new (void)
46 {
47 	EFlag *flag;
48 
49 	flag = g_slice_new (EFlag);
50 	g_cond_init (&flag->cond);
51 	g_mutex_init (&flag->mutex);
52 	flag->is_set = FALSE;
53 
54 	return flag;
55 }
56 
57 /**
58  * e_flag_is_set: (skip)
59  * @flag: an #EFlag
60  *
61  * Returns the state of @flag.
62  *
63  * Returns: %TRUE if @flag is set
64  *
65  * Since: 1.12
66  **/
67 gboolean
e_flag_is_set(EFlag * flag)68 e_flag_is_set (EFlag *flag)
69 {
70 	gboolean is_set;
71 
72 	g_return_val_if_fail (flag != NULL, FALSE);
73 
74 	g_mutex_lock (&flag->mutex);
75 	is_set = flag->is_set;
76 	g_mutex_unlock (&flag->mutex);
77 
78 	return is_set;
79 }
80 
81 /**
82  * e_flag_set: (skip)
83  * @flag: an #EFlag
84  *
85  * Sets @flag.  All threads waiting on @flag are woken up.  Threads that
86  * call e_flag_wait() or e_flag_wait_until() once @flag is set will not
87  * block at all.
88  *
89  * Since: 1.12
90  **/
91 void
e_flag_set(EFlag * flag)92 e_flag_set (EFlag *flag)
93 {
94 	g_return_if_fail (flag != NULL);
95 
96 	g_mutex_lock (&flag->mutex);
97 	flag->is_set = TRUE;
98 	g_cond_broadcast (&flag->cond);
99 	g_mutex_unlock (&flag->mutex);
100 }
101 
102 /**
103  * e_flag_clear: (skip)
104  * @flag: an #EFlag
105  *
106  * Unsets @flag.  Subsequent calls to e_flag_wait() or e_flag_wait_until()
107  * will block until @flag is set.
108  *
109  * Since: 1.12
110  **/
111 void
e_flag_clear(EFlag * flag)112 e_flag_clear (EFlag *flag)
113 {
114 	g_return_if_fail (flag != NULL);
115 
116 	g_mutex_lock (&flag->mutex);
117 	flag->is_set = FALSE;
118 	g_mutex_unlock (&flag->mutex);
119 }
120 
121 /**
122  * e_flag_wait: (skip)
123  * @flag: an #EFlag
124  *
125  * Blocks until @flag is set.  If @flag is already set, the function returns
126  * immediately.
127  *
128  * Since: 1.12
129  **/
130 void
e_flag_wait(EFlag * flag)131 e_flag_wait (EFlag *flag)
132 {
133 	g_return_if_fail (flag != NULL);
134 
135 	g_mutex_lock (&flag->mutex);
136 	while (!flag->is_set)
137 		g_cond_wait (&flag->cond, &flag->mutex);
138 	g_mutex_unlock (&flag->mutex);
139 }
140 
141 /**
142  * e_flag_timed_wait: (skip)
143  * @flag: an #EFlag
144  * @abs_time: a #GTimeVal, determining the final time
145  *
146  * Blocks until @flag is set, or until the time specified by @abs_time.
147  * If @flag is already set, the function returns immediately.  The return
148  * value indicates the state of @flag after waiting.
149  *
150  * If @abs_time is %NULL, e_flag_timed_wait() acts like e_flag_wait().
151  *
152  * To easily calculate @abs_time, a combination of g_get_current_time() and
153  * g_time_val_add() can be used.
154  *
155  * Returns: %TRUE if @flag is now set
156  *
157  * Since: 1.12
158  *
159  * Deprecated: 3.8: Use e_flag_wait_until() instead.
160  **/
161 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
162 gboolean
e_flag_timed_wait(EFlag * flag,GTimeVal * abs_time)163 e_flag_timed_wait (EFlag *flag,
164                    GTimeVal *abs_time)
165 {
166 	gboolean is_set;
167 
168 	g_return_val_if_fail (flag != NULL, FALSE);
169 
170 	g_mutex_lock (&flag->mutex);
171 	while (!flag->is_set)
172 		if (!g_cond_timed_wait (&flag->cond, &flag->mutex, abs_time))
173 			break;
174 	is_set = flag->is_set;
175 	g_mutex_unlock (&flag->mutex);
176 
177 	return is_set;
178 }
179 G_GNUC_END_IGNORE_DEPRECATIONS
180 
181 /**
182  * e_flag_wait_until: (skip)
183  * @flag: an #EFlag
184  * @end_time: the monotonic time to wait until
185  *
186  * Blocks until @flag is set, or until the time specified by @end_time.
187  * If @flag is already set, the function returns immediately.  The return
188  * value indicates the state of @flag after waiting.
189  *
190  * To easily calculate @end_time, a combination of g_get_monotonic_time() and
191  * G_TIME_SPAN_SECOND macro.
192  *
193  * Returns: %TRUE if @flag is now set
194  *
195  * Since: 3.8
196  **/
197 gboolean
e_flag_wait_until(EFlag * flag,gint64 end_time)198 e_flag_wait_until (EFlag *flag,
199                    gint64 end_time)
200 {
201 	gboolean is_set;
202 
203 	g_return_val_if_fail (flag != NULL, FALSE);
204 
205 	g_mutex_lock (&flag->mutex);
206 	while (!flag->is_set)
207 		if (!g_cond_wait_until (&flag->cond, &flag->mutex, end_time))
208 			break;
209 	is_set = flag->is_set;
210 	g_mutex_unlock (&flag->mutex);
211 
212 	return is_set;
213 }
214 
215 /**
216  * e_flag_free: (skip)
217  * @flag: an #EFlag
218  *
219  * Destroys @flag.
220  *
221  * Since: 1.12
222  **/
223 void
e_flag_free(EFlag * flag)224 e_flag_free (EFlag *flag)
225 {
226 	g_return_if_fail (flag != NULL);
227 
228 	/* Just to make sure that other threads are not holding the lock. */
229 	g_mutex_lock (&flag->mutex);
230 	g_cond_clear (&flag->cond);
231 	g_mutex_unlock (&flag->mutex);
232 	g_mutex_clear (&flag->mutex);
233 	g_slice_free (EFlag, flag);
234 }
235