4
4
5
5
//go:build unix
6
6
7
+ // When cross-compiling with clang to linux/armv5, atomics are emulated
8
+ // and cause a compiler warning. This results in a build failure since
9
+ // cgo uses -Werror. See #65290.
10
+ #pragma GCC diagnostic ignored "-Wpragmas"
11
+ #pragma GCC diagnostic ignored "-Wunknown-warning-option"
12
+ #pragma GCC diagnostic ignored "-Watomic-alignment"
13
+
7
14
#include <pthread.h>
8
15
#include <errno.h>
9
16
#include <stdio.h>
@@ -42,31 +49,38 @@ x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
42
49
uintptr_t
43
50
_cgo_wait_runtime_init_done (void ) {
44
51
void (* pfn )(struct context_arg * );
52
+ pfn = __atomic_load_n (& cgo_context_function , __ATOMIC_CONSUME );
45
53
46
- pthread_mutex_lock (& runtime_init_mu );
47
- while (runtime_init_done == 0 ) {
48
- pthread_cond_wait (& runtime_init_cond , & runtime_init_mu );
49
- }
54
+ int done = 2 ;
55
+ if (__atomic_load_n (& runtime_init_done , __ATOMIC_CONSUME ) != done ) {
56
+ pthread_mutex_lock (& runtime_init_mu );
57
+ while (__atomic_load_n (& runtime_init_done , __ATOMIC_CONSUME ) == 0 ) {
58
+ pthread_cond_wait (& runtime_init_cond , & runtime_init_mu );
59
+ }
50
60
51
- // The key and x_cgo_pthread_key_created are for the whole program,
52
- // whereas the specific and destructor is per thread.
53
- (void )pthread_key_destructor ;
54
- // if (x_cgo_pthread_key_created == 0 && pthread_key_create(&pthread_g, pthread_key_destructor) == 0) {
55
- // x_cgo_pthread_key_created = 1;
56
- // }
57
-
58
- // TODO(iant): For the case of a new C thread calling into Go, such
59
- // as when using -buildmode=c-archive, we know that Go runtime
60
- // initialization is complete but we do not know that all Go init
61
- // functions have been run. We should not fetch cgo_context_function
62
- // until they have been, because that is where a call to
63
- // SetCgoTraceback is likely to occur. We are going to wait for Go
64
- // initialization to be complete anyhow, later, by waiting for
65
- // main_init_done to be closed in cgocallbackg1. We should wait here
66
- // instead. See also issue #15943.
67
- pfn = cgo_context_function ;
61
+ // The key and x_cgo_pthread_key_created are for the whole program,
62
+ // whereas the specific and destructor is per thread.
63
+ (void )pthread_key_destructor ;
64
+ // if (x_cgo_pthread_key_created == 0 && pthread_key_create(&pthread_g, pthread_key_destructor) == 0) {
65
+ // x_cgo_pthread_key_created = 1;
66
+ // }
67
+
68
+
69
+ // TODO(iant): For the case of a new C thread calling into Go, such
70
+ // as when using -buildmode=c-archive, we know that Go runtime
71
+ // initialization is complete but we do not know that all Go init
72
+ // functions have been run. We should not fetch cgo_context_function
73
+ // until they have been, because that is where a call to
74
+ // SetCgoTraceback is likely to occur. We are going to wait for Go
75
+ // initialization to be complete anyhow, later, by waiting for
76
+ // main_init_done to be closed in cgocallbackg1. We should wait here
77
+ // instead. See also issue #15943.
78
+ pfn = __atomic_load_n (& cgo_context_function , __ATOMIC_CONSUME );
79
+
80
+ __atomic_store_n (& runtime_init_done , done , __ATOMIC_RELEASE );
81
+ pthread_mutex_unlock (& runtime_init_mu );
82
+ }
68
83
69
- pthread_mutex_unlock (& runtime_init_mu );
70
84
if (pfn != nil ) {
71
85
struct context_arg arg ;
72
86
@@ -77,6 +91,30 @@ _cgo_wait_runtime_init_done(void) {
77
91
return 0 ;
78
92
}
79
93
94
+ // _cgo_set_stacklo sets g->stacklo based on the stack size.
95
+ // This is common code called from x_cgo_init, which is itself
96
+ // called by rt0_go in the runtime package.
97
+ void _cgo_set_stacklo (G * g , uintptr * pbounds )
98
+ {
99
+ uintptr bounds [2 ];
100
+
101
+ // pbounds can be passed in by the caller; see gcc_linux_amd64.c.
102
+ if (pbounds == NULL ) {
103
+ pbounds = & bounds [0 ];
104
+ }
105
+
106
+ x_cgo_getstackbound (pbounds );
107
+
108
+ g -> stacklo = * pbounds ;
109
+
110
+ // Sanity check the results now, rather than getting a
111
+ // morestack on g0 crash.
112
+ if (g -> stacklo >= g -> stackhi ) {
113
+ fprintf (stderr , "runtime/cgo: bad stack bounds: lo=%p hi=%p\n" , (void * )(g -> stacklo ), (void * )(g -> stackhi ));
114
+ abort ();
115
+ }
116
+ }
117
+
80
118
// Store the g into a thread-specific value associated with the pthread key pthread_g.
81
119
// And pthread_key_destructor will dropm when the thread is exiting.
82
120
void x_cgo_bindm (void * g ) {
@@ -90,27 +128,20 @@ void x_cgo_bindm(void* g) {
90
128
void
91
129
x_cgo_notify_runtime_init_done (void * dummy __attribute__ ((unused ))) {
92
130
pthread_mutex_lock (& runtime_init_mu );
93
- runtime_init_done = 1 ;
131
+ __atomic_store_n ( & runtime_init_done , 1 , __ATOMIC_RELEASE ) ;
94
132
pthread_cond_broadcast (& runtime_init_cond );
95
133
pthread_mutex_unlock (& runtime_init_mu );
96
134
}
97
135
98
136
// Sets the context function to call to record the traceback context
99
137
// when calling a Go function from C code. Called from runtime.SetCgoTraceback.
100
138
void x_cgo_set_context_function (void (* context )(struct context_arg * )) {
101
- pthread_mutex_lock (& runtime_init_mu );
102
- cgo_context_function = context ;
103
- pthread_mutex_unlock (& runtime_init_mu );
139
+ __atomic_store_n (& cgo_context_function , context , __ATOMIC_RELEASE );
104
140
}
105
141
106
142
// Gets the context function.
107
143
void (* (_cgo_get_context_function (void )))(struct context_arg * ) {
108
- void (* ret )(struct context_arg * );
109
-
110
- pthread_mutex_lock (& runtime_init_mu );
111
- ret = cgo_context_function ;
112
- pthread_mutex_unlock (& runtime_init_mu );
113
- return ret ;
144
+ return __atomic_load_n (& cgo_context_function , __ATOMIC_CONSUME );
114
145
}
115
146
116
147
// _cgo_try_pthread_create retries pthread_create if it fails with
0 commit comments