summaryrefslogtreecommitdiff
path: root/libgo/runtime/lock_sema.c
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-06 19:49:01 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-06 19:49:01 +0000
commit0ce10ea1348e9afd5d0eec6bca986bfe58bac5ac (patch)
tree39530b071991b2326f881b2a30a2d82d6c133fd6 /libgo/runtime/lock_sema.c
parent57a8bf1b0c6057ccbacb0cf79eb84d1985c2c1fe (diff)
downloadgcc-0ce10ea1348e9afd5d0eec6bca986bfe58bac5ac.tar.gz
libgo: Update to October 24 version of master library.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@204466 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/runtime/lock_sema.c')
-rw-r--r--libgo/runtime/lock_sema.c101
1 files changed, 66 insertions, 35 deletions
diff --git a/libgo/runtime/lock_sema.c b/libgo/runtime/lock_sema.c
index 2663c5463de..ce435119323 100644
--- a/libgo/runtime/lock_sema.c
+++ b/libgo/runtime/lock_sema.c
@@ -95,9 +95,6 @@ runtime_unlock(Lock *l)
uintptr v;
M *mp;
- if(--runtime_m()->locks < 0)
- runtime_throw("runtime_unlock: lock count");
-
for(;;) {
v = (uintptr)runtime_atomicloadp((void**)&l->key);
if(v == LOCKED) {
@@ -114,6 +111,9 @@ runtime_unlock(Lock *l)
}
}
}
+
+ if(--runtime_m()->locks < 0)
+ runtime_throw("runtime_unlock: lock count");
}
// One-time notifications.
@@ -151,6 +151,10 @@ runtime_notesleep(Note *n)
M *m;
m = runtime_m();
+
+ if(runtime_g() != m->g0)
+ runtime_throw("notesleep not on g0");
+
if(m->waitsema == 0)
m->waitsema = runtime_semacreate();
if(!runtime_casp((void**)&n->key, nil, m)) { // must be LOCKED (got wakeup)
@@ -159,61 +163,49 @@ runtime_notesleep(Note *n)
return;
}
// Queued. Sleep.
- if(m->profilehz > 0)
- runtime_setprof(false);
runtime_semasleep(-1);
- if(m->profilehz > 0)
- runtime_setprof(true);
}
-void
-runtime_notetsleep(Note *n, int64 ns)
+static bool
+notetsleep(Note *n, int64 ns, int64 deadline, M *mp)
{
M *m;
- M *mp;
- int64 deadline, now;
-
- if(ns < 0) {
- runtime_notesleep(n);
- return;
- }
m = runtime_m();
- if(m->waitsema == 0)
- m->waitsema = runtime_semacreate();
+
+ // Conceptually, deadline and mp are local variables.
+ // They are passed as arguments so that the space for them
+ // does not count against our nosplit stack sequence.
// Register for wakeup on n->waitm.
if(!runtime_casp((void**)&n->key, nil, m)) { // must be LOCKED (got wakeup already)
if(n->key != LOCKED)
runtime_throw("notetsleep - waitm out of sync");
- return;
+ return true;
+ }
+
+ if(ns < 0) {
+ // Queued. Sleep.
+ runtime_semasleep(-1);
+ return true;
}
- if(m->profilehz > 0)
- runtime_setprof(false);
deadline = runtime_nanotime() + ns;
for(;;) {
// Registered. Sleep.
if(runtime_semasleep(ns) >= 0) {
// Acquired semaphore, semawakeup unregistered us.
// Done.
- if(m->profilehz > 0)
- runtime_setprof(true);
- return;
+ return true;
}
// Interrupted or timed out. Still registered. Semaphore not acquired.
- now = runtime_nanotime();
- if(now >= deadline)
+ ns = deadline - runtime_nanotime();
+ if(ns <= 0)
break;
-
// Deadline hasn't arrived. Keep sleeping.
- ns = deadline - now;
}
- if(m->profilehz > 0)
- runtime_setprof(true);
-
// Deadline arrived. Still registered. Semaphore not acquired.
// Want to give up and return, but have to unregister first,
// so that any notewakeup racing with the return does not
@@ -223,15 +215,54 @@ runtime_notetsleep(Note *n, int64 ns)
if(mp == m) {
// No wakeup yet; unregister if possible.
if(runtime_casp((void**)&n->key, mp, nil))
- return;
+ return false;
} else if(mp == (M*)LOCKED) {
// Wakeup happened so semaphore is available.
// Grab it to avoid getting out of sync.
if(runtime_semasleep(-1) < 0)
runtime_throw("runtime: unable to acquire - semaphore out of sync");
- return;
- } else {
+ return true;
+ } else
runtime_throw("runtime: unexpected waitm - semaphore out of sync");
- }
}
}
+
+bool
+runtime_notetsleep(Note *n, int64 ns)
+{
+ M *m;
+ bool res;
+
+ m = runtime_m();
+
+ if(runtime_g() != m->g0 && !m->gcing)
+ runtime_throw("notetsleep not on g0");
+
+ if(m->waitsema == 0)
+ m->waitsema = runtime_semacreate();
+
+ res = notetsleep(n, ns, 0, nil);
+ return res;
+}
+
+// same as runtime_notetsleep, but called on user g (not g0)
+// calls only nosplit functions between entersyscallblock/exitsyscall
+bool
+runtime_notetsleepg(Note *n, int64 ns)
+{
+ M *m;
+ bool res;
+
+ m = runtime_m();
+
+ if(runtime_g() == m->g0)
+ runtime_throw("notetsleepg on g0");
+
+ if(m->waitsema == 0)
+ m->waitsema = runtime_semacreate();
+
+ runtime_entersyscallblock();
+ res = notetsleep(n, ns, 0, nil);
+ runtime_exitsyscall();
+ return res;
+}