Deadlock on WinCE

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Deadlock on WinCE

Breght Boschker
Hi,

taking a well-known example (the so-called 'producer-consumer'
problem) with a relatively small queue, we have observed a deadlock.
(See below for code) - the results we get:

Pthread test
request_queue_put: # of elements: 1
request_queue_put: # of elements: 2
request_queue_put: # of elements: 3
request_queue_put: # of elements: 4
request_queue_put: # of elements: 5
***********************************************
put: queue FULL. waiting for free space
***********************************************
request_queue_get: # of elements: 4
request_queue_get: # of elements: 3
request_queue_get: # of elements: 2
request_queue_get: # of elements: 1
request_queue_get: # of elements: 0
===============================================
get: queue EMPTY, waiting for data
===============================================
request_queue_put: # of elements: 1
request_queue_put: # of elements: 2
 request_queue_put: # of elements: 3
request_queue_put: # of elements: 4
request_queue_put: # of elements: 5
***********************************************
put: queue FULL. waiting for free space
***********************************************
request_queue_get: # of elements: 4
request_queue_get: # of elements: 3
request_queue_get: # of elements: 2
request_queue_get: # of elements: 1
request_queue_get: # of elements: 0
===============================================
get: queue EMPTY, waiting for data
===============================================

***** at this point, the program stops (the WinCE Remote Kernel
Tracker reports all threads of the application to be in 'blocked'
state). If the queue size is increased (say to 20 elements), the first
thread (the 'producer') completely fills the queue, *then* sends a
signal, the consumer thread is released from its pthread_cond_wait and
consumes a number of elements. After this, the two threads alternate
(put & get) and we have seen no deadlock so far.

Furthermore, the Remote Kernel Tracker shows that signals ('SetEvent')
are sent, but these do not result in the other thread becoming
unblocked. Also, we have noticed a lot of 'CreateEvent' calls during
the running period of one of either threads. Some background
information on our system:

Compiler: MS eMbedded Visual C++ 4.0 (SP4)
Target machine: ARMv4I / WinCE 5.00
PThread-WIN32 version: 2.7.0 (we had to put some defines around e.g.
<errno.h> in some files and in errno.c needed to put a typecast in
order to satisfy the compiler).

Any help/leads or ideas would be appreciated.


We use the following code:

#include <stdio.h>
#include "pthread.h"

#define QUEUESIZE 5
typedef struct rs { int type; } REQUEST_STRUCT;

typedef struct rq {
    int full;
    int empty;
    int head;
    int tail;
    int elt_count;
    pthread_mutex_t mut;
    pthread_cond_t not_full;
    pthread_cond_t not_empty;
    REQUEST_STRUCT buf[QUEUESIZE];
} REQUEST_QUEUE;


#include "windows.h"
void cenav_pthread_create(HANDLE a, HANDLE b) {}
void cenav_pthread_exit() { }

void *producer (void *args);
void *consumer (void *args);
extern REQUEST_QUEUE *request_queue_create (void);
extern void request_queue_delete (REQUEST_QUEUE *q);
extern void request_queue_put (REQUEST_QUEUE *q, REQUEST_STRUCT *rs);
extern void request_queue_get (REQUEST_QUEUE *q,  REQUEST_STRUCT *rs);


int request_test ()
{
    REQUEST_QUEUE *fifo;
    pthread_t pro, con;

    fifo = request_queue_create ();
    if (fifo ==  NULL) {
        fprintf (stderr, "main: Queue Init failed.\n");
        exit (1);
    }
    pthread_create (&pro, NULL, producer, fifo);
    pthread_create (&con, NULL, consumer, fifo);
    pthread_join (pro, NULL);
    pthread_join (con, NULL);
    request_queue_delete (fifo);

    return 0;
}

void *producer (void *q)
{
    REQUEST_QUEUE *fifo;
        REQUEST_STRUCT rs;
    int i;

    fifo = (REQUEST_QUEUE *)q;

    while (1)
    {
        request_queue_put (fifo, &rs);
    }
    return (NULL);
}

void *consumer (void *q)
{
    REQUEST_QUEUE *fifo;
        REQUEST_STRUCT rs;
    int i;

    fifo = (REQUEST_QUEUE *)q;

    while(1)
    {
        request_queue_get (fifo, &rs);
    }
    return (NULL);
}


extern REQUEST_QUEUE *request_queue_create (void)
{
    REQUEST_QUEUE *q;

    q = (REQUEST_QUEUE *)malloc (sizeof (REQUEST_QUEUE));
    if (q == NULL) return (NULL);

    q->empty = 1;
    q->full = 0;
    q->head = 0;
    q->tail = 0;

    q->mut       = PTHREAD_MUTEX_INITIALIZER;
    q->not_full  = PTHREAD_COND_INITIALIZER;
    q->not_empty = PTHREAD_COND_INITIALIZER;
    q->elt_count = 0;
    return (q);
}

extern void request_queue_delete (REQUEST_QUEUE *q)
{
    free (q);
}

extern void request_queue_put (REQUEST_QUEUE *q, REQUEST_STRUCT *rs)
{
     int result = 0;

    result = pthread_mutex_lock(&(q->mut));

    while (q->full) {
        printf ("put: queue FULL. waiting for free space\n");
        pthread_cond_wait(&q->not_full, &q->mut);
    }
    q->buf[q->tail] = *rs;
    q->tail++;
    if (q->tail == QUEUESIZE)
        q->tail = 0;
    if (q->tail == q->head)
        q->full = 1;
    q->empty = 0;
     q->elt_count++;

    printf("request_queue_put: # of elements: %d\n", q->elt_count);

    pthread_cond_signal(&q->not_empty);
    result = pthread_mutex_unlock(&(q->mut));
     return;
}

extern void request_queue_get (REQUEST_QUEUE *q,  REQUEST_STRUCT *rs)
{
    int result = 0;

    result = pthread_mutex_lock(&q->mut);

    while (q->empty) {
        printf ("get: queue EMPTY, waiting for data\n");
        pthread_cond_wait(&q->not_empty, &q->mut);
    }
    *rs = q->buf[q->head];

    q->head++;
    if (q->head == QUEUESIZE)
        q->head = 0;
    if (q->head == q->tail)
        q->empty = 1;
    q->full = 0;
    q->elt_count--;
    printf("request_queue_get: # of elements: %d\n", q->elt_count);

    pthread_cond_signal(&q->not_full);
    result = pthread_mutex_unlock(&(q->mut));
    return;
}

int main(int argc, char **argv)
{
    printf("Pthread test\n");
    request_test();
}

Thanks in advance,
   Breght Boschker