Trivial C11 threads.h wrapper (public domain)

M

Markus Elfring

Exactly, in particular there are some linux systems where the headers
are annotated with gcc extensions that make it difficult to ignore the
return of a system function.

I would appreciate if such return value ignorance can be avoided.
http://stackoverflow.com/questions/...n-value-is-unused-for-a-certain-type#12416677

And then, finally, the C11 standard leaves no way to get semantic of a
failed call accros, here.

I find this information questionable. I get the impression from one of your
articles that you know also alternative approaches.
http://gustedt.wordpress.com/2012/07/15/capture-return-codes-from-library-functions/

Do you see a way to use the return value in some way?

Yes, of course! ;-)

How do think about to forward the error code to a log message for a file like
"stderr" eventually?
Would you like to call the function "abort" if a function call like
"pthread_mutex_destroy" failed?

Is the completion of error detection and corresponding exception handling an
open issue also in the affected wrapper implementation?

Regards,
Markus
 
J

Jens Gustedt

Hallo Marcus,

Am 01.10.2012 11:25, schrieb Markus Elfring:
I would appreciate if such return value ignorance can be avoided.
http://stackoverflow.com/questions/...n-value-is-unused-for-a-certain-type#12416677

The problem here is that this is not an interface that I/we design,
but that this is supposed to emulate a C library interface. The
description there is extremely concise, and in particular it doesn't
foresee the possibility of failure of the call. (For other functions
the standard would have some generic phrase "if you pass invalid input
to the function the behavior is undefined".)
I find this information questionable. I get the impression from one of your
articles that you know also alternative approaches.
http://gustedt.wordpress.com/2012/07/15/capture-return-codes-from-library-functions/

The wrappers there suppose that the functions *do* give a return
indication that something went wrong and then provide an possible
extension to capture such an error with a try/catch mechanism.

If you'd want to have such a wrapper around the *pthread* functions,
there is no problem, and you could even use P99 tools for that.

I think I can't do that per default, here, since the mtx_destroy
function then would be non-conforming.

But one could definitively think of an optional header that wraps the
pthread calls (and perhaps other POSIX stuff) and put a red tape on
that saying that the resulting code may not be C11 conforming on
certain aspects.
Yes, of course! ;-)

How do think about to forward the error code to a log message for a file like
"stderr" eventually?
Would you like to call the function "abort" if a function call like
"pthread_mutex_destroy" failed?

Is the completion of error detection and corresponding exception handling an
open issue also in the affected wrapper implementation?

No, I don't think that this is a general problem, since most of the
C11 function foresee a mechanism to return error conditions. There are
only a few functions like this one that don't have any at all.

What is generally happening, though, is that the error conditions that
C11 foresees are only a subset of what POSIX provides. So sometimes
there might be a loss of information.

Jens
 
M

Markus Elfring

