1*af29f831Sginsbach /* $NetBSD: t_once.c,v 1.2 2017/08/25 22:59:47 ginsbach Exp $ */
2ac555471Sjmmv
3ac555471Sjmmv /*
4ac555471Sjmmv * Copyright (c) 2008 The NetBSD Foundation, Inc.
5ac555471Sjmmv * All rights reserved.
6ac555471Sjmmv *
7ac555471Sjmmv * Redistribution and use in source and binary forms, with or without
8ac555471Sjmmv * modification, are permitted provided that the following conditions
9ac555471Sjmmv * are met:
10ac555471Sjmmv * 1. Redistributions of source code must retain the above copyright
11ac555471Sjmmv * notice, this list of conditions and the following disclaimer.
12ac555471Sjmmv * 2. Redistributions in binary form must reproduce the above copyright
13ac555471Sjmmv * notice, this list of conditions and the following disclaimer in the
14ac555471Sjmmv * documentation and/or other materials provided with the distribution.
15ac555471Sjmmv *
16ac555471Sjmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17ac555471Sjmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18ac555471Sjmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19ac555471Sjmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20ac555471Sjmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21ac555471Sjmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22ac555471Sjmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23ac555471Sjmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24ac555471Sjmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25ac555471Sjmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26ac555471Sjmmv * POSSIBILITY OF SUCH DAMAGE.
27ac555471Sjmmv */
28ac555471Sjmmv
29ac555471Sjmmv #include <sys/cdefs.h>
30ac555471Sjmmv __COPYRIGHT("@(#) Copyright (c) 2008\
31ac555471Sjmmv The NetBSD Foundation, inc. All rights reserved.");
32*af29f831Sginsbach __RCSID("$NetBSD: t_once.c,v 1.2 2017/08/25 22:59:47 ginsbach Exp $");
33ac555471Sjmmv
34*af29f831Sginsbach #include <sys/time.h>
35ac555471Sjmmv #include <pthread.h>
36ac555471Sjmmv #include <signal.h>
37ac555471Sjmmv #include <stdio.h>
38ac555471Sjmmv #include <stdlib.h>
39ac555471Sjmmv
40ac555471Sjmmv #include <atf-c.h>
41ac555471Sjmmv
42ac555471Sjmmv #include "h_common.h"
43ac555471Sjmmv
44ac555471Sjmmv static pthread_once_t once = PTHREAD_ONCE_INIT;
45ac555471Sjmmv static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
46ac555471Sjmmv static int x;
47ac555471Sjmmv
48ac555471Sjmmv #define NTHREADS 25
49ac555471Sjmmv
50ac555471Sjmmv static void
ofunc(void)51ac555471Sjmmv ofunc(void)
52ac555471Sjmmv {
53ac555471Sjmmv printf("Variable x has value %d\n", x);
54ac555471Sjmmv x++;
55ac555471Sjmmv }
56ac555471Sjmmv
57ac555471Sjmmv ATF_TC(once1);
ATF_TC_HEAD(once1,tc)58ac555471Sjmmv ATF_TC_HEAD(once1, tc)
59ac555471Sjmmv {
60ac555471Sjmmv atf_tc_set_md_var(tc, "descr", "Checks pthread_once()");
61ac555471Sjmmv }
ATF_TC_BODY(once1,tc)62ac555471Sjmmv ATF_TC_BODY(once1, tc)
63ac555471Sjmmv {
64ac555471Sjmmv
65ac555471Sjmmv printf("1: Test 1 of pthread_once()\n");
66ac555471Sjmmv
67ac555471Sjmmv PTHREAD_REQUIRE(pthread_once(&once, ofunc));
68ac555471Sjmmv PTHREAD_REQUIRE(pthread_once(&once, ofunc));
69ac555471Sjmmv
70ac555471Sjmmv printf("1: X has value %d\n",x );
71ac555471Sjmmv ATF_REQUIRE_EQ(x, 1);
72ac555471Sjmmv }
73ac555471Sjmmv
74ac555471Sjmmv static void
once2_ofunc(void)75ac555471Sjmmv once2_ofunc(void)
76ac555471Sjmmv {
77ac555471Sjmmv x++;
78ac555471Sjmmv printf("ofunc: Variable x has value %d\n", x);
79ac555471Sjmmv x++;
80ac555471Sjmmv }
81ac555471Sjmmv
82ac555471Sjmmv static void *
once2_threadfunc(void * arg)83ac555471Sjmmv once2_threadfunc(void *arg)
84ac555471Sjmmv {
85ac555471Sjmmv int num;
86ac555471Sjmmv
87ac555471Sjmmv PTHREAD_REQUIRE(pthread_once(&once, once2_ofunc));
88ac555471Sjmmv
89ac555471Sjmmv num = *(int *)arg;
90ac555471Sjmmv printf("Thread %d sees x with value %d\n", num, x);
91ac555471Sjmmv ATF_REQUIRE_EQ(x, 2);
92ac555471Sjmmv
93ac555471Sjmmv return NULL;
94ac555471Sjmmv }
95ac555471Sjmmv
96ac555471Sjmmv ATF_TC(once2);
ATF_TC_HEAD(once2,tc)97ac555471Sjmmv ATF_TC_HEAD(once2, tc)
98ac555471Sjmmv {
99ac555471Sjmmv atf_tc_set_md_var(tc, "descr", "Checks pthread_once()");
100ac555471Sjmmv }
ATF_TC_BODY(once2,tc)101ac555471Sjmmv ATF_TC_BODY(once2, tc)
102ac555471Sjmmv {
103ac555471Sjmmv pthread_t threads[NTHREADS];
104ac555471Sjmmv int id[NTHREADS];
105ac555471Sjmmv int i;
106ac555471Sjmmv
107ac555471Sjmmv printf("1: Test 2 of pthread_once()\n");
108ac555471Sjmmv
109ac555471Sjmmv for (i=0; i < NTHREADS; i++) {
110ac555471Sjmmv id[i] = i;
111ac555471Sjmmv PTHREAD_REQUIRE(pthread_create(&threads[i], NULL, once2_threadfunc, &id[i]));
112ac555471Sjmmv }
113ac555471Sjmmv
114ac555471Sjmmv for (i=0; i < NTHREADS; i++)
115ac555471Sjmmv PTHREAD_REQUIRE(pthread_join(threads[i], NULL));
116ac555471Sjmmv
117ac555471Sjmmv printf("1: X has value %d\n",x );
118ac555471Sjmmv ATF_REQUIRE_EQ(x, 2);
119ac555471Sjmmv }
120ac555471Sjmmv
121ac555471Sjmmv static void
once3_cleanup(void * m)122ac555471Sjmmv once3_cleanup(void *m)
123ac555471Sjmmv {
124ac555471Sjmmv pthread_mutex_t *mu = m;
125ac555471Sjmmv
126ac555471Sjmmv PTHREAD_REQUIRE(pthread_mutex_unlock(mu));
127ac555471Sjmmv }
128ac555471Sjmmv
129ac555471Sjmmv static void
once3_ofunc(void)130ac555471Sjmmv once3_ofunc(void)
131ac555471Sjmmv {
132ac555471Sjmmv pthread_testcancel();
133ac555471Sjmmv }
134ac555471Sjmmv
135ac555471Sjmmv static void *
once3_threadfunc(void * arg)136ac555471Sjmmv once3_threadfunc(void *arg)
137ac555471Sjmmv {
138ac555471Sjmmv PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
139ac555471Sjmmv pthread_cleanup_push(once3_cleanup, &mutex);
140ac555471Sjmmv PTHREAD_REQUIRE(pthread_once(&once, once3_ofunc));
141ac555471Sjmmv pthread_cleanup_pop(1);
142ac555471Sjmmv
143ac555471Sjmmv return NULL;
144ac555471Sjmmv }
145ac555471Sjmmv
146ac555471Sjmmv static void
handler(int sig,siginfo_t * info,void * ctx)147ac555471Sjmmv handler(int sig, siginfo_t *info, void *ctx)
148ac555471Sjmmv {
149ac555471Sjmmv atf_tc_fail("Signal handler was called; "
150ac555471Sjmmv "main thread deadlocked in pthread_once()");
151ac555471Sjmmv }
152ac555471Sjmmv
153ac555471Sjmmv ATF_TC(once3);
ATF_TC_HEAD(once3,tc)154ac555471Sjmmv ATF_TC_HEAD(once3, tc)
155ac555471Sjmmv {
156ac555471Sjmmv atf_tc_set_md_var(tc, "descr", "Checks pthread_once()");
157ac555471Sjmmv }
ATF_TC_BODY(once3,tc)158ac555471Sjmmv ATF_TC_BODY(once3, tc)
159ac555471Sjmmv {
160ac555471Sjmmv pthread_t thread;
161ac555471Sjmmv struct sigaction act;
162ac555471Sjmmv struct itimerval it;
163ac555471Sjmmv printf("Test 3 of pthread_once() (test versus cancellation)\n");
164ac555471Sjmmv
165ac555471Sjmmv act.sa_sigaction = handler;
166ac555471Sjmmv sigemptyset(&act.sa_mask);
167ac555471Sjmmv act.sa_flags = SA_SIGINFO;
168ac555471Sjmmv sigaction(SIGALRM, &act, NULL);
169ac555471Sjmmv
170ac555471Sjmmv timerclear(&it.it_value);
171ac555471Sjmmv it.it_value.tv_usec = 500000;
172ac555471Sjmmv timerclear(&it.it_interval);
173ac555471Sjmmv setitimer(ITIMER_REAL, &it, NULL);
174ac555471Sjmmv
175ac555471Sjmmv PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
176ac555471Sjmmv PTHREAD_REQUIRE(pthread_create(&thread, NULL, once3_threadfunc, NULL));
177ac555471Sjmmv PTHREAD_REQUIRE(pthread_cancel(thread));
178ac555471Sjmmv PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
179ac555471Sjmmv PTHREAD_REQUIRE(pthread_join(thread, NULL));
180ac555471Sjmmv
181ac555471Sjmmv PTHREAD_REQUIRE(pthread_once(&once, ofunc));
182ac555471Sjmmv
183ac555471Sjmmv /* Cancel timer */
184ac555471Sjmmv timerclear(&it.it_value);
185ac555471Sjmmv setitimer(ITIMER_REAL, &it, NULL);
186ac555471Sjmmv
187ac555471Sjmmv printf("Test succeeded\n");
188ac555471Sjmmv }
189ac555471Sjmmv
ATF_TP_ADD_TCS(tp)190ac555471Sjmmv ATF_TP_ADD_TCS(tp)
191ac555471Sjmmv {
192ac555471Sjmmv ATF_TP_ADD_TC(tp, once1);
193ac555471Sjmmv ATF_TP_ADD_TC(tp, once2);
194ac555471Sjmmv ATF_TP_ADD_TC(tp, once3);
195ac555471Sjmmv
196ac555471Sjmmv return atf_no_error();
197ac555471Sjmmv }
198