OSDN Git Service

runtime: Multiplex goroutines onto OS threads.
[pf3gnuchains/gcc-fork.git] / libgo / runtime / go-rec-nb-small.c
1 /* go-rec-nb-small.c -- nonblocking receive of something smal on a channel.
2
3    Copyright 2009 The Go Authors. All rights reserved.
4    Use of this source code is governed by a BSD-style
5    license that can be found in the LICENSE file.  */
6
7 #include <stdint.h>
8
9 #include "runtime.h"
10 #include "go-assert.h"
11 #include "go-panic.h"
12 #include "channel.h"
13
14 /* Prepare to receive something on a nonblocking channel.  */
15
16 int
17 __go_receive_nonblocking_acquire (struct __go_channel *channel)
18 {
19   int i;
20   _Bool has_data;
21
22   i = pthread_mutex_lock (&channel->lock);
23   __go_assert (i == 0);
24
25   while (channel->selected_for_receive)
26     runtime_cond_wait (&channel->cond, &channel->lock);
27
28   if (channel->is_closed
29       && (channel->num_entries == 0
30           ? channel->next_store == 0
31           : channel->next_fetch == channel->next_store))
32     {
33       __go_unlock_and_notify_selects (channel);
34       return RECEIVE_NONBLOCKING_ACQUIRE_CLOSED;
35     }
36
37   if (channel->num_entries > 0)
38     has_data = channel->next_fetch != channel->next_store;
39   else
40     {
41       if (channel->waiting_to_receive)
42         {
43           /* Some other goroutine is already waiting for data on this
44              channel, so we can't pick it up.  */
45           has_data = 0;
46         }
47       else if (channel->next_store > 0)
48         {
49           /* There is data on the channel.  */
50           has_data = 1;
51         }
52       else if (__go_synch_with_select (channel, 0))
53         {
54           /* We synched up with a select sending data, so there will
55              be data for us shortly.  Tell the select to go, and then
56              wait for the data.  */
57           __go_broadcast_to_select (channel);
58
59           while (channel->next_store == 0)
60             runtime_cond_wait (&channel->cond, &channel->lock);
61
62           has_data = 1;
63         }
64       else
65         {
66           /* Otherwise there is no data.  */
67           has_data = 0;
68         }
69
70       if (has_data)
71         {
72           channel->waiting_to_receive = 1;
73           __go_assert (channel->next_store == 1);
74         }
75     }
76
77   if (!has_data)
78     {
79       i = pthread_mutex_unlock (&channel->lock);
80       __go_assert (i == 0);
81       return RECEIVE_NONBLOCKING_ACQUIRE_NODATA;
82     }
83
84   return RECEIVE_NONBLOCKING_ACQUIRE_DATA;
85 }
86
87 /* Receive something 64 bits or smaller on a nonblocking channel.  */
88
89 struct __go_receive_nonblocking_small
90 __go_receive_nonblocking_small (struct __go_channel *channel)
91 {
92   uintptr_t element_size;
93   struct __go_receive_nonblocking_small ret;
94
95   if (channel == NULL)
96     {
97       ret.__val = 0;
98       ret.__success = 0;
99       ret.__closed = 0;
100       return ret;
101     }
102
103   element_size = channel->element_type->__size;
104   __go_assert (element_size <= sizeof (uint64_t));
105
106   int data = __go_receive_nonblocking_acquire (channel);
107   if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA)
108     {
109       ret.__val = 0;
110       ret.__success = 0;
111       ret.__closed = data == RECEIVE_NONBLOCKING_ACQUIRE_CLOSED;
112       return ret;
113     }
114
115   ret.__val = channel->data[channel->next_fetch];
116
117   __go_receive_release (channel);
118
119   ret.__success = 1;
120   ret.__closed = 0;
121
122   return ret;
123 }