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. */
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
19 __go_send_acquire (struct __go_channel
*channel
, _Bool for_select
)
23 i
= pthread_mutex_lock (&channel
->lock
);
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
);
36 __go_panic_msg ("too many operations on closed channel");
38 channel
->selected_for_send
= 0;
39 __go_unlock_and_notify_selects (channel
);
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
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
54 if (!channel
->waiting_to_send
)
56 __go_assert (channel
->next_store
== 0);
62 /* If there is room on the channel, we are OK. */
63 if ((channel
->next_store
+ 1) % channel
->num_entries
64 != channel
->next_fetch
)
69 /* Wait for something to change, then loop around and try
72 i
= pthread_cond_wait (&channel
->cond
, &channel
->lock
);
77 /* Finished sending something on a channel. */
80 __go_send_release (struct __go_channel
*channel
)
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
);
95 _Bool synched_with_select
;
97 /* This is a synchronous channel. Indicate that we have a value
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
106 i
= pthread_cond_broadcast (&channel
->cond
);
107 __go_assert (i
== 0);
109 /* Wait until the value is received. */
110 synched_with_select
= 0;
113 if (channel
->next_store
== 0)
116 /* If nobody is currently waiting to receive, try to synch
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
);
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
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. */
152 __go_send_small (struct __go_channel
*channel
, uint64_t val
, _Bool for_select
)
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
))
162 channel
->data
[channel
->next_store
] = val
;
164 __go_send_release (channel
);