diff --git a/chan.c b/chan.c index 68f0e00..800cd0c 100644 --- a/chan.c +++ b/chan.c @@ -57,10 +57,13 @@ int hip_chan_send(hip_chan_t* c, const void* ptr, hip_oow_t len) hip = c->hip; caller = UCTX_FROM_LINK(hip->running); - if (c->unit_count < c->unit_capa) + if (HIP_LIST_IS_EMPTY(&c->recvq)) { - /* buffered */ hip_uint8_t* dptr; + + if (c->unit_count >= c->unit_capa) goto block; + + /* the buffer is not full. write to the buffer */ if (len > c->unit_size) len = c->unit_size; /* can't buffer longer than the specified unit size */ dptr = &c->buf[c->unit_wpos * c->unit_size]; memcpy(dptr, ptr, len); @@ -71,10 +74,16 @@ int hip_chan_send(hip_chan_t* c, const void* ptr, hip_oow_t len) } c->unit_wpos = (c->unit_wpos + 1) % c->unit_capa; c->unit_count++; + + /* give another routine a chance to read. + * does this cause too many context switches? + * without this, there is a high chance the the same routine + * starves the channel by reading and writing in succession + * if it read and write on the same channel */ + hip_yield(hip); return len; } - - if (!HIP_LIST_IS_EMPTY(&c->recvq)) /* there is a receving routine */ + else /* there is a receiving routing waiting */ { hip_uctx_link_t* x; hip_uctx_t* recver; @@ -95,6 +104,7 @@ int hip_chan_send(hip_chan_t* c, const void* ptr, hip_oow_t len) } +block: /* remember the data holder and places the current running routine in the send queue */ caller->chan_data_ptr = (hip_uint8_t*)ptr; caller->chan_data_len = len; @@ -115,16 +125,22 @@ int hip_chan_recv(hip_chan_t* c, void* ptr, hip_oow_t len) hip = c->hip; caller = UCTX_FROM_LINK(hip->running); - if (c->unit_count > 0) + if (HIP_LIST_IS_EMPTY(&c->sendq)) { + if (c->unit_count <= 0) goto block; + + /* the buffer is not empty. there's data to read */ if (len > c->unit_size) len = c->unit_size; memcpy(ptr, &c->buf[c->unit_rpos * c->unit_size], len); c->unit_rpos = (c->unit_rpos + 1) % c->unit_capa; c->unit_count--; + + /* In receiving, i doubt it causes starvation to not yield to another routine. + * let me not switch to the scheduler here for now. */ + /*hip_yield(hip);*/ return len; } - - if (!HIP_LIST_IS_EMPTY(&c->sendq)) /* there is a sending routine */ + else /* there is a sending routine */ { hip_uctx_link_t* x; hip_uctx_t* sener; @@ -145,6 +161,7 @@ int hip_chan_recv(hip_chan_t* c, void* ptr, hip_oow_t len) return len; } +block: /* remember the data holder and place the calling routine in the receive queue */ caller->chan_data_ptr = ptr; caller->chan_data_len = len; diff --git a/ctx.c b/ctx.c index 873ffe0..01cd5ba 100644 --- a/ctx.c +++ b/ctx.c @@ -828,7 +828,7 @@ int main() setbuf(stdout, NULL); hip = hip_open(HIP_FLAG_LAZY); - chan = hip_chan_open(hip, 100, 0); + chan = hip_chan_open(hip, 100, 1); hip_newrtn(hip, 0, uf1, chan); hip_newrtn(hip, 0, uf2, HIP_NULL);