OSDN Git Service

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