/*
 * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/bus.c,v 1.10 2004/04/30 13:41:56 aleigh Exp $ 
 */

/*
 * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved
 * 
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright
 * notice above does not evidence any actual or intended publication of such
 * source code.
 * 
 * Use, disclosure, copying, distribution, or transmission of this code without
 * express permission is prohibited.
 */

#include "mecha.h"

struct busSelem {
    long msg_type;
    /* unsigned int time; */
    void *data;
    size_t data_len;
    struct busSelem *next;
};
typedef struct busSelem busTelem;

struct busSbus {
    pthread_rwlock_t lock;
    struct busSelem *msgs;
    struct busSelem *last_msg;
    void (*destructor) (void *);
};

busTbus *busFinit(void (*destructor) (void *))
{
    busTbus *bus;

    bus = (busTbus *) malloc(sizeof(busTbus));
    assert(bus != NULL);

    memFclear(bus, sizeof(busTbus));

    bus->msgs = NULL;
    bus->last_msg = NULL;
    bus->destructor = destructor;

    if (pthread_rwlock_init(&bus->lock, NULL) == -1) {
        return NULL;
    }
    return bus;
}

void busFfree(busTbus * bus)
{
    busTelem *e, *np;

    assert(bus != NULL);

    pthread_rwlock_wrlock(&bus->lock);

    e = bus->msgs;

    while (1) {
        bus->destructor(e->data);
        np = e->next;
        free(e);
        if (np == NULL)
            break;
        e = np;
    }

    free(bus);
}

int busFpush(busTbus * bus, void *data, size_t data_len)
{
    busTelem *elem;

    assert(bus != NULL);
    assert(data != NULL);

    elem = (busTelem *) malloc(sizeof(busTelem));

    assert(elem != NULL);

    elem->data = data;
    elem->data_len = data_len;
    elem->next = NULL;

    if (pthread_rwlock_wrlock(&bus->lock) == -1)
        return -1;

    if (bus->last_msg == NULL) {
        bus->msgs = bus->last_msg = elem;
    } else {
        bus->last_msg->next = elem;
        bus->last_msg = elem;
    }

    pthread_rwlock_unlock(&bus->lock);

    return 0;
}

int busFpull(busTbus * bus, void **data)
{
    busTelem *e;
    size_t len;

    assert(bus != NULL);
    assert(data != NULL);

    if (pthread_rwlock_wrlock(&bus->lock) == -1)
        return -1;

    if (bus->msgs == NULL) {
        pthread_rwlock_unlock(&bus->lock);
        return 0;
    }
    e = bus->msgs;
    if (bus->last_msg == e) {
        bus->last_msg = bus->msgs = NULL;
    } else {
        bus->msgs = e->next;
    }

    pthread_rwlock_unlock(&bus->lock);

    *data = e->data;
    len = e->data_len;

    free(e);

    return len;
}
