There are no extra threads.
The main difference is that Valgrind only allows one client thread
- to run at once. This is controlled with the VCPU semaphore,
- "run_sema". Any time a thread wants to run client code or
+ to run at once. This is controlled with the CPU Big Lock,
+ "the_BigLock". Any time a thread wants to run client code or
manipulate any shared state (which is anything other than its own
- ThreadState entry), it must hold the run_sema.
+ ThreadState entry), it must hold the_BigLock.
When a thread is about to block in a blocking syscall, it releases
- run_sema, and re-takes it when it becomes runnable again (either
+ the_BigLock, and re-takes it when it becomes runnable again (either
because the syscall finished, or we took a signal).
VG_(scheduler) therefore runs in each thread. It returns only when
}
/* CPU semaphore, so that threads can run exclusively */
-static vg_sema_t run_sema;
+static vg_sema_t the_BigLock;
/* ---------------------------------------------------------------------
}
/*
- Mark a thread as Runnable. This will block until the run_sema is
+ Mark a thread as Runnable. This will block until the_BigLock is
available, so that we get exclusive access to all the shared
- structures and the CPU. Up until we get the sema, we must not
+ structures and the CPU. Up until we get the_BigLock, we must not
touch any shared state.
When this returns, we'll actually be running.
*/
-void VG_(set_running)(ThreadId tid, HChar* who)
+void VG_(acquire_BigLock)(ThreadId tid, HChar* who)
{
ThreadState *tst;
}
#endif
- /* First, acquire the lock. We can't do anything else safely prior
- to this point. Even doing debug printing prior to this point
- is, technically, wrong. */
- ML_(sema_down)(&run_sema);
+ /* First, acquire the_BigLock. We can't do anything else safely
+ prior to this point. Even doing debug printing prior to this
+ point is, technically, wrong. */
+ ML_(sema_down)(&the_BigLock);
tst = VG_(get_ThreadState)(tid);
but it may mean that we remain in a Runnable state and we're just
yielding the CPU to another thread).
*/
-void VG_(set_sleeping)(ThreadId tid, ThreadStatus sleepstate, HChar* who)
+void VG_(release_BigLock)(ThreadId tid, ThreadStatus sleepstate, HChar* who)
{
ThreadState *tst = VG_(get_ThreadState)(tid);
print_sched_event(tid, buf);
}
- /* Release the run_sema; this will reschedule any runnable
+ /* Release the_BigLock; this will reschedule any runnable
thread. */
- ML_(sema_up)(&run_sema);
+ ML_(sema_up)(&the_BigLock);
}
/* Clear out the ThreadState and release the semaphore. Leaves the
if (VG_(clo_trace_sched))
print_sched_event(tid, "release lock in VG_(exit_thread)");
- ML_(sema_up)(&run_sema);
+ ML_(sema_up)(&the_BigLock);
}
/* If 'tid' is blocked in a syscall, send it SIGVGKILL so as to get it
vg_assert(tid != VG_INVALID_THREADID);
vg_assert(VG_(threads)[tid].os_state.lwpid == VG_(gettid)());
- VG_(set_sleeping)(tid, VgTs_Yielding, "VG_(vg_yield)");
+ VG_(release_BigLock)(tid, VgTs_Yielding, "VG_(vg_yield)");
/*
Tell the kernel we're yielding.
*/
VG_(do_syscall0)(__NR_sched_yield);
- VG_(set_running)(tid, "VG_(vg_yield)");
+ VG_(acquire_BigLock)(tid, "VG_(vg_yield)");
}
would be too hard to try to re-number the thread and relocate the
thread state down to VG_(threads)[1].
- This function also needs to reinitialize the run_sema, since
- otherwise we may end up sharing its state with the parent, which
- would be deeply confusing.
+ This function also needs to reinitialize the_BigLock, since
+ otherwise we may end up sharing its state with the parent, which
+ would be deeply confusing.
*/
static void sched_fork_cleanup(ThreadId me)
{
}
/* re-init and take the sema */
- ML_(sema_deinit)(&run_sema);
- ML_(sema_init)(&run_sema);
- ML_(sema_down)(&run_sema);
+ ML_(sema_deinit)(&the_BigLock);
+ ML_(sema_init)(&the_BigLock);
+ ML_(sema_down)(&the_BigLock);
}
vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
vg_assert(VG_IS_PAGE_ALIGNED(clstack_size));
- ML_(sema_init)(&run_sema);
+ ML_(sema_init)(&the_BigLock);
for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
/* Paranoia .. completely zero it out. */
/*
Run a thread until it wants to exit.
- We assume that the caller has already called VG_(set_running) for
+ We assume that the caller has already called VG_(acquire_BigLock) for
us, so we own the VCPU. Also, all signals are blocked.
*/
VgSchedReturnCode VG_(scheduler) ( ThreadId tid )
/* 3 Aug 06: doing sys__nsleep works but crashes some apps.
sys_yield also helps the problem, whilst not crashing apps. */
- VG_(set_sleeping)(tid, VgTs_Yielding,
- "VG_(scheduler):timeslice");
+ VG_(release_BigLock)(tid, VgTs_Yielding,
+ "VG_(scheduler):timeslice");
/* ------------ now we don't have The Lock ------------ */
# if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
}
# endif
- VG_(set_running)(tid, "VG_(scheduler):timeslice");
+ VG_(acquire_BigLock)(tid, "VG_(scheduler):timeslice");
/* ------------ now we do have The Lock ------------ */
/* OK, do some relatively expensive housekeeping stuff */
if (!VG_(is_running_thread)(tid)) {
VG_(message)(Vg_DebugMsg,
"Thread %d is supposed to be running, "
- "but doesn't own run_sema (owned by %d)\n",
+ "but doesn't own the_BigLock (owned by %d)\n",
tid, VG_(running_tid));
bad = True;
}
bad = True;
}
- if (lwpid != run_sema.owner_thread) {
+ if (lwpid != the_BigLock.owner_lwpid) {
VG_(message)(Vg_DebugMsg,
- "Thread %d doesn't own the run_sema\n",
+ "Thread (LWPID) %d doesn't own the_BigLock\n",
tid);
bad = True;
}
sema->pipe[1]);
vg_assert(sema->pipe[0] != sema->pipe[1]);
- sema->owner_thread = -1;
+ sema->owner_lwpid = -1;
/* create initial token */
sema_char = 'A';
void ML_(sema_deinit)(vg_sema_t *sema)
{
- vg_assert(sema->owner_thread != -1); /* must be initialised */
+ vg_assert(sema->owner_lwpid != -1); /* must be initialised */
vg_assert(sema->pipe[0] != sema->pipe[1]);
VG_(close)(sema->pipe[0]);
VG_(close)(sema->pipe[1]);
sema->pipe[0] = sema->pipe[1] = -1;
- sema->owner_thread = -1;
+ sema->owner_lwpid = -1;
}
/* get a token */
Int ret;
Int lwpid = VG_(gettid)();
- vg_assert(sema->owner_thread != lwpid); /* can't have it already */
+ vg_assert(sema->owner_lwpid != lwpid); /* can't have it already */
vg_assert(sema->pipe[0] != sema->pipe[1]);
again:
if (sema_char == 'Z') sema_char = 'A'; else sema_char++;
- sema->owner_thread = lwpid;
+ sema->owner_lwpid = lwpid;
}
/* put token back */
Char buf[2];
buf[0] = sema_char;
buf[1] = 0;
- vg_assert(sema->owner_thread != -1); /* must be initialised */
+ vg_assert(sema->owner_lwpid != -1); /* must be initialised */
vg_assert(sema->pipe[0] != sema->pipe[1]);
- vg_assert(sema->owner_thread == VG_(gettid)()); /* must have it */
+ vg_assert(sema->owner_lwpid == VG_(gettid)()); /* must have it */
- sema->owner_thread = 0;
+ sema->owner_lwpid = 0;
ret = VG_(write)(sema->pipe[1], buf, 1);