Fix r180999.
[gcc.git] / libgo / runtime / go-send-nb-small.c
1 /* go-send-nb-small.c -- nonblocking send of something small 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 nonblocking channel. Return true if
14 we acquired the channel, false if we did not acquire it because
15 there is no space to send a value. */
16
17 _Bool
18 __go_send_nonblocking_acquire (struct __go_channel *channel)
19 {
20 int i;
21 _Bool has_space;
22
23 i = pthread_mutex_lock (&channel->lock);
24 __go_assert (i == 0);
25
26 while (channel->selected_for_send)
27 {
28 i = pthread_cond_wait (&channel->cond, &channel->lock);
29 __go_assert (i == 0);
30 }
31
32 if (channel->is_closed)
33 {
34 i = pthread_mutex_unlock (&channel->lock);
35 __go_assert (i == 0);
36 __go_panic_msg ("send on closed channel");
37 }
38
39 if (channel->num_entries > 0)
40 has_space = ((channel->next_store + 1) % channel->num_entries
41 != channel->next_fetch);
42 else
43 {
44 /* This is a synchronous channel. If somebody is current
45 sending, then we can't send. Otherwise, see if somebody is
46 waiting to receive, or see if we can synch with a select. */
47 if (channel->waiting_to_send)
48 {
49 /* Some other goroutine is currently sending on this
50 channel, which means that we can't. */
51 has_space = 0;
52 }
53 else if (channel->waiting_to_receive)
54 {
55 /* Some other goroutine is waiting to receive a value, so we
56 can send directly to them. */
57 has_space = 1;
58 }
59 else if (__go_synch_with_select (channel, 1))
60 {
61 /* We found a select waiting to receive data, so we can send
62 to that. */
63 __go_broadcast_to_select (channel);
64 has_space = 1;
65 }
66 else
67 {
68 /* Otherwise, we can't send, because nobody is waiting to
69 receive. */
70 has_space = 0;
71 }
72
73 if (has_space)
74 {
75 channel->waiting_to_send = 1;
76 __go_assert (channel->next_store == 0);
77 }
78 }
79
80 if (!has_space)
81 {
82 i = pthread_mutex_unlock (&channel->lock);
83 __go_assert (i == 0);
84
85 return 0;
86 }
87
88 return 1;
89 }
90
91 /* Send something 64 bits or smaller on a channel. */
92
93 _Bool
94 __go_send_nonblocking_small (struct __go_channel *channel, uint64_t val)
95 {
96 if (channel == NULL)
97 return 0;
98
99 __go_assert (channel->element_type->__size <= sizeof (uint64_t));
100
101 if (!__go_send_nonblocking_acquire (channel))
102 return 0;
103
104 channel->data[channel->next_store] = val;
105
106 __go_send_release (channel);
107
108 return 1;
109 }