2011-10-08 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / libgo / runtime / go-send-small.c
blob25e3c82bd89e41b92d415980a89f41287b91b2b5
1 /* go-send-small.c -- send something 64 bits or smaller on a channel.
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. */
7 #include <stdint.h>
9 #include "go-assert.h"
10 #include "go-panic.h"
11 #include "channel.h"
13 /* Prepare to send something on a channel. FOR_SELECT is true if this
14 call is being made after a select statement returned with this
15 channel selected. */
17 void
18 __go_send_acquire (struct __go_channel *channel, _Bool for_select)
20 int i;
22 i = pthread_mutex_lock (&channel->lock);
23 __go_assert (i == 0);
25 while (1)
27 if (channel->is_closed)
29 if (for_select)
30 channel->selected_for_send = 0;
31 i = pthread_mutex_unlock (&channel->lock);
32 __go_assert (i == 0);
33 __go_panic_msg ("send on closed channel");
36 /* If somebody else has the channel locked for sending, we have
37 to wait. If FOR_SELECT is true, then we are the one with the
38 lock. */
39 if (!channel->selected_for_send || for_select)
41 if (channel->num_entries == 0)
43 /* This is a synchronous channel. If nobody else is
44 waiting to send, we grab the channel and tell the
45 caller to send the data. We will then wait for a
46 receiver. */
47 if (!channel->waiting_to_send)
49 __go_assert (channel->next_store == 0);
50 return;
53 else
55 /* If there is room on the channel, we are OK. */
56 if ((channel->next_store + 1) % channel->num_entries
57 != channel->next_fetch)
58 return;
62 /* Wait for something to change, then loop around and try
63 again. */
65 i = pthread_cond_wait (&channel->cond, &channel->lock);
66 __go_assert (i == 0);
70 /* Finished sending something on a channel. */
72 void
73 __go_send_release (struct __go_channel *channel)
75 int i;
77 if (channel->num_entries != 0)
79 /* This is a buffered channel. Bump the store count and signal
80 the condition variable. */
81 channel->next_store = (channel->next_store + 1) % channel->num_entries;
83 i = pthread_cond_signal (&channel->cond);
84 __go_assert (i == 0);
86 else
88 _Bool synched_with_select;
90 /* This is a synchronous channel. Indicate that we have a value
91 waiting. */
92 channel->next_store = 1;
93 channel->waiting_to_send = 1;
95 /* Tell everybody else to do something. This has to be a
96 broadcast because we might have both senders and receivers
97 waiting on the condition, but senders won't send another
98 signal. */
99 i = pthread_cond_broadcast (&channel->cond);
100 __go_assert (i == 0);
102 /* Wait until the value is received. */
103 synched_with_select = 0;
104 while (1)
106 if (channel->next_store == 0)
107 break;
109 /* If nobody is currently waiting to receive, try to synch
110 up with a select. */
111 if (!channel->waiting_to_receive && !synched_with_select)
113 if (__go_synch_with_select (channel, 1))
115 synched_with_select = 1;
116 __go_broadcast_to_select (channel);
117 continue;
121 i = pthread_cond_wait (&channel->cond, &channel->lock);
122 __go_assert (i == 0);
125 channel->waiting_to_send = 0;
127 /* Using the mutexes should implement a memory barrier. */
129 /* We have to signal again since we cleared the waiting_to_send
130 field. This has to be a broadcast because both senders and
131 receivers might be waiting, but only senders will be able to
132 act. */
133 i = pthread_cond_broadcast (&channel->cond);
134 __go_assert (i == 0);
137 channel->selected_for_send = 0;
139 __go_unlock_and_notify_selects (channel);
142 /* Send something 64 bits or smaller on a channel. */
144 void
145 __go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select)
147 if (channel == NULL)
149 // Block forever.
150 __go_select (0, 0, NULL, NULL);
153 __go_assert (channel->element_type->__size <= sizeof (uint64_t));
155 __go_send_acquire (channel, for_select);
157 channel->data[channel->next_store] = val;
159 __go_send_release (channel);