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. FOR_SELECT is true if this
14 call is being made after a select statement returned with this
18 __go_send_acquire (struct __go_channel
*channel
, _Bool for_select
)
22 i
= pthread_mutex_lock (&channel
->lock
);
27 if (channel
->is_closed
)
30 channel
->selected_for_send
= 0;
31 i
= pthread_mutex_unlock (&channel
->lock
);
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
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
47 if (!channel
->waiting_to_send
)
49 __go_assert (channel
->next_store
== 0);
55 /* If there is room on the channel, we are OK. */
56 if ((channel
->next_store
+ 1) % channel
->num_entries
57 != channel
->next_fetch
)
62 /* Wait for something to change, then loop around and try
65 i
= pthread_cond_wait (&channel
->cond
, &channel
->lock
);
70 /* Finished sending something on a channel. */
73 __go_send_release (struct __go_channel
*channel
)
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
);
88 _Bool synched_with_select
;
90 /* This is a synchronous channel. Indicate that we have a value
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
99 i
= pthread_cond_broadcast (&channel
->cond
);
100 __go_assert (i
== 0);
102 /* Wait until the value is received. */
103 synched_with_select
= 0;
106 if (channel
->next_store
== 0)
109 /* If nobody is currently waiting to receive, try to synch
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
);
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
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. */
145 __go_send_small (struct __go_channel
*channel
, uint64_t val
, _Bool for_select
)
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
);