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);
}