This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [MTASCsft PATCH WIP5 01/33] Multi Thread, Async Signal and Async Cancel safety documentation: intro


On Sun, 2013-12-01 at 02:07 -0200, Alexandre Oliva wrote:
> On Nov 28, 2013, Torvald Riegel <triegel@redhat.com> wrote:
> 
> > Our functions have sequential specifications, that is, there are
> > preconditions and postconditions involving program state, arguments,
> > return value.
> 
> There's more than that.  There are such effects as calling back, in
> unspecified order (not even guaranteed sequential),

"Sequential" doesn't conflict with "unspecified order".  You can have a
sequential order even if you don't know *how* the individual parts are
ordered.  Like, you know, unspecified total orders.

>  user code that is
> expected to behave in certain ways but that may perform arbitrary
> additional operations.  There are such effects as interrupting a
> function part-way and performing additional operations there.

Even then, what the thing inbetween (eg, the callback) is supposed to do
(or allowed to do) is also specified with pre/post conditions.

> There are
> such effects as observable interleaving of concurrent executions.

If these are allowed for *some* functions, fine.  Even for those, we
will have, at the very least, sequential specifications too, or
something that can be reduced to them, because we need to reason about
single-threaded specifications too.  Even for those functions that have
(partial) concurrent specifications, I would guess that they aren't
complete concurrent specifications either.  But we should discuss this
for each case separately, I suppose.

For example, setsid/getsid are accessors to what's probably meant to be
shared state, and they don't have concurrent specifications.

> These
> are built right into the interface specifications.  I resist referring
> to these as sequential specifications in order to retain whatever is
> left of my sanity ;-)

Fine.  So let's group them.  Split those that say something explicitly
about concurrent invocations (examples?) from those that don't (e.g.,
setsid/getsid).

> > Given that your patch adds MT-Safe docs in the first place, I doubt
> > there is a significant number of functions that have a concurrent
> > specification.
> 
> I don't see how the purported conclusion follows from the premise.
> It seems to imply there's some fundamental incompatibility between
> thread-safety and concurrency!

No.  But if someone else had spent the effort to document concurrency,
wouldn't they have documented MT-Safety right away?  OTOH, I agree that
I'm mixing POSIX "docs" and glibc "docs" in this argument, so this isn't
mean to be causal effect; I'm just estimating that there won't be many
MT-Safe functions with a (complete) concurrent specification (ie, what I
said above).

> >> This is perfectly sufficient as a user-visible definition.
> 
> > No, see above.  There are choices we have to make and reflect in the
> > definition.
> 
> The choices you mentioned seemed to me to be artifacts of the unsuitable
> model you tried to fit things in.

They aren't.  See the getsid/setsid and funlock/ftrylock examples I
gave.

> >> those arise from
> >> the user-visible synchronization primitives only, which no functions are
> >> required to use internally, for the simple fact that no function is
> >> required to perform synchronization.
> 
> > If they don't access shared state, they are obviously not required to do
> > that.  If they do, they will do in practice because then several threads
> > access the same state.  If you don't want to read or produce garbage (in
> > the sense of states beyond what's specified in the sequential spec)
> > while doing that, you need to synchronize in some way; even if it's
> > single-word state, you need to synchronize to prevent the compiler from
> > making the assumption that this is sequential code (and thus reload, or
> > do any other optimization only safe in sequential code).
> 
> > If you mean something else by synchronization, then please define it.  I
> > already asked for a proper definition in a prior email.
> 
> By synchronization, I meant the synchronization primitives defined by
> POSIX, that synchronize the complete memory state (per the definition).
> No function is required to do that.  Even if it accesses shared state,
> it could refrain from using the global-sync primitives exposed to users,

Obviously, it can use other implementations.  The ordering guarantees
matter here, not whether it's the POSIX sync functions that are called
or others.

> and rely on stricter ones.

Stricter in which sense?  From an ordering perspective, you can't get
any stronger than "synchronize the complete memory state".

> Or C*11 atomics.  Or other features of the
> hardware memory model.

That's internal, and irrelevant to this discussion.  Let us focus on
which ordering guarantees we need to expose to the user program, not how
we do it.  It's fine if we say we want the same semantics as C11 memory
order X, for example, but that's not related to C11 atomics
specifically.

To me, synchronization is, roughly, synchronizing views of shared state
between several threads.  That's a conceptual thing, not just a POSIX or
C11 thing.  So my statement is that if you have shared state, you
probably need to synchronize in some way.  Even relaxed-memory-order
atomic accesses are synchronization in some way.

> Do you agree that only functions that POSIX explicitly specifies as
> synchronization functions are required to perform that sort of
> synchronization

I suppose "that sort" means the "synchronize the complete memory state"
notion?  Either way, I cannot agree or disagree here because POSIX
simply doesn't specify clearly what MT-Safe means.  It doesn't say that
MT-Safe would have to call those POSIX sync functions, but it also
doesn't say that MT-Safe would guarantee ordering/"synchronization"
semantics weaker than those.

> and that all other implementations can resort to more
> efficient primitives that are not exposed by POSIX interfaces, even if
> they are available to users through the implementation language?

The POSIX interfaces don't matter here, it's the semantics that matter.

> Do you agree that it follows from this that users of the POSIX APIs must
> not rely on any functions' performing global synchronization, and must
> perform it on their own if that's what they (the users) require?

No, because MT-Safe isn't defined in sufficient detail.  If it get's
clarified, for example regarding the choices I outlined and the
setsid/getsid and funlock/ftrylock examples I gave, then one is able to
answer this question.

> >> The internal library implementation may need to be aware of the
> >> underlying hardware and language memory models, and the application may
> >> want to take advantage of additional flexibility provided by them, but
> >> those are outside the scope of POSIX, and of the definition of whether
> >> POSIX-defined interfaces are MT-Safe.
> 
> > If POSIX doesn't want to rely on a language's memory model (which would
> > be unwise in the long term IMHO), fine.
> 
> There appears to be some miscommunication here.  Not exposing all of a
> model to users doesn't amount to not relying on it internally, nor to
> having incompatibilities with it.  Which of these, if any, would be
> unwise?

I said that it would be unwise for POSIX to not rely on a programming
language's memory model, C11's in this case, in the specification.  It
could specify a subset of this model on it's own, but if if this custom
model would have to be integrated with the C11 model anyway for
compatibility, then it could just reuse the parts that it would need to
define it's custom model.  Duplicating those doesn't seem worthwhile.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]