lkml.org 
[lkml]   [1996]   [Dec]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectPROBLEM --> Atomic operations in mmap attached address space...


    Hi,

    I am having some trouble with atomic operations in "mmap" mapped
    address space... These work fine when the same memory is mapped with "shmat"
    !!!

    Here is the test code I am using in a Linux SMP Machine with
    2.0.27... What it does is to launch several processes that try to increment
    a shared counter a certain number of times.
    It shoud be compiled with

    gcc -O -o lock_test lock_test.c

    Before using it you should create with dd 2 1k files in the same directory
    named ./foo and ./pid_t

    The program usage is : lock_test mmap|shm <n_workers> <number>

    When used with the "shm" option everything works fine..
    When used with the "mmap" option the atomic operations do not work the
    way they should !! 8-(...

    Try it with big numbers... Otherwise the bug will not show up !!!
    ex) ./lock mmap 5 100000

    I expect you to see lost count and deadlocks with mmap and no
    problems with shm !!

    I would like to know if anyone else is getting this same results and if
    by any chance there is a patch that solves this mmap problem...
    If someone is already working in this problem I would like to
    volunteer to receive patches and do some beta testing...

    Thanks,

    mcc

    Here is the code :

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>


    /*
    * Some hacks to defeat gcc over-optimizations.. Based in Kernel code !!
    */
    #define ADDR (*(struct __dummy *) addr)
    struct __dummy { unsigned long a[100]; };

    typedef volatile int slock_t;


    extern inline int set_bit(int nr, volatile void * addr)
    {
    int oldbit;

    asm volatile ("
    lock ;
    btsl %2,%1\n\tsbbl %0,%0"
    :"=r" (oldbit),"=m" (ADDR)
    :"ir" (nr));
    return oldbit;
    }


    extern inline int clear_bit(int nr, volatile void * addr)
    {
    int oldbit;

    asm volatile("
    lock ;
    btrl %2,%1\n\tsbbl %0,%0"
    :"=r" (oldbit),"=m" (ADDR)
    :"ir" (nr));
    return oldbit;
    }

    #define S_LOCK(p)\
    {\
    while(set_bit(0,(p)) ) ;\
    }

    #define S_UNLOCK(p) (clear_bit(0,(p)))

    #define S_CLOCK(p) (!set_bit(0,(p)))

    #define S_INIT_LOCK(p) S_UNLOCK(p)

    #define ATOMIC_INCR(addr) \
    { \
    asm volatile("/* inlined atomic_incr */
    lock
    incl %0" \
    : \
    : "rm" (*(addr))); \
    }

    #define LOCK(X) S_LOCK(&(X))
    #define UNLOCK(X) S_UNLOCK(&(X))
    #define INIT_LOCK(X) S_INIT_LOCK(&(X))
    #define COND_LOCK(X) S_CLOCK(&(X))

    #define SHM 1
    #define MMAP 2

    int shared_mem = MMAP;

    typedef struct {
    int last_worker;
    slock_t lock;
    volatile long counter;
    volatile int n_workers;
    } COUNTER;


    long n_times;

    pid_t *worker_pid;

    work(int worker, COUNTER *c)
    {
    int i;

    if( worker > 0 )
    {
    if( fork() )
    {
    return;
    }
    else
    if( worker_pid[worker] == -1 )
    {
    printf("Could not initiate worker[%d]", worker );
    perror("");
    }
    }

    worker_pid[worker] = getpid();

    printf("Worker[pid=%-4d,n=%-4d] started\n", worker_pid[worker],worker);
    fflush(stdout);

    for( i = 0 ; i < n_times; i++ )
    {

    #ifdef ATOMIC

    ATOMIC_INCR(&(c->counter));
    #else
    LOCK(c->lock);

    #ifdef MCC_DEBUG
    if( worker != c->last_worker && c->last_worker != -1 )
    {
    fprintf(stderr,"worker[pid=%-4d,n=%-2d] grabbed lock from worker[pid=%-4d,n=%-2d]\t",
    worker_pid[worker], worker,
    worker_pid[c->last_worker],
    c->last_worker );
    fprintf(stderr,"counter=%d\n", c->counter );
    fflush(stdout);
    }

    c->last_worker = worker;
    #endif
    c->counter ++;

    UNLOCK(c->lock);
    #endif

    }

    printf("Worker[%d] ended\n", worker);
    fflush(stdout);


    LOCK(c->lock);
    --c->n_workers;
    UNLOCK(c->lock);

    printf("Worker[%d] exiting with counter=%d\n", worker, c->counter );


    if( worker != 0 ) exit(0);

    }


    main(int argc, char *argv[])
    {
    COUNTER *counter;
    int n_workers,i;
    int fd_counter, fd_pid;
    char *c;

    int shmid;

    umask(077);

    if( argc < 3 )
    {
    printf("Usage : %s mmap|shm <n_workers> <number>\n", *argv );
    exit(1);
    }
    else c = argv[1];



    if( strcmp(c,"mmap" ) == 0 )
    shared_mem = MMAP;
    else if( strcmp(c,"shm") == 0 )
    shared_mem = SHM;
    else
    {
    printf("Usage : %s -mmap|shm <n_workers> <number>\n", *argv );
    exit(1);
    }

    if( shared_mem == MMAP )
    {

    printf("Using BSD mmap\n");
    fflush(stdout);

    if( (fd_counter = open("./foo", O_RDWR, 0700 )) == -1 )
    {
    perror("Could not open ./foo\n");
    exit(3);
    }

    if( (long) ( counter = (COUNTER *)
    mmap( 0, sizeof(COUNTER),
    PROT_READ | PROT_WRITE, MAP_SHARED ,
    fd_counter , 0 ) ) == -1 )
    {

    perror("Allocation of shared memory failed");
    exit(2);
    }
    }
    else
    {
    printf("Using SYSV SHM \n");
    fflush(stdout);

    if( ( shmid = shmget(IPC_PRIVATE, sizeof(COUNTER), 0600)) == -1 )
    {
    perror("shmget failed :");
    exit(1);
    }

    if( ( counter = (COUNTER *) shmat(shmid,0,0) ) == (void *) -1 )
    {
    perror("shmat failed");
    }
    }

    printf("\nCounter allocated at %lx\n\n", (long) counter );
    fflush(stdout);

    n_workers = atoi(argv[2]);

    if( (fd_pid = open("./pid_t", O_RDWR, 0700 )) == -1 )
    {
    perror("Could not open ./pid_t\n");
    exit(3);
    }
    if( ( worker_pid = (pid_t *) mmap( 0,sizeof(pid_t) * n_workers, PROT_READ | PROT_WRITE, MAP_SHARED, fd_pid , 0 ) ) == (pid_t *) -1 )
    {
    printf("Could not allocate pid_t space, Aborting --> ");
    perror(NULL);
    }

    worker_pid[0] = getpid();
    n_times = atoi(argv[3]);

    INIT_LOCK(counter->lock);
    counter -> counter = 0;
    counter -> last_worker = -1;
    counter -> n_workers = n_workers;

    for( i = 1 ; i < n_workers ; i++ ) work(i, counter );

    work(0, counter);


    while( counter->n_workers ) ; /* Wait for everyone to finish */


    puts("\n\n");

    for( i = 1 ; i < n_workers ; i++ )
    {
    printf("Going to wait for process %d to finish\n", worker_pid[i]);
    waitpid(worker_pid[i], NULL, 0 );
    printf("Worker[%d] finished\n", i );
    }

    puts("Worker[0] finished\n");


    printf("\n\n -----> %d * %d == %d <----- \n\n", n_workers, n_times , counter -> counter );


    if( shared_mem == SHM )
    {
    shmdt((void *)counter);
    shmctl(shmid,IPC_RMID,NULL);
    }


    }

    \
     
     \ /
      Last update: 2005-03-22 13:38    [W:4.331 / U:29.240 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site