diff options
Diffstat (limited to 'libgo/runtime/go-rec-nb-small.c')
-rw-r--r-- | libgo/runtime/go-rec-nb-small.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/libgo/runtime/go-rec-nb-small.c b/libgo/runtime/go-rec-nb-small.c new file mode 100644 index 00000000000..9983d34644d --- /dev/null +++ b/libgo/runtime/go-rec-nb-small.c @@ -0,0 +1,127 @@ +/* go-rec-nb-small.c -- nonblocking receive of something smal on a channel. + + Copyright 2009 The Go Authors. All rights reserved. + Use of this source code is governed by a BSD-style + license that can be found in the LICENSE file. */ + +#include <stdint.h> + +#include "go-assert.h" +#include "go-panic.h" +#include "channel.h" + +/* Prepare to receive something on a nonblocking channel. */ + +int +__go_receive_nonblocking_acquire (struct __go_channel *channel) +{ + int i; + _Bool has_data; + + i = pthread_mutex_lock (&channel->lock); + __go_assert (i == 0); + + while (channel->selected_for_receive) + { + i = pthread_cond_wait (&channel->cond, &channel->lock); + __go_assert (i == 0); + } + + if (channel->is_closed + && (channel->num_entries == 0 + ? channel->next_store == 0 + : channel->next_fetch == channel->next_store)) + { + if (channel->saw_close) + { + ++channel->closed_op_count; + if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS) + { + i = pthread_mutex_unlock (&channel->lock); + __go_assert (i == 0); + __go_panic_msg ("too many operations on closed channel"); + } + } + channel->saw_close = 1; + __go_unlock_and_notify_selects (channel); + return RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; + } + + if (channel->num_entries > 0) + has_data = channel->next_fetch != channel->next_store; + else + { + if (channel->waiting_to_receive) + { + /* Some other goroutine is already waiting for data on this + channel, so we can't pick it up. */ + has_data = 0; + } + else if (channel->next_store > 0) + { + /* There is data on the channel. */ + has_data = 1; + } + else if (__go_synch_with_select (channel, 0)) + { + /* We synched up with a select sending data, so there will + be data for us shortly. Tell the select to go, and then + wait for the data. */ + __go_broadcast_to_select (channel); + + while (channel->next_store == 0) + { + i = pthread_cond_wait (&channel->cond, &channel->lock); + __go_assert (i == 0); + } + + has_data = 1; + } + else + { + /* Otherwise there is no data. */ + has_data = 0; + } + + if (has_data) + { + channel->waiting_to_receive = 1; + __go_assert (channel->next_store == 1); + } + } + + if (!has_data) + { + i = pthread_mutex_unlock (&channel->lock); + __go_assert (i == 0); + return RECEIVE_NONBLOCKING_ACQUIRE_NODATA; + } + + return RECEIVE_NONBLOCKING_ACQUIRE_DATA; +} + +/* Receive something 64 bits or smaller on a nonblocking channel. */ + +struct __go_receive_nonblocking_small +__go_receive_nonblocking_small (struct __go_channel *channel) +{ + struct __go_receive_nonblocking_small ret; + + __go_assert (channel->element_size <= sizeof (uint64_t)); + + int data = __go_receive_nonblocking_acquire (channel); + if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA) + { + ret.__val = 0; + ret.__success = data == RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; + return ret; + } + + ret.__val = channel->data[channel->next_fetch]; + + __go_receive_release (channel); + + ret.__success = 1; + + return ret; +} |