OSDN Git Service

Change builtin make to runtime call at lowering time.
[pf3gnuchains/gcc-fork.git] / libgo / runtime / go-send-small.c
1 /* go-send-small.c -- send something 64 bits or smaller 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 "go-assert.h"
10 #include "go-panic.h"
11 #include "channel.h"
12
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.  */
16
17 void
18 __go_send_acquire (struct __go_channel *channel, _Bool for_select)
19 {
20   int i;
21
22   i = pthread_mutex_lock (&channel->lock);
23   __go_assert (i == 0);
24
25   while (1)
26     {
27       if (channel->is_closed)
28         {
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");
34         }
35
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)
40         {
41           if (channel->num_entries == 0)
42             {
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)
48                 {
49                   __go_assert (channel->next_store == 0);
50                   return;
51                 }
52             }
53           else
54             {
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;
59             }
60         }
61
62       /* Wait for something to change, then loop around and try
63          again.  */
64
65       i = pthread_cond_wait (&channel->cond, &channel->lock);
66       __go_assert (i == 0);
67     }
68 }
69
70 /* Finished sending something on a channel.  */
71
72 void
73 __go_send_release (struct __go_channel *channel)
74 {
75   int i;
76
77   if (channel->num_entries != 0)
78     {
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;
82
83       i = pthread_cond_signal (&channel->cond);
84       __go_assert (i == 0);
85     }
86   else
87     {
88       _Bool synched_with_select;
89
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;
94
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);
101
102       /* Wait until the value is received.  */
103       synched_with_select = 0;
104       while (1)
105         {
106           if (channel->next_store == 0)
107             break;
108
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)
112             {
113               if (__go_synch_with_select (channel, 1))
114                 {
115                   synched_with_select = 1;
116                   __go_broadcast_to_select (channel);
117                   continue;
118                 }
119             }
120
121           i = pthread_cond_wait (&channel->cond, &channel->lock);
122           __go_assert (i == 0);
123         }
124
125       channel->waiting_to_send = 0;
126
127       /* Using the mutexes should implement a memory barrier.  */
128
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);
135     }
136
137   channel->selected_for_send = 0;
138
139   __go_unlock_and_notify_selects (channel);
140 }
141
142 /* Send something 64 bits or smaller on a channel.  */
143
144 void
145 __go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select)
146 {
147   if (channel == NULL)
148     __go_panic_msg ("send to nil channel");
149
150   __go_assert (channel->element_type->__size <= sizeof (uint64_t));
151
152   __go_send_acquire (channel, for_select);
153
154   channel->data[channel->next_store] = val;
155
156   __go_send_release (channel);
157 }