hip/chan.c

130 lines
3.1 KiB
C
Raw Normal View History

#include "hip-prv.h"
#include <stdlib.h>
#include <string.h>
struct hip_chan_t
{
hip_t* hip;
int closed;
hip_oow_t unit_size;
hip_oow_t buf_size;
hip_uint8_t* buf;
hip_uint8_t* endptr;
hip_uint8_t* readptr;
hip_uint8_t* writeptr;
hip_uctx_link_t sendq; // list of senders waiting on this channel
hip_uctx_link_t recvq; // list of receivers waiting on this channel
};
hip_chan_t* hip_chan_open(hip_t* hip, hip_oow_t buf_size)
{
hip_chan_t* c;
c = (hip_chan_t*)malloc(HIP_SIZEOF(*c) + buf_size);
if (HIP_UNLIKELY(!c)) return HIP_NULL;
memset(c, 0, HIP_SIZEOF(*c));
c->hip = hip;
c->closed = 0;
c->buf_size = buf_size;
c->buf = (hip_uint8_t*)(c + 1);
c->endptr = 0;
c->readptr = 0;
c->writeptr = 0;
HIP_LIST_INIT(&c->recvq);
HIP_LIST_INIT(&c->sendq);
return c;
}
void hip_chan_close(hip_chan_t* c)
{
free(c);
}
int hip_chan_send(hip_chan_t* c, const void* ptr, hip_oow_t len)
{
hip_uctx_t* self;
int ret;
self = UCTX_FROM_LINK(c->hip->running);
// TODO: IS BUFFER EMPTY
if (!HIP_LIST_IS_EMPTY(&c->recvq)) /* there is a receving routine */
{
hip_uctx_link_t* x;
hip_uctx_t* xx;
/* remove the receiving routine from the queue and make it runnable */
x = HIP_LIST_HEAD(&c->recvq);
HIP_LIST_UNCHAIN(x);
HIP_LIST_ADD_BACK(x, &c->hip->runnables);
xx = UCTX_FROM_LINK(x);
if (len > xx->chan_data_len) len = xx->chan_data_len;
memcpy(xx->chan_data_ptr, ptr, len);
*(xx->chan_ret_ptr) = len; /* manipulate the return value of the receiver */
hip_yield(c->hip); /* let other routines go first */
return len;
}
/* remember the data holder and places the current running routine in the send queue */
self->chan_data_ptr = (hip_uint8_t*)ptr;
self->chan_data_len = len;
self->chan_ret_ptr = &ret; /* remember the pointer to the return value holder to be set by the receiver */
HIP_LIST_ADD_BACK(c->hip->running, &c->sendq);
hip_switch(c->hip);
return ret;
}
int hip_chan_recv(hip_chan_t* c, void* ptr, hip_oow_t len)
{
hip_uctx_t* self;
int ret;
self = UCTX_FROM_LINK(c->hip->running);
/* TODO: IS THERE DATA IN BUFFER ? */
if (!HIP_LIST_IS_EMPTY(&c->sendq)) /* there is a sending routine */
{
hip_uctx_link_t* x;
hip_uctx_t* xx;
/* remove the sending routine from the queue and make it runnable */
x = HIP_LIST_HEAD(&c->sendq);
HIP_LIST_UNCHAIN(x);
HIP_LIST_ADD_BACK(x, &c->hip->runnables);
xx = UCTX_FROM_LINK(x);
/* copy the data from the sending routine's buffer */
if (len > xx->chan_data_len) len = xx->chan_data_len; /* TODO: do something else instead of simple truncation */
memcpy(ptr, xx->chan_data_ptr, len);
*(xx->chan_data_ptr) = len; /* manipulate the return value of the sender */
hip_yield(c->hip); /* let other routines go first */
return len;
}
/* remember the data holder and place the calling routine in the receive queue */
self->chan_data_ptr = ptr;
self->chan_data_len = len;
self->chan_ret_ptr = &ret; /* remember the pointer to the return value holder to be set by the sender */
HIP_LIST_ADD_BACK(c->hip->running, &c->recvq);
hip_switch(c->hip); /* switch to the scheduler */
return ret;
}