mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-06 13:09:50 +00:00
Implement kernel semaphores.
Reviewed by: jhb
This commit is contained in:
parent
ee755665c2
commit
54db32e945
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=81645
@ -54,7 +54,7 @@ MAN= BUF_LOCK.9 BUF_LOCKFREE.9 BUF_LOCKINIT.9 BUF_REFCNT.9 \
|
||||
physio.9 posix4.9 printf.9 psignal.9 \
|
||||
random.9 resettodr.9 resource_int_value.9 resource_query_string.9 \
|
||||
rtalloc.9 rtentry.9 runqueue.9 \
|
||||
sbuf.9 scheduler.9 sleep.9 sleepqueue.9 spl.9 store.9 \
|
||||
sbuf.9 scheduler.9 sema.9 sleep.9 sleepqueue.9 spl.9 store.9 \
|
||||
style.9 suser.9 swi.9 sx.9 sysctl_add_oid.9 sysctl_ctx_init.9 \
|
||||
taskqueue.9 time.9 timeout.9 tvtohz.9 \
|
||||
ucred.9 uidinfo.9 uio.9 \
|
||||
@ -155,6 +155,13 @@ MLINKS+=sleep.9 asleep.9 sleep.9 await.9 sleep.9 msleep.9
|
||||
MLINKS+=sleepqueue.9 endtsleep.9 sleepqueue.9 sleepinit.9
|
||||
MLINKS+=sleepqueue.9 unsleep.9
|
||||
MLINKS+=buf.9 bp.9
|
||||
MLINKS+=sema.9 sema_init.9
|
||||
MLINKS+=sema.9 sema_destroy.9
|
||||
MLINKS+=sema.9 sema_post.9
|
||||
MLINKS+=sema.9 sema_wait.9
|
||||
MLINKS+=sema.9 sema_timedwait.9
|
||||
MLINKS+=sema.9 sema_trywait.9
|
||||
MLINKS+=sema.9 sema_value.9
|
||||
MLINKS+=spl.9 spl0.9
|
||||
MLINKS+=spl.9 splbio.9 spl.9 splclock.9 spl.9 splhigh.9 spl.9 splimp.9
|
||||
MLINKS+=spl.9 splnet.9 spl.9 splsoftclock.9 spl.9 splsofttty.9
|
||||
|
108
share/man/man9/sema.9
Normal file
108
share/man/man9/sema.9
Normal file
@ -0,0 +1,108 @@
|
||||
.\"
|
||||
.\" Copyright (C) 2001 Jason Evans <jasone@FreeBSD.org>. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice(s), this list of conditions and the following disclaimer as
|
||||
.\" the first lines of this file unmodified other than the possible
|
||||
.\" addition of one or more copyright notices.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice(s), this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
||||
.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
.\" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
|
||||
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
.\" DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 13, 2001
|
||||
.Dt SEMA 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm sema ,
|
||||
.Nm sema_init ,
|
||||
.Nm sema_destroy ,
|
||||
.Nm sema_post ,
|
||||
.Nm sema_wait ,
|
||||
.Nm sema_timedwait ,
|
||||
.Nm sema_trywait ,
|
||||
.Nm sema_value
|
||||
.Nd kernel counting semaphore
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <sys/sema.h>
|
||||
.Ft void
|
||||
.Fn sema_init "struct sema *sema" "int value" "const char *description"
|
||||
.Ft void
|
||||
.Fn sema_destroy "struct sema *sema"
|
||||
.Ft void
|
||||
.Fn sema_post "struct sema *sema"
|
||||
.Ft void
|
||||
.Fn sema_wait "struct sema *sema"
|
||||
.Ft int
|
||||
.Fn sema_timedwait "struct sema *sema" "int timo"
|
||||
.Ft int
|
||||
.Fn sema_trywait "struct sema *sema"
|
||||
.Ft int
|
||||
.Fn sema_value "struct sema *sema"
|
||||
.Sh DESCRIPTION
|
||||
Counting semaphores provide a mechanism for synchronizing access to a pool of
|
||||
resources.
|
||||
Unlike mutexes, semaphores do not have the concept of an owner, so they can also
|
||||
be useful in situations where one thread needs to acquire a resource, and
|
||||
another thread needs to release it.
|
||||
Each semaphore has an integer value associated with it.
|
||||
Posting (incrementing) always succeeds, but waiting (decrementing) can only
|
||||
successfully complete if the resulting value of the semaphore is greater than or
|
||||
equal to zero.
|
||||
.Pp
|
||||
Semaphores should not be used where mutexes and condition variables
|
||||
will suffice.
|
||||
Semaphores are a more complex synchronization mechanism than mutexes and
|
||||
condition variables and are not as efficient.
|
||||
.Pp
|
||||
Semaphores are created with
|
||||
.Fn sema_init ,
|
||||
where
|
||||
.Fa sema
|
||||
is a pointer to space for a
|
||||
.Vt struct sema ,
|
||||
.Fa value
|
||||
is the initial value of the semaphore, and
|
||||
.Fa description
|
||||
is a pointer toa null-terminated character string that describes the semaphore.
|
||||
Semaphores are destroyed with
|
||||
.Fn sema_destroy .
|
||||
A semaphore is posted (incremented) with
|
||||
.Fn sema_post .
|
||||
A semaphore is waited on (decremented) with
|
||||
.Fn sema_wait ,
|
||||
.Fn sema_timedwait ,
|
||||
or
|
||||
.Fn sema_trywait .
|
||||
The
|
||||
.Fa timo
|
||||
argument to
|
||||
.Fn sema_timedwait
|
||||
specifies the minimum time in ticks to wait before returning with failure.
|
||||
.Fn sema_value
|
||||
returns the current value of the semaphore.
|
||||
.Pp
|
||||
.Fn sema_timedwait
|
||||
and
|
||||
.Fn sema_trywait
|
||||
will return 0 if waiting on the semaphore failed; otherwise a non-zero value
|
||||
will be returned to indicate success.
|
||||
.Sh SEE ALSO
|
||||
.Xr mutex 9
|
||||
.Xr condvar 9
|
@ -783,6 +783,7 @@ kern/kern_physio.c standard
|
||||
kern/kern_proc.c standard
|
||||
kern/kern_prot.c standard
|
||||
kern/kern_resource.c standard
|
||||
kern/kern_sema.c standard
|
||||
kern/kern_shutdown.c standard
|
||||
kern/kern_sig.c standard
|
||||
kern/kern_subr.c standard
|
||||
|
177
sys/kern/kern_sema.c
Normal file
177
sys/kern/kern_sema.c
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Jason Evans <jasone@freebsd.org>. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice(s), this list of conditions and the following disclaimer as
|
||||
* the first lines of this file unmodified other than the possible
|
||||
* addition of one or more copyright notices.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice(s), this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Counting semaphores.
|
||||
*
|
||||
* Priority propagation will not generally raise the priority of semaphore
|
||||
* "owners" (a misnomer in the context of semaphores), so should not be relied
|
||||
* upon in combination with semaphores.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/condvar.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/sema.h>
|
||||
|
||||
void
|
||||
sema_init(struct sema *sema, int value, const char *description)
|
||||
{
|
||||
|
||||
KASSERT((value >= 0), ("%s(): negative value\n", __func__));
|
||||
|
||||
bzero(sema, sizeof(*sema));
|
||||
mtx_init(&sema->sema_mtx, "sema backing lock",
|
||||
MTX_DEF | MTX_NOWITNESS | MTX_QUIET);
|
||||
cv_init(&sema->sema_cv, description);
|
||||
sema->sema_value = value;
|
||||
|
||||
CTR3(KTR_LOCK, __func__ "(%p, %d, \"%s\")", sema, value, description);
|
||||
}
|
||||
|
||||
void
|
||||
sema_destroy(struct sema *sema)
|
||||
{
|
||||
|
||||
CTR2(KTR_LOCK, __func__ "(%p) \"%s\"", sema,
|
||||
cv_wmesg(&sema->sema_cv));
|
||||
|
||||
KASSERT((sema->sema_waiters == 0), ("%s(): waiters\n", __func__));
|
||||
|
||||
mtx_destroy(&sema->sema_mtx);
|
||||
cv_destroy(&sema->sema_cv);
|
||||
}
|
||||
|
||||
void
|
||||
_sema_post(struct sema *sema, const char *file, int line)
|
||||
{
|
||||
|
||||
mtx_lock(&sema->sema_mtx);
|
||||
sema->sema_value++;
|
||||
if (sema->sema_waiters && sema->sema_value > 0)
|
||||
cv_signal(&sema->sema_cv);
|
||||
|
||||
CTR5(KTR_LOCK, __func__ "(%p) \"%s\" v = %d at %s:%d", sema,
|
||||
cv_wmesg(&sema->sema_cv), sema->sema_value, file, line);
|
||||
|
||||
mtx_unlock(&sema->sema_mtx);
|
||||
}
|
||||
|
||||
void
|
||||
_sema_wait(struct sema *sema, const char *file, int line)
|
||||
{
|
||||
|
||||
mtx_lock(&sema->sema_mtx);
|
||||
while (sema->sema_value == 0) {
|
||||
sema->sema_waiters++;
|
||||
cv_wait(&sema->sema_cv, &sema->sema_mtx);
|
||||
sema->sema_waiters--;
|
||||
}
|
||||
sema->sema_value--;
|
||||
|
||||
CTR5(KTR_LOCK, __func__ "(%p) \"%s\" v = %d at %s:%d", sema,
|
||||
cv_wmesg(&sema->sema_cv), sema->sema_value, file, line);
|
||||
|
||||
mtx_unlock(&sema->sema_mtx);
|
||||
}
|
||||
|
||||
int
|
||||
_sema_timedwait(struct sema *sema, int timo, const char *file, int line)
|
||||
{
|
||||
int ret, timed_out;
|
||||
|
||||
mtx_lock(&sema->sema_mtx);
|
||||
|
||||
/*
|
||||
* A spurious wakeup will cause the timeout interval to start over.
|
||||
* This isn't a big deal as long as spurious wakeups don't occur
|
||||
* continuously, since the timeout period is merely a lower bound on how
|
||||
* long to wait.
|
||||
*/
|
||||
for (timed_out = 0; sema->sema_value == 0 && timed_out == 0;) {
|
||||
sema->sema_waiters++;
|
||||
timed_out = cv_timedwait(&sema->sema_cv, &sema->sema_mtx, timo);
|
||||
sema->sema_waiters--;
|
||||
}
|
||||
if (sema->sema_value > 0) {
|
||||
/* Success. */
|
||||
sema->sema_value--;
|
||||
ret = 1;
|
||||
|
||||
CTR5(KTR_LOCK, __func__ "(%p) \"%s\" v = %d at %s:%d", sema,
|
||||
cv_wmesg(&sema->sema_cv), sema->sema_value, file, line);
|
||||
} else {
|
||||
ret = 0;
|
||||
|
||||
CTR4(KTR_LOCK, __func__ "(%p) \"%s\" fail at %s:%d", sema,
|
||||
cv_wmesg(&sema->sema_cv), file, line);
|
||||
}
|
||||
|
||||
mtx_unlock(&sema->sema_mtx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
_sema_trywait(struct sema *sema, const char *file, int line)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mtx_lock(&sema->sema_mtx);
|
||||
|
||||
if (sema->sema_value > 0) {
|
||||
/* Success. */
|
||||
sema->sema_value--;
|
||||
ret = 1;
|
||||
|
||||
CTR5(KTR_LOCK, __func__ "(%p) \"%s\" v = %d at %s:%d", sema,
|
||||
cv_wmesg(&sema->sema_cv), sema->sema_value, file, line);
|
||||
} else {
|
||||
ret = 0;
|
||||
|
||||
CTR4(KTR_LOCK, __func__ "(%p) \"%s\" fail at %s:%d", sema,
|
||||
cv_wmesg(&sema->sema_cv), file, line);
|
||||
}
|
||||
|
||||
mtx_unlock(&sema->sema_mtx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
sema_value(struct sema *sema)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mtx_lock(&sema->sema_mtx);
|
||||
ret = sema->sema_value;
|
||||
mtx_unlock(&sema->sema_mtx);
|
||||
return (ret);
|
||||
}
|
60
sys/sys/sema.h
Normal file
60
sys/sys/sema.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Jason Evans <jasone@freebsd.org>. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice(s), this list of conditions and the following disclaimer as
|
||||
* the first lines of this file unmodified other than the possible
|
||||
* addition of one or more copyright notices.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice(s), this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SYS_SEMA_H_
|
||||
#define _SYS_SEMA_H_
|
||||
|
||||
#include <sys/_mutex.h>
|
||||
#include <sys/condvar.h>
|
||||
|
||||
struct sema {
|
||||
struct mtx sema_mtx; /* General protection lock. */
|
||||
struct cv sema_cv; /* Waiters. */
|
||||
int sema_waiters; /* Number of waiters. */
|
||||
int sema_value; /* Semaphore value. */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
void sema_init(struct sema *sema, int value, const char *description);
|
||||
void sema_destroy(struct sema *sema);
|
||||
void _sema_post(struct sema *sema, const char *file, int line);
|
||||
void _sema_wait(struct sema *sema, const char *file, int line);
|
||||
int _sema_timedwait(struct sema *sema, int timo, const char *file, int
|
||||
line);
|
||||
int _sema_trywait(struct sema *sema, const char *file, int line);
|
||||
int sema_value(struct sema *sema);
|
||||
|
||||
#define sema_post(sema) _sema_post((sema), __FILE__, __LINE__)
|
||||
#define sema_wait(sema) _sema_wait((sema), __FILE__, __LINE__)
|
||||
#define sema_timedwait(sema, timo) \
|
||||
_sema_timedwait((sema), (timo), __FILE__, __LINE__)
|
||||
#define sema_trywait(sema) _sema_trywait((sema), __FILE__, __LINE__)
|
||||
|
||||
#endif /* _KERNEL */
|
||||
#endif /* _SYS_SEMA_H_ */
|
Loading…
Reference in New Issue
Block a user