1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 * Copyright (c) 2008 Likewise Software, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1.  Redistributions of source code must retain the above copyright
12 *     notice, this list of conditions and the following disclaimer.
13 * 2.  Redistributions in binary form must reproduce the above copyright
14 *     notice, this list of conditions and the following disclaimer in the
15 *     documentation and/or other materials provided with the distribution.
16 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
17 *     contributors may be used to endorse or promote products derived from
18 *     this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Portions of this software have been released under the following terms:
32 *
33 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
34 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
35 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
36 *
37 * To anyone who acknowledges that this file is provided "AS IS"
38 * without any express or implied warranty:
39 * permission to use, copy, modify, and distribute this file for any
40 * purpose is hereby granted without fee, provided that the above
41 * copyright notices and this notice appears in all source code copies,
42 * and that none of the names of Open Software Foundation, Inc., Hewlett-
43 * Packard Company or Digital Equipment Corporation be used
44 * in advertising or publicity pertaining to distribution of the software
45 * without specific, written prior permission.  Neither Open Software
46 * Foundation, Inc., Hewlett-Packard Company nor Digital
47 * Equipment Corporation makes any representations about the suitability
48 * of this software for any purpose.
49 *
50 * Copyright (c) 2007, Novell, Inc. All rights reserved.
51 * Redistribution and use in source and binary forms, with or without
52 * modification, are permitted provided that the following conditions
53 * are met:
54 *
55 * 1.  Redistributions of source code must retain the above copyright
56 *     notice, this list of conditions and the following disclaimer.
57 * 2.  Redistributions in binary form must reproduce the above copyright
58 *     notice, this list of conditions and the following disclaimer in the
59 *     documentation and/or other materials provided with the distribution.
60 * 3.  Neither the name of Novell Inc. nor the names of its contributors
61 *     may be used to endorse or promote products derived from this
62 *     this software without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
65 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
66 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
67 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
68 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
69 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
70 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
71 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
72 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
73 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
74 *
75 * @APPLE_LICENSE_HEADER_END@
76 */
77
78#include <config.h>
79
80#include "dcethread-private.h"
81#include "dcethread-util.h"
82#include "dcethread-debug.h"
83
84#ifdef API
85
86int
87dcethread_cond_wait(dcethread_cond *cond, dcethread_mutex *mutex)
88{
89    int ret = 0;
90    int (*interrupt_old)(dcethread*, void*) = NULL;
91    void *data_old = NULL;
92    condwait_info info;
93
94    info.cond = cond;
95    info.mutex = mutex;
96
97    if (dcethread__begin_block(dcethread__self(), dcethread__interrupt_condwait, &info, &interrupt_old, &data_old))
98    {
99        dcethread__dispatchinterrupt(dcethread__self());
100        return dcethread__set_errno(EINTR);
101    }
102    mutex->owner = (pthread_t) -1;
103    ret = dcethread__set_errno(pthread_cond_wait(cond, (pthread_mutex_t*) &mutex->mutex));
104    mutex->owner = pthread_self();
105    if (dcethread__end_block(dcethread__self(), interrupt_old, data_old))
106    {
107        dcethread__dispatchinterrupt(dcethread__self());
108        return dcethread__set_errno(EINTR);
109    }
110
111    return dcethread__set_errno(ret);
112}
113
114int
115dcethread_cond_wait_throw(dcethread_cond *cond, dcethread_mutex *mutex)
116{
117    DCETHREAD_WRAP_THROW(dcethread_cond_wait(cond, mutex));
118}
119
120#endif /* API */
121
122#ifdef TEST
123
124#include "dcethread-test.h"
125
126static void*
127basic_thread(void* data)
128{
129    volatile int interrupt_caught = 0;
130    dcethread_cond cond;
131    dcethread_mutex mutex;
132
133    MU_TRY_DCETHREAD( dcethread_mutex_init(&mutex, NULL) );
134    MU_TRY_DCETHREAD( dcethread_cond_init(&cond, NULL) );
135
136    DCETHREAD_TRY
137    {
138	MU_ASSERT(!interrupt_caught);
139        MU_TRY_DCETHREAD( dcethread_mutex_lock (&mutex) );
140
141	while (1)
142	{
143            MU_TRY_DCETHREAD( dcethread_cond_wait (&cond, &mutex) );
144	}
145    }
146    DCETHREAD_CATCH(dcethread_interrupt_e)
147    {
148	MU_ASSERT(!interrupt_caught);
149	interrupt_caught = 1;
150    }
151    DCETHREAD_FINALLY
152    {
153        dcethread_mutex_unlock (&mutex);
154    }
155    DCETHREAD_ENDTRY;
156
157    MU_ASSERT(interrupt_caught);
158
159    return NULL;
160}
161
162MU_TEST(dcethread_cond_wait, interrupt_pre)
163{
164    dcethread* thread;
165
166    MU_TRY_DCETHREAD( dcethread_create(&thread, NULL, basic_thread, NULL) );
167    MU_TRY_DCETHREAD( dcethread_interrupt(thread) );
168    MU_TRY_DCETHREAD( dcethread_join(thread, NULL) );
169}
170
171MU_TEST(dcethread_cond_wait, interrupt_post)
172{
173    dcethread* thread;
174    struct timespec ts;
175
176    ts.tv_nsec = 100000000;
177    ts.tv_sec = 0;
178
179    MU_TRY_DCETHREAD( dcethread_create(&thread, NULL, basic_thread, NULL) );
180    MU_TRY_DCETHREAD( dcethread_delay(&ts) );
181    MU_TRY_DCETHREAD( dcethread_interrupt(thread) );
182    MU_TRY_DCETHREAD( dcethread_join(thread, NULL) );
183}
184
185dcethread_mutex global_mutex = DCETHREAD_MUTEX_INITIALIZER;
186
187static void*
188global_lock_thread(void* data)
189{
190    volatile int interrupt_caught = 0;
191    dcethread_cond cond;
192
193    MU_TRY_DCETHREAD( dcethread_cond_init(&cond, NULL) );
194
195    DCETHREAD_TRY
196    {
197	MU_ASSERT(!interrupt_caught);
198        MU_TRY_DCETHREAD( dcethread_mutex_lock (&global_mutex) );
199
200	while (1)
201	{
202            MU_TRY_DCETHREAD( dcethread_cond_wait (&cond, &global_mutex) );
203	}
204    }
205    DCETHREAD_CATCH(dcethread_interrupt_e)
206    {
207	MU_ASSERT(!interrupt_caught);
208	interrupt_caught = 1;
209    }
210    DCETHREAD_FINALLY
211    {
212        dcethread_mutex_unlock (&global_mutex);
213    }
214    DCETHREAD_ENDTRY;
215
216    MU_ASSERT(interrupt_caught);
217
218    return NULL;
219}
220
221MU_TEST(dcethread_cond_wait, interrupt_global)
222{
223    dcethread* thread;
224    struct timespec ts;
225
226    ts.tv_nsec = 100000000;
227    ts.tv_sec = 0;
228
229    MU_TRY_DCETHREAD( dcethread_create(&thread, NULL, global_lock_thread, NULL) );
230    MU_TRY_DCETHREAD( dcethread_delay(&ts) );
231    MU_TRY_DCETHREAD( dcethread_mutex_lock(&global_mutex) );
232    MU_TRY_DCETHREAD( dcethread_interrupt(thread) );
233    MU_TRY_DCETHREAD( dcethread_mutex_unlock(&global_mutex) );
234    MU_TRY_DCETHREAD( dcethread_join(thread, NULL) );
235}
236
237#endif /* TEST */
238