Merge from mainline (167278:168000).
[official-gcc/graphite-test-results.git] / libgo / runtime / go-send-small.c
blob506c90e648d099ca44003c7d15b435cf122a6af3
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. Return true if the channel
14 is acquired, false, if it is closed. FOR_SELECT is true if this
15 call is being made after a select statement returned with this
16 channel selected. */
18 _Bool
19 __go_send_acquire (struct __go_channel *channel, _Bool for_select)
21 int i;
23 i = pthread_mutex_lock (&channel->lock);
24 __go_assert (i == 0);
26 while (1)
28 /* Check whether the channel is closed. */
29 if (channel->is_closed)
31 ++channel->closed_op_count;
32 if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
34 i = pthread_mutex_unlock (&channel->lock);
35 __go_assert (i == 0);
36 __go_panic_msg ("too many operations on closed channel");
38 channel->selected_for_send = 0;
39 __go_unlock_and_notify_selects (channel);
40 return 0;
43 /* If somebody else has the channel locked for sending, we have
44 to wait. If FOR_SELECT is true, then we are the one with the
45 lock. */
46 if (!channel->selected_for_send || for_select)
48 if (channel->num_entries == 0)
50 /* This is a synchronous channel. If nobody else is
51 waiting to send, we grab the channel and tell the
52 caller to send the data. We will then wait for a
53 receiver. */
54 if (!channel->waiting_to_send)
56 __go_assert (channel->next_store == 0);
57 return 1;
60 else
62 /* If there is room on the channel, we are OK. */
63 if ((channel->next_store + 1) % channel->num_entries
64 != channel->next_fetch)
65 return 1;
69 /* Wait for something to change, then loop around and try
70 again. */
72 i = pthread_cond_wait (&channel->cond, &channel->lock);
73 __go_assert (i == 0);
77 /* Finished sending something on a channel. */
79 void
80 __go_send_release (struct __go_channel *channel)
82 int i;
84 if (channel->num_entries != 0)
86 /* This is a buffered channel. Bump the store count and signal
87 the condition variable. */
88 channel->next_store = (channel->next_store + 1) % channel->num_entries;
90 i = pthread_cond_signal (&channel->cond);
91 __go_assert (i == 0);
93 else
95 _Bool synched_with_select;
97 /* This is a synchronous channel. Indicate that we have a value
98 waiting. */
99 channel->next_store = 1;
100 channel->waiting_to_send = 1;
102 /* Tell everybody else to do something. This has to be a
103 broadcast because we might have both senders and receivers
104 waiting on the condition, but senders won't send another
105 signal. */
106 i = pthread_cond_broadcast (&channel->cond);
107 __go_assert (i == 0);
109 /* Wait until the value is received. */
110 synched_with_select = 0;
111 while (1)
113 if (channel->next_store == 0)
114 break;
116 /* If nobody is currently waiting to receive, try to synch
117 up with a select. */
118 if (!channel->waiting_to_receive && !synched_with_select)
120 if (__go_synch_with_select (channel, 1))
122 synched_with_select = 1;
123 __go_broadcast_to_select (channel);
124 continue;
128 i = pthread_cond_wait (&channel->cond, &channel->lock);
129 __go_assert (i == 0);
132 channel->waiting_to_send = 0;
134 /* Using the mutexes should implement a memory barrier. */
136 /* We have to signal again since we cleared the waiting_to_send
137 field. This has to be a broadcast because both senders and
138 receivers might be waiting, but only senders will be able to
139 act. */
140 i = pthread_cond_broadcast (&channel->cond);
141 __go_assert (i == 0);
144 channel->selected_for_send = 0;
146 __go_unlock_and_notify_selects (channel);
149 /* Send something 64 bits or smaller on a channel. */
151 void
152 __go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select)
154 if (channel == NULL)
155 __go_panic_msg ("send to nil channel");
157 __go_assert (channel->element_size <= sizeof (uint64_t));
159 if (!__go_send_acquire (channel, for_select))
160 return;
162 channel->data[channel->next_store] = val;
164 __go_send_release (channel);