The problem here is that this is not an interface that I/we design,
but that this is supposed to emulate a C library interface. The
description there is extremely concise, and in particular it doesn't
foresee the possibility of failure of the call. (For other functions
the standard would have some generic phrase "if you pass invalid input
to the function the behavior is undefined".)

I would appreciate if members of the involved standardisation committees will
share their advices for proper and unambiguous interpretation of the discussed
specification and corresponding implementation details.

No, I don't think that this is a general problem, since most of the
C11 function foresee a mechanism to return error conditions. There are
only a few functions like this one that don't have any at all.

What is generally happening, though, is that the error conditions that
C11 foresees are only a subset of what POSIX provides. So sometimes
there might be a loss of information.

I guess that this feature difference in the programming interfaces will lead to
a lot of more discussions between software developers, reviewers and testers. I
am curious on further clarifications.

Regards,
Markus
 
J

Jens Gustedt

Am 01.10.2012 12:05, schrieb Markus Elfring:
I would appreciate if members of the involved standardisation committees will
share their advices for proper and unambiguous interpretation of the discussed
specification and corresponding implementation details.

You probably could have a point here, in issuing a defect report on
the standard. I think it would certainly be a good idea if the
standard would have such a phrase, this then would allow an
implementation to do what pleases, e.g raise an exception.

I guess that this feature difference in the programming interfaces will lead to
a lot of more discussions between software developers, reviewers and testers. I
am curious on further clarifications.

By programming with these thinks myself (and translating code that had
been written for pthread to C11 threads) I found that most of the
differences are minor and can be easily dealt with.

The main difference is really the starting point of this discussion,
the differing function types for threads. And this one is well
justified from the POV of C, int is the type that you'd have to expect
as a return from a thread, just as main returns an int to the
environment.

On my page for possible defects/improvements for C

p99.gforge.inria.fr/defects-and-improvements

I already have a list of useless incompatibilities between C and
C++. Perhaps it would be good to add the same sort of discussion for C
versus POSIX. Since POSIX always tries (or tried so far) to be
compatible with the current C standard, they probably will want to
deal with these new interfaces and try to explain how they work
together.

Jens
 
N

Noob

Markus said:
I would appreciate if members of the involved standardisation committees will
share their advices for proper and unambiguous interpretation of the discussed
specification and corresponding implementation details.

There might be some POSIX members in comp.unix.programmer

There might be some ISO/IEC JTC1/SC22/WG14 members in comp.std.c
 
J

James Kuyper

Enums have a type already

True, though it need not be a nameable type - the tag is optional.
... and can only take a value in their range.

That depend upon what you mean by "their range". Every enumerated type
has a corresponding compatible integer type. I believe that any value
representable in that integer type can also be be stored in the
enumerated type.
What's the advantage of a typedef? ...

I can't think of any, off-hand, but others may be able to.
 
E

Eric Sosman

Enums have a type already and can only take a value in their range.

An enum has a type, yes, but a variable of that type is
not range-restricted.

enum { FOO=1, BAR=2 } x;
x = 42; // legal

Some see this as a flaw in C, and I'd have to agree that C's
enums are sort of half-baked. However, it allows things like

enum { COMMAND=1, DATA=2, STROBE=0x40, RESET=0x80 } flags;
flags = STROBE | DATA;
What's the advantage of a typedef? the disadvantage is extended the
type space.

In this instance it's moot. The source under discussion tries
to mimic C11 thread support for systems that lack C11 but have
Pthreads. As a C11 imitation, it should not introduce gratuitous
identifiers not called for by the C11 Standard. (Some, of course,
are unavoidable: The Pthreads-related headers declare names that
the C11 Standard reserves for the programmer's use, and some of
those even have external linkage.)
 
N

Nick Bowler

Am 01.10.2012 11:25, schrieb Markus Elfring:

The problem here is that this is not an interface that I/we design,
but that this is supposed to emulate a C library interface. The
description there is extremely concise, and in particular it doesn't
foresee the possibility of failure of the call. (For other functions
the standard would have some generic phrase "if you pass invalid input
to the function the behavior is undefined".)

The standard is clear that if it does not specify the behaviour for some
particular input to a function, then the behaviour is undefined if the
program does such a thing (C11§4p2). I think the _intent_ is that the
description of mtx_destroy does not specify the behaviour if it is
passed a pointer to a mtx_t object which either

(a) has never been set by a successful call to mtx_init, or
(b) has been destroyed by a call to mtx_destroy with no subsequent
successful call to mtx_init.

and therefore the behaviour would be undefined.

On the other hand, the mutex specification appears to play fast and
loose with terminology which makes everything rather murky. For
instance (at least in the n1570 document), it does not use the word
"shall" (which has formal meaning in this standard) in its restriction
that there be no threads blocked on the mutex when calling mtx_destroy
(C11§7.26.4.1p2). It also uses the word "mutex" to refer to two
apparently different things:

(1) Objects of type mtx_t are described as "hold[ing] an identifier
for a mutex" (C11§7.26.1p4), but such objects of type mtx_t are
themselves called "mutex"es in the remainder of the section.

(2) But there is another thing called a "mutex", which is created by
mtx_init and is *not* an object of type mtx_t -- the mtx_init
assigns an identifier uniquely identifying this "mutex" to an
object of type mtx_t (which the specification also calls a
"mutex"!) Here's a gem (C11§7.26.4.2):

If the mtx_init function succeeds, it sets the mutex pointed
to by mtx to a value that identifies the newly created mutex.

Gross!

NB: I cannot find an italicised definition of mutex in the document, nor
does it appear in section 3, so I guess it's assumed that anyone reading
the document already knows exactly what it is. But given the above,
even the standard authors don't seem clear on this point. That being
said, I haven't read all of the normative references so it could
technically have a proper definition in one of those...
 
K

Keith Thompson

Toby Douglass said:
Enums have a type already and can only take a value in their range.
What's the advantage of a typedef? the disadvantage is extended the
type space.

I believe that the intent of the enumeration constants defined by
C11's <threads.h> is not to define enumeration *types*. It's merely
to provide constants of type int with distinct values. If this
were C++ rather than C, it's likely that they'd be defined as
"const int" objects -- or, conversely, that the functions they're
passed to would take arguments of an enumeration type.

I presume, though the standard doesn't say so explicitly, that

mtx_plain, mtx_recursive, mtx_timed

are intended to have distinct values as are

thrd_timedout, thrd_success, thrd_busy, thrd_error, thrd_nomem

An enumeration type (without a tag or typedef) is an easy way to
achieve that. Adding a tag and/or typedef would create a type name
that's never actually used. Using that type for the parameters to
the relevant functions would not provide any type safety.
 
K

Keith Thompson

Jens Gustedt said:
The problem here is that this is not an interface that I/we design,
but that this is supposed to emulate a C library interface. The
description there is extremely concise, and in particular it doesn't
foresee the possibility of failure of the call. (For other functions
the standard would have some generic phrase "if you pass invalid input
to the function the behavior is undefined".)
[...]

I haven't studied C11's <threads.h> closely, but I do find the
description of mtx_destroy() a bit troubling:

Synopsis

1 #include <threads.h>
void mtx_destroy(mtx_t *mtx);

Description

2 The mtx_destroy function releases any resources used by the mutex
pointed to by mtx. No threads can be blocked waiting for the
mutex pointed to by mtx.

Returns

3 The mtx_destroy function returns no value.

So what does mtx_destroy() do if some thread *is* blocked waiting
for mtx? I suppose the behavior is undefined by omission, but
changing the word "can" to "shall" would have made that explicit.

And why not define the behavior, more or less as POSIX does?
Would detecting blocked threads be too difficult on some systems?
 
K

Kaz Kylheku

So what does mtx_destroy() do if some thread *is* blocked waiting
for mtx?

What if some thread is using a pointer P and another one calls free(P)?

The program is broken in that situation. One thread is finalizing an object,
but it has no right to do that because the object is referenced elsewhere.

The real POSIX API provides return values for situations like this: EBUSY (the
mutex is being destroyed while it is locked or in use) and EINVAL: the mutex is
invalid.

However, these return values are optional! Implementations do not have check
these situations. (Not even for mutexes attributed as having type
PTHREAD_MUTEX_ERRORCHECK: that type causes certain very specific debugging
checks to be required in the lock and unlock operations only.)
 
J

Jens Gustedt

Am 30.09.2012 23:13, schrieb Markus Elfring:
I would interpret source code like the following as an update candidate.

http://p99.gforge.inria.fr/p99-html/p99__threads_8h_source.html :
...
00633 // 7.26.4 Mutex functions
00634
00638 p99_inline
00639 void mtx_destroy(mtx_t *p00_mtx) {
00640 (void)pthread_mutex_destroy(&P99_ENCP(p00_mtx));
00641 }
...


How do think about to get rid of the cast to the return type "void" in such use
cases?

Ok, the discussion that followed this have conviced me that we are
facing a defect of the C11 specification here. I have written up my
ideas about that and added the report to my list on

http://p99.gforge.inria.fr/defects-and-improvements

Jens
 
M

Markus Elfring

The main difference is really the starting point of this discussion,
the differing function types for threads. And this one is well
justified from the POV of C, int is the type that you'd have
to expect as a return from a thread, just as main returns an int
to the environment.

On my page for possible defects/improvements for C

I am curious if you will get feedback by standardisation committee members for
your descriptions.
http://p99.gforge.inria.fr/defects-and-improvements/DR-underspecified-thread-functions.html

Did you forward any of them to an "official" communication channel?


Do the discussed functions just use an interface style that we all know from a
function like "free"?
http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html

Do such standard specifications allow different error handling implementations?

Regards,
Markus
 
K

Keith Thompson

Markus Elfring said:
I am curious if you will get feedback by standardisation committee
members for your descriptions.
http://p99.gforge.inria.fr/defects-and-improvements/DR-underspecified-thread-functions.html

Did you forward any of them to an "official" communication channel?
[...]

Posting to comp.std.c is *slightly* more likely to get the committee's
attention than posting to comp.lang.c. The committee has no official
relationship with either newsgroup, but comp.std.c has lower traffic and
is likely to have more commmittee members reading it.
 
J

Jens Gustedt

Hello,

Am 03.10.2012 11:02, schrieb Markus Elfring:
I am curious if you will get feedback by standardisation committee members for
your descriptions.
http://p99.gforge.inria.fr/defects-and-improvements/DR-underspecified-thread-functions.html

Did you forward any of them to an "official" communication channel?

I am not sure what channel that would be, the ISO committees don't
seem to be very open to the outside world. But as Keith suggest,
comp.std.c has probably better chances to be read, so I am
crossposting there.
Do the discussed functions just use an interface style that we all know from a
function like "free"?
http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html

Do such standard specifications allow different error handling implementations?

Yes, I think so. It clearly defines under what circumstances the
behavior is undefined, so an implementation would be allowed to define
a behavior as it wishes in these cases.

Generally, if you look at the text for free that you are citing, and
compare it with the text about the threads in C11, you'll notice a
difference in quality. C11 certainly lacked some iterations of
discussion and error correction before it went into the standard. In
particular, a better coordination with the POSIX committee would have
been in order concerning threads.

Jens
 
M

Markus Elfring

I am curious if you will get feedback by standardisation committee members
I am not sure what channel that would be, the ISO committees
don't seem to be very open to the outside world.

Do you get also any useful information by Derek M. Jones occasionally? ;-)
http://www.knosof.co.uk/cbook/

Generally, if you look at the text for free that you are citing,
and compare it with the text about the threads in C11, you'll notice
a difference in quality. C11 certainly lacked some iterations
of discussion and error correction before it went into the standard.
In particular, a better coordination with the POSIX committee
would have been in order concerning threads.

I see also another update candidate if you compare descriptions for the
functions "pthread_cond_wait" and "cnd_wait".

http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_wait.html :
"...
When using condition variables there is always a Boolean predicate involving
shared variables associated with each condition wait that is true if the thread
should proceed. Spurious wakeups from the pthread_cond_timedwait() or
pthread_cond_wait() functions may occur.
Since the return from pthread_cond_timedwait() or pthread_cond_wait() does not
imply anything about the value of this predicate, the predicate should be
re-evaluated upon such return.
...."

How do you think about further clarification for the handling of "predicates"
and "spurious wakeups" by the current standard specification for the C
programming language?
Do you need not to care for them eventually because they are not mentioned in a
corresponding draft document?
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

Regards,
Markus
 
S

Shao Miller

I haven't studied C11's <threads.h> closely, but I do find the
description of mtx_destroy() a bit troubling:

Synopsis

1 #include <threads.h>
void mtx_destroy(mtx_t *mtx);

Description

2 The mtx_destroy function releases any resources used by the mutex
pointed to by mtx. No threads can be blocked waiting for the
mutex pointed to by mtx.

Returns

3 The mtx_destroy function returns no value.

So what does mtx_destroy() do if some thread *is* blocked waiting
for mtx? I suppose the behavior is undefined by omission, but
changing the word "can" to "shall" would have made that explicit.

And why not define the behavior, more or less as POSIX does?
Would detecting blocked threads be too difficult on some systems?

Maybe the function waits for such threads to unblock, before it releases
the resources. (Just kidding.)

- Shao Miller
 
S

Shao Miller

An enumeration type (without a tag or typedef) is an easy way to
achieve that. Adding a tag and/or typedef would create a type name
that's never actually used. Using that type for the parameters to
the relevant functions would not provide any type safety.

Other than IDEs which show the possible named enum values while you're
typing an argument or such.

- Shao Miller
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,077
Messages
2,570,567
Members
47,204
Latest member
abhinav72673

Latest Threads

Top