Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Wed, 23 Feb 2022 19:57:46 +0100
From: Markus Wichmann <nullplan@....net>
To: musl@...ts.openwall.com
Subject: Re: Suggestion for thread safety

On Wed, Feb 23, 2022 at 12:30:43AM +0000, Lee Shallis wrote:
> think of the lock as the same as a mutex, just simpler,

It isn't really simpler than a fast mutex, but a lot buggier.

> it is supposed
> to prevent execution races for potentially non-thread safe system
> calls such a poorly implemented malloc (which can have it's symbol
> overwritten by a developer implementation),

Any malloc implementation has to be thread safe. It is not sensible to
use one that isn't. It is also not sensible to pessimise the whole
program because one day a developer might choose to do something stupid.

> fprintf etc (which from
> what I've heard are NOT thread safe)

fprintf() takes a FILE and must therefore act as if flockfile() was
called on entry and funlockfile() on exit. IOW: Accesses to the same file
are ordered. If not, the implementation is broken.

> also errno might not be
> thread local under some implementations,

Any such implementation is fundamentally broken and cannot be repaired.
There is no way to call a blocking system call in such a system without
taking the lock on errno first, thereby suspending all other threads
that might try to access errno, which is pretty much all of them, except
maybe for some pure calculations somewhere, thereby negating any benefit
multi-threading might have brought the program.

> it's better to assume it's
> not then to assume it is and have all hell break loose.

I disagree. It is better to assume the standards are followed and fix
problems as they occur than to assume you are programming for some kind
of space alien computer that works by rules inconsistent with any normal
system. Report the bug, work around it if necessary, and move on.

I recently found myself on a system on which, unbeknownst to me,
sendmsg() always returns 0 when called on TCP sockets. I wrote a program
assuming it would work. It did not. I reported the bug and worked around
the problem with malloc() and send(). That is why we test.

> just use it to simplify any code that had to go through the
> effort of calling pthread_mutex_create/pthread_mutex_destroy or
> whatever,

PTHREAD_MUTEX_INITIALIZER exists.

> the code I gave was literally a simple
> example of how to hide system thread safety details in pure ansi C,

Nonsense. You didn't hide anything, you didn't make anything safer, and
by staying in ANSI C, you make it impossible to achieve your goal.

> As for your point about splitting paragraphs up, I'm not very good at
> that as you might have noticed by now,

If you don't care to be understood, I won't care to understand you. And
it is pretty difficult to convince people that don't understand you.

> anyways the point of these is
> that I wanted a simpler system than the one that is provided so that
> if I ever put enough work into my library that it no longer needs libc
> then I would be able to do so rather seamlessly,

You might have bitten off more than you can chew with that goal. Writing
a libc is no mean feat, and developing a library to the point it could
replace libc takes about as much effort. Somehow people seem to think
they'll start with memcpy() and it will stay on that level of
complexity. It won't.

> in other words just
> with LOCK & pauseCB I've achieved thread safety without the file
> knowing anything about the system api,

You have indeed not done that. You have instead written the word "lock"
enough times to give someone skim-reading the file false confidence that
this stuff will actually work in a multi-threaded context, only to then
fail under high load for inexplicable reasons.

I keep seeing this behavior from programmers that ought to know better.
You see, an exclusive lock consists of two parts: The mutual exclusion
and the sleep. And yes, spinlocks skip the second part, but my point is:
The mutual exclusion is actually the easy part, and any hack with a
Messiah complex and a CPU manual can do it. The sleep is the hard part,
if you want to do it right. It needs to be Goldilocks. Too short, and
you are wasting resources (every time your thread spins in the loop is
time the CPU could have better spent on other threads), too long and you
are wasting time.

Your sleep is definitely too short, and you didn't even get the mutual
exclusion part right.

Ciao,
Markus

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.