On Tue, Mar 8, 2022 at 7:26 AM Paolo Bonzini <[email protected]> wrote:
> On 3/8/22 15:09, Warner Losh wrote:
> >
> > Yes, qatomic_foo is expected to work. It's what we use across
> > threads, and it is expected to work "in kernel mode", i.e. within
> cpu_loop().
> >
> > Even when the writers are done in the context of system calls to the
> kernel?
>
> Yes.
>
> That said, for the similar syscall in Linux we just forward it to the
> kernel (and the kernel obviously can only do an atomic---no
> start_exclusive/end_exclusive involved).
>
OK. It seemed similar to futex, but I didn't know if that worked because
it restricted itself, or because all atomics worked when used from the
kernel :)
> > And if the system call does this w/o using
> > the start_exclusive/end_exclusive stuff, is that a problem?
>
> If it does it without start_exclusive/end_exclusive they must use
> qatomic_foo().
So this answer is in the context *-user implementing a system call
that's executed as a callout from cpu_loop()? Or does the kernel
have to use the C11 atomics that qatomic_foo() is based on... I'm
thinking the former based on the above, but want to make sure.
> If it does it with start_exclusive/end_exclusive, they
> can even write a compare-and-exchange as
>
> old = *(uint64_t *)g2h(cs, addr);
> if (old == oldval)
> *(uint64_t *)g2h(cs, addr) = new;
>
Nice.
The test program that's seeing corrupted mutex state is just two threads.
I've simplified
it a bit (it's an ATF test, and there's a lot of boilerplate that I
removed, including validating
the return values). It looks pretty straight forward. Often it will work,
sometimes, though
it fails with an internal assertion in what implements pthread_mutex about
state that's
not possible w/o the atomics/system calls that implement the pthread_mutex
failing to
work.
Warner
P.S. Here's the code for reading purposes... W/o the headers it won't
compile and the
ATF stuff at the end comes from elsewhere...
static pthread_mutex_t static_mutex = PTHREAD_MUTEX_INITIALIZER;
static int global_x;
bool thread3_started = false;
static void *
mutex3_threadfunc(void *arg) {
long count = *(int *)arg;
thread3_started = true;
while (count--) {
pthread_mutex_lock(&static_mutex);
global_x++;
pthread_mutex_unlock(&static_mutex);
}
}
int main(int argc, char **argv) {
int count, count2;
pthread_t new;
void *joinval;
global_x = 0;
count = count2 = 1000;
pthread_mutex_lock(&static_mutex);
pthread_create(&new, NULL, mutex3_threadfunc, &count2);
while (!thread3_started) {
/* Wait for thread 3 to start to increase chance of race */
}
pthread_mutex_unlock(&static_mutex);
while (count--) {
pthread_mutex_lock(&static_mutex);
global_x++;
pthread_mutex_unlock(&static_mutex);
}
pthread_join(new, &joinval);
pthread_mutex_lock(&static_mutex);
ATF_REQUIRE_EQ_MSG(count, -1, "%d", count);
ATF_REQUIRE_EQ_MSG((long)joinval, -1, "%ld", (long)joinval);
ATF_REQUIRE_EQ_MSG(global_x, 1000 * 2, "%d vs %d", globaol_x,
1000 * 2);
}