#include "hip-prv.h" #include #include 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; }