From: Noob on
[ Cross-posted to c.p.t and c.u.p ]

Hello,

I'm using a proprietary library (no source code) which requires the user
to provide 4 mutex-related functions (create, delete, lock, unlock).

AFAICT, if I were using a POSIX OS, I could make trivial wrappers around

pthread_mutex_init
pthread_mutex_destroy
pthread_mutex_lock
pthread_mutex_unlock

But this library has specific requirements for the delete function:

If delete is called on a locked mutex, the function must return an error
code to signal the error to the function's caller.

However, the documentation for pthread_mutex_destroy explicitly states:
http://www.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_init.html

"""
It shall be safe to destroy an initialized mutex that is unlocked.
Attempting to destroy a locked mutex results in undefined behavior.
"""

This means that my delete function can't just call pthread_mutex_destroy
because I would invoke UB if the mutex is locked, and I wouldn't be able
to return the requested error code, right?

So... Does this mean I have to keep track whether the mutex is locked?
(It would appear so.)

Or perhaps I could mess with the OS code? (shudder)

I'd like to tell the library author that it is unreasonable to impose
overhead on every lock and unlock operation just to catch an obvious (?)
programming error on delete. What do you think?

N.B. the library requires mutex with recursive semantic.

Regards.
From: David Schwartz on
On Oct 28, 6:27 am, Noob <r...(a)127.0.0.1> wrote:

> But this library has specific requirements for the delete function:
>
> If delete is called on a locked mutex, the function must return an error
> code to signal the error to the function's caller.

That is, IMO, fundamentally busted behavior, unless it only means
locked by the calling thread.

> This means that my delete function can't just call pthread_mutex_destroy
> because I would invoke UB if the mutex is locked, and I wouldn't be able
> to return the requested error code, right?
>
> So... Does this mean I have to keep track whether the mutex is locked?
> (It would appear so.)
> Or perhaps I could mess with the OS code? (shudder)
>
> I'd like to tell the library author that it is unreasonable to impose
> overhead on every lock and unlock operation just to catch an obvious (?)
> programming error on delete. What do you think?
>
> N.B. the library requires mutex with recursive semantic.

Since the mutex is recursive, one of two things are the case:

1) The requirement only applies if the calling thread holds the lock
on the mutex, in which case you have to keep track of the lock count
anyway. (Otherwise, how would you know what to do in the unlock
operation?) The library is being reasonable, though quirky.

2) The requirement applies even if another thread holds the mutex.
This is a real pain to implement, and the requirement is fundamentally
busted.

DS
From: Noob on
David Schwartz wrote:

> Noob wrote:
>
>> But this library has specific requirements for the delete function:
>>
>> If delete is called on a locked mutex, the function must return an error
>> code to signal the error to the function's caller.
>
> That is, IMO, fundamentally busted behavior, unless it only means
> locked by the calling thread.

Could you expand on /why/ you think it is busted behavior?
(I need ammo to try to convince the library authors.)

The exact requirements are:

1) Return an error when attempting to delete "a mutex currently owned by
another thread".
2) Return an error when attempting to delete "a mutex currently owned by
the calling thread".

NB: by "owned" I assume they mean "locked".

Since a locked mutex is so either by the calling thread, or by another
thread (duh!) it seems the two requirements boil down to:

Return an error (and, I assume, leave the mutex alone) when attempting
to delete a locked mutex.

>> This means that my delete function can't just call pthread_mutex_destroy
>> because I would invoke UB if the mutex is locked, and I wouldn't be able
>> to return the requested error code, right?
>>
>> So... Does this mean I have to keep track whether the mutex is locked?
>> (It would appear so.)
>> Or perhaps I could mess with the OS code? (shudder)
>>
>> I'd like to tell the library author that it is unreasonable to impose
>> overhead on every lock and unlock operation just to catch an obvious (?)
>> programming error on delete. What do you think?
>>
>> N.B. the library requires mutex with recursive semantic.
>
> Since the mutex is recursive, one of two things are the case:
>
> 1) The requirement only applies if the calling thread holds the lock
> on the mutex, in which case you have to keep track of the lock count
> anyway. (Otherwise, how would you know what to do in the unlock
> operation?) The library is being reasonable, though quirky.

The OS I'm using provides recursive mutex. Therefore, I don't think I
have to deal with lock counts, as the OS takes care of that.

Unless I need to know in delete whether the mutex is locked.

Trying to delete a locked mutex sounds like a serious programmer error.

Mutex destruction (and creation) should be done in well-defined parts of
the application, when one can be sure the mutex is not in use anymore,
right?

> 2) The requirement applies even if another thread holds the mutex.
> This is a real pain to implement, and the requirement is fundamentally
> busted.

According to the library's spec, delete may be called at any time, by
any thread, and it is the user's responsibility to return an error and
leave the mutex untouched if the mutex is currently locked...

Regards.
From: Eric Sosman on
Noob wrote:
> David Schwartz wrote:
>
>> Noob wrote:
>>
>>> But this library has specific requirements for the delete function:
>>>
>>> If delete is called on a locked mutex, the function must return an error
>>> code to signal the error to the function's caller.
>> That is, IMO, fundamentally busted behavior, unless it only means
>> locked by the calling thread.
>
> Could you expand on /why/ you think it is busted behavior?
> (I need ammo to try to convince the library authors.)
>
> The exact requirements are:
>
> 1) Return an error when attempting to delete "a mutex currently owned by
> another thread".

This is broken, period. Suppose thread T1 tries to delete the
mutex and discovers (somehow) that it is locked by T2. T1 leaves
the mutex alone, the deletion attempt returns an error, and all is
well.

But suppose T1 comes along at a moment when the mutex is unlocked,
and succeeds in deleting it. Two clock cycles later, T2 tries to lock
the destroyed mutex, and the fertilizer hits the fan. The fact that T1
found the mutex unlocked is no proof that the mutex is "unused," or
that T2 might not attempt to use it again.

If T1 deletes a mutex that T2 might still want to use, the
application is broken. If T1 can find the mutex locked by T2, it
must be the case that T2 still wants to use it. Therefore the mere
possibility that delete-while-locked-elsewhere could occur is proof
that the design is broken.

> 2) Return an error when attempting to delete "a mutex currently owned by
> the calling thread".

This isn't quite as clear-cut, but it still seems dubious.

> [...]
> Trying to delete a locked mutex sounds like a serious programmer error.

Yes, but the point is more general: Trying to delete an "in use"
mutex is a serious programmer error. A mutex in the locked state is
obviously in use, but it is a mistake to reason that a mutex in the
unlocked state is not in use.

> According to the library's spec, delete may be called at any time, by
> any thread, and it is the user's responsibility to return an error and
> leave the mutex untouched if the mutex is currently locked...

Broken. The danger isn't when deletion fails because the mutex is
locked, but when deletion succeeds because the mutex is unlocked -- but
is still in use.

--
Eric.Sosman(a)sun.com
From: Måns Rullgård on
David Schwartz <davids(a)webmaster.com> writes:

> On Oct 28, 6:27�am, Noob <r...(a)127.0.0.1> wrote:
>
>> But this library has specific requirements for the delete function:
>>
>> If delete is called on a locked mutex, the function must return an error
>> code to signal the error to the function's caller.
>
> That is, IMO, fundamentally busted behavior, unless it only means
> locked by the calling thread.

I agree. I wouldn't go anywhere near that library. Find another one
written by someone with half a brain.

That said, you could use pthread_mutex_trylock() to find out whether
or not the muxtex is locked.

--
M�ns Rullg�rd
mans(a)mansr.com