Gilles Chanteperdrix wrote:
> Jan Kiszka wrote:
...
>> I think I'm getting closer to the issue. Our actual problem comes from
>> the fact that the xnsynch_owner is easily out of sync with the real
>> owner, it even sometimes points to a former owner:
>>
>> Thread A releases a mutex on which thread B pends. It wakes up B,
>> causing it to become the new xnsynch owner, and clears the claimed bit
>> as there are no further sleepers. B returns, and when it wants to
>> release the mutex, it does this happily in user space because claimed is
>> not set. Now the fast lock variable is 'unlocked', while xnsynch still
>> reports B being the owner. This is no problem as the next time two
>> threads fight over this lock the waiter will simply overwrite the
>> xnsynch_owner before it falls asleep. But this "trick" doesn't work for
>> waiters that have been robbed. They will spin inside xnsynch_sleep_on
>> and stumble over this inconsistency.
>>
>> I have two approaches in mind now: First one is something like
>> XNSYNCH_STEALNOINFORM, i.e. causing xnsynch_sleep_on to not set XNROBBED
>> so that the robbed thread spins one level higher in the skin code -
>> which would have to be extended a bit.
> 
> No, the stealing is the xnsynch job.
> 
>> Option two is to clear xnsynch_owner once a new owner is about to return
>> from kernel with the lock held while there are no more xnsynch_sleepers.
>> That should work with even less changes and save us one syscall in the
>> robbed case. Need to think about it more, though.
> 
> In fact the only time when the owner is required to be in sync is when
> PIP occurs, and this is guaranteed to work, because when PIP is needed a
> syscall is emitted anyway. To the extent that xnsynch does not even
> track the owner on non PIP synch (which is why the posix skin originally
>  forcibly set the synch owner, and it was simply kept to get the fastsem
> stuff working).
> 
> Ok. And what about the idea of the xnsynch bit to tell him "hey, the
> owner is tracked in the upper layer, go there to find it".

I'm yet having difficulties to imagine how this should look like when
it's implemented. Would it be simpler than my second idea?

Anyway, here is a patch (on top of my handle-based lock series) for the
approach that clears xnsynch_owner when there are no waiters. At least
it causes no regression based on your test, but I haven't checked lock
stealing yet. In theory, everything still appears to be fine to me. This
approach basically restores the state we find when some thread just
acquired the lock in user space.

Jan

---
 ksrc/skins/posix/mutex.c |   10 +++++++---
 ksrc/skins/posix/mutex.h |   17 +++++++++++------
 2 files changed, 18 insertions(+), 9 deletions(-)

Index: b/ksrc/skins/posix/mutex.c
===================================================================
--- a/ksrc/skins/posix/mutex.c
+++ b/ksrc/skins/posix/mutex.c
@@ -117,7 +117,6 @@ int pse51_mutex_init_internal(struct __s
        mutex->attr = *attr;
        mutex->owner = ownerp;
        mutex->owningq = kq;
-       mutex->sleepers = 0;
        xnarch_atomic_set(ownerp, XN_NO_HANDLE);
 
        xnlock_get_irqsave(&nklock, s);
@@ -305,14 +304,12 @@ int pse51_mutex_timedlock_break(struct _
                /* Attempting to relock a normal mutex, deadlock. */
                xnlock_get_irqsave(&nklock, s);
                for (;;) {
-                       ++mutex->sleepers;
                        if (timed)
                                xnsynch_sleep_on(&mutex->synchbase,
                                                 abs_to, XN_REALTIME);
                        else
                                xnsynch_sleep_on(&mutex->synchbase,
                                                 XN_INFINITE, XN_RELATIVE);
-                       --mutex->sleepers;
 
                        if (xnthread_test_info(cur, XNBREAK)) {
                                err = -EINTR;
@@ -329,6 +326,13 @@ int pse51_mutex_timedlock_break(struct _
                                break;
                        }
                }
+               if (!xnsynch_nsleepers(&mutex->synchbase)) {
+                       xnarch_atomic_set
+                               (mutex->owner,
+                                clear_claimed
+                                       (xnarch_atomic_get(mutex->owner)));
+                       xnsynch_set_owner(&mutex->synchbase, NULL);
+               }
                xnlock_put_irqrestore(&nklock, s);
 
                break;
Index: b/ksrc/skins/posix/mutex.h
===================================================================
--- a/ksrc/skins/posix/mutex.h
+++ b/ksrc/skins/posix/mutex.h
@@ -57,7 +57,6 @@ typedef struct pse51_mutex {
 
        xnarch_atomic_t *owner;
        pthread_mutexattr_t attr;
-       unsigned sleepers;
        pse51_kqueues_t *owningq;
 } pse51_mutex_t;
 
@@ -172,12 +171,10 @@ static inline int pse51_mutex_timedlock_
        }
 
        xnsynch_set_owner(&mutex->synchbase, owner);
-       ++mutex->sleepers;
        if (timed)
                xnsynch_sleep_on(&mutex->synchbase, abs_to, XN_REALTIME);
        else
                xnsynch_sleep_on(&mutex->synchbase, XN_INFINITE, XN_RELATIVE);
-       --mutex->sleepers;
 
        if (xnthread_test_info(cur, XNBREAK)) {
                err = -EINTR;
@@ -192,7 +189,11 @@ static inline int pse51_mutex_timedlock_
                goto error;
        }
 
-       ownerh = set_claimed(xnthread_handle(cur), mutex->sleepers);
+       ownerh = xnthread_handle(cur);
+       if (xnsynch_nsleepers(&mutex->synchbase))
+               ownerh = set_claimed(ownerh, 1);
+       else
+               xnsynch_set_owner(&mutex->synchbase, NULL);
        xnarch_atomic_set(mutex->owner, ownerh);
        shadow->lockcnt = count;
        xnlock_put_irqrestore(&nklock, s);
@@ -200,10 +201,12 @@ static inline int pse51_mutex_timedlock_
        return 0;
 
   error:
-       if (!mutex->sleepers)
+       if (!xnsynch_nsleepers(&mutex->synchbase)) {
                xnarch_atomic_set
                        (mutex->owner,
                         clear_claimed(xnarch_atomic_get(mutex->owner)));
+               xnsynch_set_owner(&mutex->synchbase, NULL);
+       }
        xnlock_put_irqrestore(&nklock, s);
        return err;
 }
@@ -221,7 +224,9 @@ static inline void pse51_mutex_unlock_in
 
        xnlock_get_irqsave(&nklock, s);
        owner = xnsynch_wakeup_one_sleeper(&mutex->synchbase);
-       ownerh = set_claimed(xnthread_handle(owner), mutex->sleepers);
+       ownerh =
+           set_claimed(xnthread_handle(owner),
+                       xnsynch_nsleepers(&mutex->synchbase));
        xnarch_atomic_set(mutex->owner, ownerh);
        if (owner)
                xnpod_schedule();

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core

Reply via email to