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]

[patch] pthread_mutex asserts on s390(x)


Hi,

the attached testcase (reduced from one in libapr) frequently triggers the 
mutex->__data.__owner == 0 assert.  It turns out the problem are missing 
memory clobbers in the inline asm versions of atomic cmp-and-swap.  As 
they are also used to implement the low-level-locks they need to act as 
barrier.  With the patch the load is not reordered anymore and the 
testcase survices.


Ciao,
Michael.
-- 
	* sysdeps/s390/bits/atomic.h
	(__arch_compare_and_exchange_val_32_acq,
	 __arch_compare_and_exchange_val_64_acq): Add "memory" clobber.

Index: sysdeps/s390/bits/atomic.h
===================================================================
--- sysdeps/s390/bits/atomic.h.orig
+++ sysdeps/s390/bits/atomic.h
@@ -56,7 +56,7 @@ typedef uintmax_t uatomic_max_t;
      __typeof (*mem) __archold = (oldval);				      \
      __asm __volatile ("cs %0,%2,%1"					      \
 		       : "+d" (__archold), "=Q" (*__archmem)		      \
-		       : "d" (newval), "m" (*__archmem) : "cc" );	      \
+		       : "d" (newval), "m" (*__archmem) : "cc", "memory" );	      \
      __archold; })
 
 #ifdef __s390x__
@@ -65,7 +65,7 @@ typedef uintmax_t uatomic_max_t;
      __typeof (*mem) __archold = (oldval);				      \
      __asm __volatile ("csg %0,%2,%1"					      \
 		       : "+d" (__archold), "=Q" (*__archmem)		      \
-		       : "d" ((long) (newval)), "m" (*__archmem) : "cc" );    \
+		       : "d" ((long) (newval)), "m" (*__archmem) : "cc", "memory" );    \
      __archold; })
 #else
 /* For 31 bit we do not really need 64-bit compare-and-exchange. We can
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>


#define MAX_COUNTER 1000000
#define MAX_THREADS 6

static long mutex_counter;

static pthread_mutex_t thread_lock;
void * thread_mutex_func(void *data);
int test_thread_mutex(int num_threads);


void * thread_mutex_func(void *data)
{
    int i;

    for (i = 0; i < MAX_COUNTER; i++) {
        pthread_mutex_lock(&thread_lock);
        mutex_counter++;
        pthread_mutex_unlock(&thread_lock);
    }
    return NULL;
}

int test_thread_mutex_nested(int num_threads)
{
    pthread_t t[MAX_THREADS];
    int s[MAX_THREADS];
    time_t time_start, time_stop;
    int i, rv;

    mutex_counter = 0;

    printf("apr_thread_mutex_t Tests\n");
    printf("%-60s", "    Initializing the apr_thread_mutex_t (NESTED)");

        pthread_mutexattr_t mattr;

        rv = pthread_mutexattr_init(&mattr);
        if (rv) return rv;

        rv = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
        if (rv) {
            pthread_mutexattr_destroy(&mattr);
            return rv;
        }

        s[0] = pthread_mutex_init(&thread_lock, &mattr);

        pthread_mutexattr_destroy(&mattr);

    if (s[0] != 0) {
        printf("Failed!\n");
        return s[0];
    }
    printf("OK\n");

    pthread_mutex_lock(&thread_lock);
    printf("    Starting %d threads    ", num_threads); 
    for (i = 0; i < num_threads; ++i) {
        s[i] = pthread_create(&t[i], NULL, thread_mutex_func, NULL);
        if (s[i] != 0) {
            printf("Failed!\n");
            return s[i];
        }
    }
    printf("OK\n");

    time_start = time(NULL);
    pthread_mutex_unlock(&thread_lock);

    /* printf("%-60s", "    Waiting for threads to exit"); */
    for (i = 0; i < num_threads; ++i) {
        pthread_join(t[i], NULL);
    }
    /* printf("OK\n"); */

    time_stop = time(NULL);
    printf("seconds: %d usec\n",
           (int)(time_stop - time_start));
    if (mutex_counter != MAX_COUNTER * num_threads)
        printf("error: counter = %ld\n", mutex_counter);

    return 0;
}

int main(int argc, const char * const *argv)
{
    int rv;

        if ((rv = test_thread_mutex_nested(2)) != 0) {
            fprintf(stderr,"thread_mutex (NESTED) test failed\n");
            exit(-4);
        }
    return 0;
}

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