1
1
#include <Python.h>
2
+ #include "pythread.h"
2
3
#include <stdio.h>
3
4
4
5
/*********************************************************
@@ -33,7 +34,7 @@ static void print_subinterp(void)
33
34
);
34
35
}
35
36
36
- static void test_repeated_init_and_subinterpreters (void )
37
+ static int test_repeated_init_and_subinterpreters (void )
37
38
{
38
39
PyThreadState * mainstate , * substate ;
39
40
#ifdef WITH_THREAD
@@ -70,6 +71,7 @@ static void test_repeated_init_and_subinterpreters(void)
70
71
PyEval_RestoreThread (mainstate );
71
72
Py_Finalize ();
72
73
}
74
+ return 0 ;
73
75
}
74
76
75
77
/*****************************************************
@@ -103,7 +105,7 @@ static void check_stdio_details(const char *encoding, const char * errors)
103
105
Py_Finalize ();
104
106
}
105
107
106
- static void test_forced_io_encoding (void )
108
+ static int test_forced_io_encoding (void )
107
109
{
108
110
/* Check various combinations */
109
111
printf ("--- Use defaults ---\n" );
@@ -122,19 +124,123 @@ static void test_forced_io_encoding(void)
122
124
printf ("Unexpected success calling Py_SetStandardStreamEncoding" );
123
125
}
124
126
Py_Finalize ();
127
+ return 0 ;
125
128
}
126
129
127
- /* Different embedding tests */
128
- int main (int argc , char * argv [])
130
+
131
+ /*********************************************************
132
+ * Test parts of the C-API that work before initialization
133
+ *********************************************************/
134
+
135
+ static int test_pre_initialization_api (void )
129
136
{
137
+ /* Leading "./" ensures getpath.c can still find the standard library */
138
+ wchar_t * program = Py_DecodeLocale ("./spam" , NULL );
139
+ if (program == NULL ) {
140
+ fprintf (stderr , "Fatal error: cannot decode program name\n" );
141
+ return 1 ;
142
+ }
143
+ Py_SetProgramName (program );
130
144
131
- /* TODO: Check the argument string to allow for more test cases */
132
- if (argc > 1 ) {
133
- /* For now: assume "forced_io_encoding */
134
- test_forced_io_encoding ();
135
- } else {
136
- /* Run the original embedding test case by default */
137
- test_repeated_init_and_subinterpreters ();
145
+ Py_Initialize ();
146
+ Py_Finalize ();
147
+
148
+ PyMem_RawFree (program );
149
+ return 0 ;
150
+ }
151
+
152
+ static void bpo20891_thread (void * lockp )
153
+ {
154
+ PyThread_type_lock lock = * ((PyThread_type_lock * )lockp );
155
+
156
+ PyGILState_STATE state = PyGILState_Ensure ();
157
+ if (!PyGILState_Check ()) {
158
+ fprintf (stderr , "PyGILState_Check failed!" );
159
+ abort ();
160
+ }
161
+
162
+ PyGILState_Release (state );
163
+
164
+ PyThread_release_lock (lock );
165
+
166
+ PyThread_exit_thread ();
167
+ }
168
+
169
+ static int test_bpo20891 (void )
170
+ {
171
+ /* bpo-20891: Calling PyGILState_Ensure in a non-Python thread before
172
+ calling PyEval_InitThreads() must not crash. PyGILState_Ensure() must
173
+ call PyEval_InitThreads() for us in this case. */
174
+ PyThread_type_lock lock = PyThread_allocate_lock ();
175
+ if (!lock ) {
176
+ fprintf (stderr , "PyThread_allocate_lock failed!" );
177
+ return 1 ;
178
+ }
179
+
180
+ _testembed_Py_Initialize ();
181
+
182
+ long thrd = PyThread_start_new_thread (bpo20891_thread , & lock );
183
+ if (thrd == -1 ) {
184
+ fprintf (stderr , "PyThread_start_new_thread failed!" );
185
+ return 1 ;
138
186
}
187
+ PyThread_acquire_lock (lock , WAIT_LOCK );
188
+
189
+ Py_BEGIN_ALLOW_THREADS
190
+ /* wait until the thread exit */
191
+ PyThread_acquire_lock (lock , WAIT_LOCK );
192
+ Py_END_ALLOW_THREADS
193
+
194
+ PyThread_free_lock (lock );
195
+
139
196
return 0 ;
140
197
}
198
+
199
+
200
+ /* *********************************************************
201
+ * List of test cases and the function that implements it.
202
+ *
203
+ * Names are compared case-sensitively with the first
204
+ * argument. If no match is found, or no first argument was
205
+ * provided, the names of all test cases are printed and
206
+ * the exit code will be -1.
207
+ *
208
+ * The int returned from test functions is used as the exit
209
+ * code, and test_capi treats all non-zero exit codes as a
210
+ * failed test.
211
+ *********************************************************/
212
+ struct TestCase
213
+ {
214
+ const char * name ;
215
+ int (* func )(void );
216
+ };
217
+
218
+ static struct TestCase TestCases [] = {
219
+ { "forced_io_encoding" , test_forced_io_encoding },
220
+ { "repeated_init_and_subinterpreters" , test_repeated_init_and_subinterpreters },
221
+ { "pre_initialization_api" , test_pre_initialization_api },
222
+ { "bpo20891" , test_bpo20891 },
223
+ { NULL , NULL }
224
+ };
225
+
226
+ int main (int argc , char * argv [])
227
+ {
228
+ if (argc > 1 ) {
229
+ for (struct TestCase * tc = TestCases ; tc && tc -> name ; tc ++ ) {
230
+ if (strcmp (argv [1 ], tc -> name ) == 0 )
231
+ return (* tc -> func )();
232
+ }
233
+ }
234
+
235
+ /* No match found, or no test name provided, so display usage */
236
+ printf ("Python " PY_VERSION " _testembed executable for embedded interpreter tests\n"
237
+ "Normally executed via 'EmbeddingTests' in Lib/test/test_capi.py\n\n"
238
+ "Usage: %s TESTNAME\n\nAll available tests:\n" , argv [0 ]);
239
+ for (struct TestCase * tc = TestCases ; tc && tc -> name ; tc ++ ) {
240
+ printf (" %s\n" , tc -> name );
241
+ }
242
+
243
+ /* Non-zero exit code will cause test_capi.py tests to fail.
244
+ This is intentional. */
245
+ return -1 ;
246
+ }
0 commit comments