Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144095524
D21254.id60756.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D21254.id60756.diff
View Options
Index: sys/kern/kern_synch.c
===================================================================
--- sys/kern/kern_synch.c
+++ sys/kern/kern_synch.c
@@ -52,6 +52,7 @@
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
+#include <sys/refcount.h>
#include <sys/sched.h>
#include <sys/sdt.h>
#include <sys/signalvar.h>
@@ -333,6 +334,36 @@
(flags & C_CATCH) ? PCATCH : 0, wmesg, sbt, pr, flags));
}
+/*
+ * Wait for a refcount wakeup. This does not guarantee that the ref is still
+ * zero on return and may be subject to transient wakeups. Callers wanting
+ * a precise answer should use refcount_wait().
+ */
+void
+refcount_sleep(volatile u_int *count, const char *wmesg, int pri)
+{
+ void *wchan;
+ u_int old;
+
+ if (REFCOUNT_COUNT(*count) == 0)
+ return;
+ wchan = __DEVOLATILE(void *, count);
+ sleepq_lock(wchan);
+ old = *count;
+ for (;;) {
+ if (REFCOUNT_COUNT(old) == 0) {
+ sleepq_release(wchan);
+ return;
+ }
+ if (old & REFCOUNT_WAITER)
+ break;
+ if (atomic_fcmpset_int(count, &old, old | REFCOUNT_WAITER))
+ break;
+ }
+ sleepq_add(wchan, NULL, wmesg, 0, 0);
+ sleepq_wait(wchan, pri);
+}
+
/*
* Make all threads sleeping on the specified identifier runnable.
*/
Index: sys/sys/refcount.h
===================================================================
--- sys/sys/refcount.h
+++ sys/sys/refcount.h
@@ -39,8 +39,11 @@
#define KASSERT(exp, msg) /* */
#endif
-#define REFCOUNT_SATURATED(val) (((val) & (1U << 31)) != 0)
-#define REFCOUNT_SATURATION_VALUE (3U << 30)
+#define REFCOUNT_WAITER (1 << 31) /* Refcount has waiter. */
+#define REFCOUNT_SATURATION_VALUE (3U << 29)
+
+#define REFCOUNT_SATURATED(val) (((val) & (1U << 30)) != 0)
+#define REFCOUNT_COUNT(x) ((x) & ~REFCOUNT_WAITER)
/*
* Attempt to handle reference count overflow and underflow. Force the counter
@@ -76,6 +79,17 @@
_refcount_update_saturated(count);
}
+static __inline void
+refcount_acquiren(volatile u_int *count, u_int n)
+{
+
+ u_int old;
+
+ old = atomic_fetchadd_int(count, n);
+ if (__predict_false(REFCOUNT_SATURATED(old)))
+ _refcount_update_saturated(count);
+}
+
static __inline __result_use_check bool
refcount_acquire_checked(volatile u_int *count)
{
@@ -91,13 +105,19 @@
}
static __inline bool
-refcount_release(volatile u_int *count)
+refcount_releasen(volatile u_int *count, u_int n)
{
u_int old;
+ u_int waiter;
atomic_thread_fence_rel();
- old = atomic_fetchadd_int(count, -1);
- if (__predict_false(old == 0 || REFCOUNT_SATURATED(old))) {
+ old = atomic_fetchadd_int(count, -n);
+ waiter = old & REFCOUNT_WAITER;
+ old = REFCOUNT_COUNT(old);
+ if (old > n)
+ return (false);
+
+ if (__predict_false(n > old || REFCOUNT_SATURATED(old))) {
/*
* Avoid multiple destructor invocations if underflow occurred.
* This is not perfect since the memory backing the containing
@@ -106,8 +126,14 @@
_refcount_update_saturated(count);
return (false);
}
- if (old > 1)
- return (false);
+
+ /*
+ * Attempt to atomically clear the waiter bit. Wakeup waiters
+ * if we are successful.
+ */
+ if (waiter != 0 &&
+ atomic_cmpset_int(count, REFCOUNT_WAITER, 0))
+ wakeup(__DEVOLATILE(u_int *, count));
/*
* Last reference. Signal the user to call the destructor.
@@ -119,6 +145,23 @@
return (true);
}
+static __inline bool
+refcount_release(volatile u_int *count)
+{
+
+ return (refcount_releasen(count, 1));
+}
+
+void refcount_sleep(volatile u_int *count, const char *wmesg, int prio);
+
+static __inline void
+refcount_wait(volatile u_int *count, const char *wmesg, int prio)
+{
+
+ while (*count != 0)
+ refcount_sleep(count, wmesg, prio);
+}
+
/*
* This functions returns non-zero if the refcount was
* incremented. Else zero is returned.
@@ -130,7 +173,7 @@
old = *count;
for (;;) {
- if (old == 0)
+ if (REFCOUNT_COUNT(old) == 0)
return (false);
if (__predict_false(REFCOUNT_SATURATED(old)))
return (true);
@@ -146,7 +189,7 @@
old = *count;
for (;;) {
- if (old == 1)
+ if (REFCOUNT_COUNT(old) == 1)
return (false);
if (__predict_false(REFCOUNT_SATURATED(old)))
return (true);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Feb 5, 4:24 PM (2 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28443066
Default Alt Text
D21254.id60756.diff (4 KB)
Attached To
Mode
D21254: Add support for blocking waits to refcounts.
Attached
Detach File
Event Timeline
Log In to Comment