xref: /freebsd/sys/contrib/openzfs/lib/libspl/condvar.c (revision 8ac904ce090b1c2e355da8aa122ca2252183f4e1)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or https://opensource.org/licenses/CDDL-1.0.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
25  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
26  * Copyright (c) 2025, Klara, Inc.
27  */
28 
29 #include <assert.h>
30 #include <pthread.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <sys/timer.h>
34 #include <sys/condvar.h>
35 
36 /*
37  * =========================================================================
38  * condition variables
39  * =========================================================================
40  */
41 
42 void
cv_init(kcondvar_t * cv,char * name,int type,void * arg)43 cv_init(kcondvar_t *cv, char *name, int type, void *arg)
44 {
45 	(void) name, (void) type, (void) arg;
46 	VERIFY0(pthread_cond_init(cv, NULL));
47 }
48 
49 void
cv_destroy(kcondvar_t * cv)50 cv_destroy(kcondvar_t *cv)
51 {
52 	VERIFY0(pthread_cond_destroy(cv));
53 }
54 
55 void
cv_wait(kcondvar_t * cv,kmutex_t * mp)56 cv_wait(kcondvar_t *cv, kmutex_t *mp)
57 {
58 	memset(&mp->m_owner, 0, sizeof (pthread_t));
59 	VERIFY0(pthread_cond_wait(cv, &mp->m_lock));
60 	mp->m_owner = pthread_self();
61 }
62 
63 int
cv_wait_sig(kcondvar_t * cv,kmutex_t * mp)64 cv_wait_sig(kcondvar_t *cv, kmutex_t *mp)
65 {
66 	cv_wait(cv, mp);
67 	return (1);
68 }
69 
70 int
cv_timedwait(kcondvar_t * cv,kmutex_t * mp,clock_t abstime)71 cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
72 {
73 	int error;
74 	struct timeval tv;
75 	struct timespec ts;
76 	clock_t delta;
77 
78 	delta = abstime - ddi_get_lbolt();
79 	if (delta <= 0)
80 		return (-1);
81 
82 	VERIFY0(gettimeofday(&tv, NULL));
83 
84 	ts.tv_sec = tv.tv_sec + delta / hz;
85 	ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC + (delta % hz) * (NANOSEC / hz);
86 	if (ts.tv_nsec >= NANOSEC) {
87 		ts.tv_sec++;
88 		ts.tv_nsec -= NANOSEC;
89 	}
90 
91 	memset(&mp->m_owner, 0, sizeof (pthread_t));
92 	error = pthread_cond_timedwait(cv, &mp->m_lock, &ts);
93 	mp->m_owner = pthread_self();
94 
95 	if (error == ETIMEDOUT)
96 		return (-1);
97 
98 	VERIFY0(error);
99 
100 	return (1);
101 }
102 
103 int
cv_timedwait_hires(kcondvar_t * cv,kmutex_t * mp,hrtime_t tim,hrtime_t res,int flag)104 cv_timedwait_hires(kcondvar_t *cv, kmutex_t *mp, hrtime_t tim, hrtime_t res,
105     int flag)
106 {
107 	(void) res;
108 	int error;
109 	struct timeval tv;
110 	struct timespec ts;
111 	hrtime_t delta;
112 
113 	ASSERT(flag == 0 || flag == CALLOUT_FLAG_ABSOLUTE);
114 
115 	delta = tim;
116 	if (flag & CALLOUT_FLAG_ABSOLUTE)
117 		delta -= gethrtime();
118 
119 	if (delta <= 0)
120 		return (-1);
121 
122 	VERIFY0(gettimeofday(&tv, NULL));
123 
124 	ts.tv_sec = tv.tv_sec + delta / NANOSEC;
125 	ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC + (delta % NANOSEC);
126 	if (ts.tv_nsec >= NANOSEC) {
127 		ts.tv_sec++;
128 		ts.tv_nsec -= NANOSEC;
129 	}
130 
131 	memset(&mp->m_owner, 0, sizeof (pthread_t));
132 	error = pthread_cond_timedwait(cv, &mp->m_lock, &ts);
133 	mp->m_owner = pthread_self();
134 
135 	if (error == ETIMEDOUT)
136 		return (-1);
137 
138 	VERIFY0(error);
139 
140 	return (1);
141 }
142 
143 void
cv_signal(kcondvar_t * cv)144 cv_signal(kcondvar_t *cv)
145 {
146 	VERIFY0(pthread_cond_signal(cv));
147 }
148 
149 void
cv_broadcast(kcondvar_t * cv)150 cv_broadcast(kcondvar_t *cv)
151 {
152 	VERIFY0(pthread_cond_broadcast(cv));
153 }
154