xref: /freebsd/sys/contrib/openzfs/lib/libspl/condvar.c (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * https://opensource.org/license/CDDL-1.0.
11  */
12 /*
13  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
14  * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
15  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
16  * Copyright (c) 2025, Klara, Inc.
17  */
18 
19 #include <assert.h>
20 #include <pthread.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <sys/timer.h>
24 #include <sys/condvar.h>
25 
26 /*
27  * =========================================================================
28  * condition variables
29  * =========================================================================
30  */
31 
32 void
cv_init(kcondvar_t * cv,char * name,int type,void * arg)33 cv_init(kcondvar_t *cv, char *name, int type, void *arg)
34 {
35 	(void) name, (void) type, (void) arg;
36 	VERIFY0(pthread_cond_init(cv, NULL));
37 }
38 
39 void
cv_destroy(kcondvar_t * cv)40 cv_destroy(kcondvar_t *cv)
41 {
42 	VERIFY0(pthread_cond_destroy(cv));
43 }
44 
45 void
cv_wait(kcondvar_t * cv,kmutex_t * mp)46 cv_wait(kcondvar_t *cv, kmutex_t *mp)
47 {
48 	memset(&mp->m_owner, 0, sizeof (pthread_t));
49 	VERIFY0(pthread_cond_wait(cv, &mp->m_lock));
50 	mp->m_owner = pthread_self();
51 }
52 
53 int
cv_wait_sig(kcondvar_t * cv,kmutex_t * mp)54 cv_wait_sig(kcondvar_t *cv, kmutex_t *mp)
55 {
56 	cv_wait(cv, mp);
57 	return (1);
58 }
59 
60 int
cv_timedwait(kcondvar_t * cv,kmutex_t * mp,clock_t abstime)61 cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
62 {
63 	int error;
64 	struct timeval tv;
65 	struct timespec ts;
66 	clock_t delta;
67 
68 	delta = abstime - ddi_get_lbolt();
69 	if (delta <= 0)
70 		return (-1);
71 
72 	VERIFY0(gettimeofday(&tv, NULL));
73 
74 	ts.tv_sec = tv.tv_sec + delta / hz;
75 	ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC + (delta % hz) * (NANOSEC / hz);
76 	if (ts.tv_nsec >= NANOSEC) {
77 		ts.tv_sec++;
78 		ts.tv_nsec -= NANOSEC;
79 	}
80 
81 	memset(&mp->m_owner, 0, sizeof (pthread_t));
82 	error = pthread_cond_timedwait(cv, &mp->m_lock, &ts);
83 	mp->m_owner = pthread_self();
84 
85 	if (error == ETIMEDOUT)
86 		return (-1);
87 
88 	VERIFY0(error);
89 
90 	return (1);
91 }
92 
93 int
cv_timedwait_hires(kcondvar_t * cv,kmutex_t * mp,hrtime_t tim,hrtime_t res,int flag)94 cv_timedwait_hires(kcondvar_t *cv, kmutex_t *mp, hrtime_t tim, hrtime_t res,
95     int flag)
96 {
97 	(void) res;
98 	int error;
99 	struct timeval tv;
100 	struct timespec ts;
101 	hrtime_t delta;
102 
103 	ASSERT(flag == 0 || flag == CALLOUT_FLAG_ABSOLUTE);
104 
105 	delta = tim;
106 	if (flag & CALLOUT_FLAG_ABSOLUTE)
107 		delta -= gethrtime();
108 
109 	if (delta <= 0)
110 		return (-1);
111 
112 	VERIFY0(gettimeofday(&tv, NULL));
113 
114 	ts.tv_sec = tv.tv_sec + delta / NANOSEC;
115 	ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC + (delta % NANOSEC);
116 	if (ts.tv_nsec >= NANOSEC) {
117 		ts.tv_sec++;
118 		ts.tv_nsec -= NANOSEC;
119 	}
120 
121 	memset(&mp->m_owner, 0, sizeof (pthread_t));
122 	error = pthread_cond_timedwait(cv, &mp->m_lock, &ts);
123 	mp->m_owner = pthread_self();
124 
125 	if (error == ETIMEDOUT)
126 		return (-1);
127 
128 	VERIFY0(error);
129 
130 	return (1);
131 }
132 
133 void
cv_signal(kcondvar_t * cv)134 cv_signal(kcondvar_t *cv)
135 {
136 	VERIFY0(pthread_cond_signal(cv));
137 }
138 
139 void
cv_broadcast(kcondvar_t * cv)140 cv_broadcast(kcondvar_t *cv)
141 {
142 	VERIFY0(pthread_cond_broadcast(cv));
143 }
144