blob: 8a6fce9e0b4bd9f6659c295da258ab2f09fc8403 [file] [log] [blame]
Victor Stinnerf2c3b682020-05-14 18:46:24 +02001
2/* interpreters module */
Eric Snow7f8bfc92018-01-29 18:23:44 -07003/* low-level access to interpreter primitives */
4
5#include "Python.h"
6#include "frameobject.h"
Eric Snowc11183c2019-03-15 16:35:46 -06007#include "interpreteridobject.h"
Eric Snow7f8bfc92018-01-29 18:23:44 -07008
9
Victor Stinnerf2c3b682020-05-14 18:46:24 +020010static char *
11_copy_raw_string(PyObject *strobj)
12{
13 const char *str = PyUnicode_AsUTF8(strobj);
14 if (str == NULL) {
15 return NULL;
16 }
17 char *copied = PyMem_Malloc(strlen(str)+1);
18 if (copied == NULL) {
19 PyErr_NoMemory();
20 return NULL;
21 }
22 strcpy(copied, str);
23 return copied;
24}
Eric Snow4e9da0d2018-02-02 21:49:49 -070025
Eric Snow7f8bfc92018-01-29 18:23:44 -070026static PyInterpreterState *
27_get_current(void)
28{
Victor Stinnerf2c3b682020-05-14 18:46:24 +020029 // PyInterpreterState_Get() aborts if lookup fails, so don't need
Eric Snow7f8bfc92018-01-29 18:23:44 -070030 // to check the result for NULL.
Victor Stinnerf2c3b682020-05-14 18:46:24 +020031 return PyInterpreterState_Get();
Eric Snow7f8bfc92018-01-29 18:23:44 -070032}
33
Eric Snow4e9da0d2018-02-02 21:49:49 -070034
Eric Snow7f8bfc92018-01-29 18:23:44 -070035/* data-sharing-specific code ***********************************************/
36
Eric Snow4e9da0d2018-02-02 21:49:49 -070037struct _sharednsitem {
Victor Stinnerf2c3b682020-05-14 18:46:24 +020038 char *name;
Eric Snow7f8bfc92018-01-29 18:23:44 -070039 _PyCrossInterpreterData data;
Eric Snow4e9da0d2018-02-02 21:49:49 -070040};
Eric Snow7f8bfc92018-01-29 18:23:44 -070041
Eric Snowc11183c2019-03-15 16:35:46 -060042static void _sharednsitem_clear(struct _sharednsitem *); // forward
43
Eric Snow4e9da0d2018-02-02 21:49:49 -070044static int
45_sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
Eric Snow7f8bfc92018-01-29 18:23:44 -070046{
Victor Stinnerf2c3b682020-05-14 18:46:24 +020047 item->name = _copy_raw_string(key);
48 if (item->name == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -070049 return -1;
Eric Snow7f8bfc92018-01-29 18:23:44 -070050 }
Eric Snow4e9da0d2018-02-02 21:49:49 -070051 if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
Eric Snowc11183c2019-03-15 16:35:46 -060052 _sharednsitem_clear(item);
Eric Snow4e9da0d2018-02-02 21:49:49 -070053 return -1;
54 }
55 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -070056}
57
Eric Snow4e9da0d2018-02-02 21:49:49 -070058static void
59_sharednsitem_clear(struct _sharednsitem *item)
60{
Victor Stinnerf2c3b682020-05-14 18:46:24 +020061 if (item->name != NULL) {
62 PyMem_Free(item->name);
63 item->name = NULL;
64 }
Eric Snow4e9da0d2018-02-02 21:49:49 -070065 _PyCrossInterpreterData_Release(&item->data);
66}
67
68static int
69_sharednsitem_apply(struct _sharednsitem *item, PyObject *ns)
70{
Victor Stinnerf2c3b682020-05-14 18:46:24 +020071 PyObject *name = PyUnicode_FromString(item->name);
Eric Snow4e9da0d2018-02-02 21:49:49 -070072 if (name == NULL) {
73 return -1;
74 }
75 PyObject *value = _PyCrossInterpreterData_NewObject(&item->data);
76 if (value == NULL) {
77 Py_DECREF(name);
78 return -1;
79 }
80 int res = PyDict_SetItem(ns, name, value);
81 Py_DECREF(name);
82 Py_DECREF(value);
83 return res;
84}
85
86typedef struct _sharedns {
87 Py_ssize_t len;
88 struct _sharednsitem* items;
89} _sharedns;
90
91static _sharedns *
92_sharedns_new(Py_ssize_t len)
93{
94 _sharedns *shared = PyMem_NEW(_sharedns, 1);
95 if (shared == NULL) {
96 PyErr_NoMemory();
97 return NULL;
98 }
99 shared->len = len;
100 shared->items = PyMem_NEW(struct _sharednsitem, len);
101 if (shared->items == NULL) {
102 PyErr_NoMemory();
103 PyMem_Free(shared);
104 return NULL;
105 }
106 return shared;
107}
108
109static void
110_sharedns_free(_sharedns *shared)
111{
112 for (Py_ssize_t i=0; i < shared->len; i++) {
113 _sharednsitem_clear(&shared->items[i]);
114 }
115 PyMem_Free(shared->items);
116 PyMem_Free(shared);
117}
118
119static _sharedns *
120_get_shared_ns(PyObject *shareable)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700121{
122 if (shareable == NULL || shareable == Py_None) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700123 return NULL;
124 }
125 Py_ssize_t len = PyDict_Size(shareable);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700126 if (len == 0) {
127 return NULL;
128 }
129
Eric Snow4e9da0d2018-02-02 21:49:49 -0700130 _sharedns *shared = _sharedns_new(len);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700131 if (shared == NULL) {
132 return NULL;
133 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700134 Py_ssize_t pos = 0;
135 for (Py_ssize_t i=0; i < len; i++) {
136 PyObject *key, *value;
137 if (PyDict_Next(shareable, &pos, &key, &value) == 0) {
138 break;
139 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700140 if (_sharednsitem_init(&shared->items[i], key, value) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700141 break;
142 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700143 }
144 if (PyErr_Occurred()) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700145 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700146 return NULL;
147 }
148 return shared;
149}
150
151static int
Eric Snow4e9da0d2018-02-02 21:49:49 -0700152_sharedns_apply(_sharedns *shared, PyObject *ns)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700153{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700154 for (Py_ssize_t i=0; i < shared->len; i++) {
155 if (_sharednsitem_apply(&shared->items[i], ns) != 0) {
156 return -1;
157 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700158 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700159 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700160}
161
162// Ultimately we'd like to preserve enough information about the
163// exception and traceback that we could re-constitute (or at least
164// simulate, a la traceback.TracebackException), and even chain, a copy
165// of the exception in the calling interpreter.
166
167typedef struct _sharedexception {
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200168 char *name;
169 char *msg;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700170} _sharedexception;
171
172static _sharedexception *
Eric Snow4e9da0d2018-02-02 21:49:49 -0700173_sharedexception_new(void)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700174{
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200175 _sharedexception *err = PyMem_NEW(_sharedexception, 1);
176 if (err == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700177 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -0700178 return NULL;
179 }
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200180 err->name = NULL;
181 err->msg = NULL;
182 return err;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700183}
184
185static void
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200186_sharedexception_clear(_sharedexception *exc)
Eric Snow4e9da0d2018-02-02 21:49:49 -0700187{
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200188 if (exc->name != NULL) {
189 PyMem_Free(exc->name);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700190 }
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200191 if (exc->msg != NULL) {
192 PyMem_Free(exc->msg);
193 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700194}
195
Eric Snow7f8bfc92018-01-29 18:23:44 -0700196static void
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200197_sharedexception_free(_sharedexception *exc)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700198{
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200199 _sharedexception_clear(exc);
200 PyMem_Free(exc);
201}
Eric Snowa1d9e0a2020-05-07 08:56:01 -0600202
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200203static _sharedexception *
204_sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb)
205{
206 assert(exctype != NULL);
207 char *failure = NULL;
Eric Snowa1d9e0a2020-05-07 08:56:01 -0600208
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200209 _sharedexception *err = _sharedexception_new();
210 if (err == NULL) {
211 goto finally;
212 }
213
214 PyObject *name = PyUnicode_FromFormat("%S", exctype);
215 if (name == NULL) {
216 failure = "unable to format exception type name";
217 goto finally;
218 }
219 err->name = _copy_raw_string(name);
220 Py_DECREF(name);
221 if (err->name == NULL) {
222 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
223 failure = "out of memory copying exception type name";
224 } else {
225 failure = "unable to encode and copy exception type name";
226 }
227 goto finally;
228 }
229
230 if (exc != NULL) {
231 PyObject *msg = PyUnicode_FromFormat("%S", exc);
232 if (msg == NULL) {
233 failure = "unable to format exception message";
234 goto finally;
235 }
236 err->msg = _copy_raw_string(msg);
237 Py_DECREF(msg);
238 if (err->msg == NULL) {
239 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
240 failure = "out of memory copying exception message";
241 } else {
242 failure = "unable to encode and copy exception message";
243 }
244 goto finally;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700245 }
246 }
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200247
248finally:
249 if (failure != NULL) {
250 PyErr_Clear();
251 if (err->name != NULL) {
252 PyMem_Free(err->name);
253 err->name = NULL;
254 }
255 err->msg = failure;
256 }
257 return err;
Eric Snowa1d9e0a2020-05-07 08:56:01 -0600258}
259
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200260static void
261_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
Eric Snowa1d9e0a2020-05-07 08:56:01 -0600262{
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200263 if (exc->name != NULL) {
264 if (exc->msg != NULL) {
265 PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg);
266 }
267 else {
268 PyErr_SetString(wrapperclass, exc->name);
269 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700270 }
Victor Stinnerf2c3b682020-05-14 18:46:24 +0200271 else if (exc->msg != NULL) {
272 PyErr_SetString(wrapperclass, exc->msg);
273 }
274 else {
275 PyErr_SetNone(wrapperclass);
276 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700277}
278
Eric Snow4e9da0d2018-02-02 21:49:49 -0700279
280/* channel-specific code ****************************************************/
Eric Snow7f8bfc92018-01-29 18:23:44 -0700281
Eric Snow3ab01362018-05-17 10:27:09 -0400282#define CHANNEL_SEND 1
283#define CHANNEL_BOTH 0
284#define CHANNEL_RECV -1
285
Eric Snow7f8bfc92018-01-29 18:23:44 -0700286static PyObject *ChannelError;
287static PyObject *ChannelNotFoundError;
288static PyObject *ChannelClosedError;
289static PyObject *ChannelEmptyError;
Eric Snow3ab01362018-05-17 10:27:09 -0400290static PyObject *ChannelNotEmptyError;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700291
292static int
293channel_exceptions_init(PyObject *ns)
294{
295 // XXX Move the exceptions into per-module memory?
296
297 // A channel-related operation failed.
298 ChannelError = PyErr_NewException("_xxsubinterpreters.ChannelError",
299 PyExc_RuntimeError, NULL);
300 if (ChannelError == NULL) {
301 return -1;
302 }
303 if (PyDict_SetItemString(ns, "ChannelError", ChannelError) != 0) {
304 return -1;
305 }
306
307 // An operation tried to use a channel that doesn't exist.
308 ChannelNotFoundError = PyErr_NewException(
309 "_xxsubinterpreters.ChannelNotFoundError", ChannelError, NULL);
310 if (ChannelNotFoundError == NULL) {
311 return -1;
312 }
313 if (PyDict_SetItemString(ns, "ChannelNotFoundError", ChannelNotFoundError) != 0) {
314 return -1;
315 }
316
317 // An operation tried to use a closed channel.
318 ChannelClosedError = PyErr_NewException(
319 "_xxsubinterpreters.ChannelClosedError", ChannelError, NULL);
320 if (ChannelClosedError == NULL) {
321 return -1;
322 }
323 if (PyDict_SetItemString(ns, "ChannelClosedError", ChannelClosedError) != 0) {
324 return -1;
325 }
326
327 // An operation tried to pop from an empty channel.
328 ChannelEmptyError = PyErr_NewException(
329 "_xxsubinterpreters.ChannelEmptyError", ChannelError, NULL);
330 if (ChannelEmptyError == NULL) {
331 return -1;
332 }
333 if (PyDict_SetItemString(ns, "ChannelEmptyError", ChannelEmptyError) != 0) {
334 return -1;
335 }
336
Eric Snow3ab01362018-05-17 10:27:09 -0400337 // An operation tried to close a non-empty channel.
338 ChannelNotEmptyError = PyErr_NewException(
339 "_xxsubinterpreters.ChannelNotEmptyError", ChannelError, NULL);
340 if (ChannelNotEmptyError == NULL) {
341 return -1;
342 }
343 if (PyDict_SetItemString(ns, "ChannelNotEmptyError", ChannelNotEmptyError) != 0) {
344 return -1;
345 }
346
Eric Snow7f8bfc92018-01-29 18:23:44 -0700347 return 0;
348}
349
Eric Snow4e9da0d2018-02-02 21:49:49 -0700350/* the channel queue */
351
352struct _channelitem;
353
354typedef struct _channelitem {
355 _PyCrossInterpreterData *data;
356 struct _channelitem *next;
357} _channelitem;
358
359static _channelitem *
360_channelitem_new(void)
361{
362 _channelitem *item = PyMem_NEW(_channelitem, 1);
363 if (item == NULL) {
364 PyErr_NoMemory();
365 return NULL;
366 }
367 item->data = NULL;
368 item->next = NULL;
369 return item;
370}
371
372static void
373_channelitem_clear(_channelitem *item)
374{
375 if (item->data != NULL) {
376 _PyCrossInterpreterData_Release(item->data);
377 PyMem_Free(item->data);
378 item->data = NULL;
379 }
380 item->next = NULL;
381}
382
383static void
384_channelitem_free(_channelitem *item)
385{
386 _channelitem_clear(item);
387 PyMem_Free(item);
388}
389
390static void
391_channelitem_free_all(_channelitem *item)
392{
393 while (item != NULL) {
394 _channelitem *last = item;
395 item = item->next;
396 _channelitem_free(last);
397 }
398}
399
400static _PyCrossInterpreterData *
401_channelitem_popped(_channelitem *item)
402{
403 _PyCrossInterpreterData *data = item->data;
404 item->data = NULL;
405 _channelitem_free(item);
406 return data;
407}
408
409typedef struct _channelqueue {
410 int64_t count;
411 _channelitem *first;
412 _channelitem *last;
413} _channelqueue;
414
415static _channelqueue *
416_channelqueue_new(void)
417{
418 _channelqueue *queue = PyMem_NEW(_channelqueue, 1);
419 if (queue == NULL) {
420 PyErr_NoMemory();
421 return NULL;
422 }
423 queue->count = 0;
424 queue->first = NULL;
425 queue->last = NULL;
426 return queue;
427}
428
429static void
430_channelqueue_clear(_channelqueue *queue)
431{
432 _channelitem_free_all(queue->first);
433 queue->count = 0;
434 queue->first = NULL;
435 queue->last = NULL;
436}
437
438static void
439_channelqueue_free(_channelqueue *queue)
440{
441 _channelqueue_clear(queue);
442 PyMem_Free(queue);
443}
444
445static int
446_channelqueue_put(_channelqueue *queue, _PyCrossInterpreterData *data)
447{
448 _channelitem *item = _channelitem_new();
449 if (item == NULL) {
450 return -1;
451 }
452 item->data = data;
453
454 queue->count += 1;
455 if (queue->first == NULL) {
456 queue->first = item;
457 }
458 else {
459 queue->last->next = item;
460 }
461 queue->last = item;
462 return 0;
463}
464
465static _PyCrossInterpreterData *
466_channelqueue_get(_channelqueue *queue)
467{
468 _channelitem *item = queue->first;
469 if (item == NULL) {
470 return NULL;
471 }
472 queue->first = item->next;
473 if (queue->last == item) {
474 queue->last = NULL;
475 }
476 queue->count -= 1;
477
478 return _channelitem_popped(item);
479}
480
481/* channel-interpreter associations */
482
Eric Snow7f8bfc92018-01-29 18:23:44 -0700483struct _channelend;
484
485typedef struct _channelend {
486 struct _channelend *next;
487 int64_t interp;
488 int open;
489} _channelend;
490
491static _channelend *
492_channelend_new(int64_t interp)
493{
494 _channelend *end = PyMem_NEW(_channelend, 1);
495 if (end == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700496 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -0700497 return NULL;
498 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700499 end->next = NULL;
500 end->interp = interp;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700501 end->open = 1;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700502 return end;
503}
504
505static void
Eric Snow4e9da0d2018-02-02 21:49:49 -0700506_channelend_free(_channelend *end)
507{
508 PyMem_Free(end);
509}
510
511static void
512_channelend_free_all(_channelend *end)
513{
Eric Snow7f8bfc92018-01-29 18:23:44 -0700514 while (end != NULL) {
515 _channelend *last = end;
516 end = end->next;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700517 _channelend_free(last);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700518 }
519}
520
521static _channelend *
522_channelend_find(_channelend *first, int64_t interp, _channelend **pprev)
523{
524 _channelend *prev = NULL;
525 _channelend *end = first;
526 while (end != NULL) {
527 if (end->interp == interp) {
528 break;
529 }
530 prev = end;
531 end = end->next;
532 }
533 if (pprev != NULL) {
534 *pprev = prev;
535 }
536 return end;
537}
538
Eric Snow4e9da0d2018-02-02 21:49:49 -0700539typedef struct _channelassociations {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700540 // Note that the list entries are never removed for interpreter
Lewis Gaulf7bbf582020-04-29 01:18:42 +0100541 // for which the channel is closed. This should not be a problem in
Eric Snow7f8bfc92018-01-29 18:23:44 -0700542 // practice. Also, a channel isn't automatically closed when an
543 // interpreter is destroyed.
544 int64_t numsendopen;
545 int64_t numrecvopen;
546 _channelend *send;
547 _channelend *recv;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700548} _channelends;
549
550static _channelends *
551_channelends_new(void)
552{
553 _channelends *ends = PyMem_NEW(_channelends, 1);
554 if (ends== NULL) {
555 return NULL;
556 }
557 ends->numsendopen = 0;
558 ends->numrecvopen = 0;
559 ends->send = NULL;
560 ends->recv = NULL;
561 return ends;
562}
563
564static void
565_channelends_clear(_channelends *ends)
566{
567 _channelend_free_all(ends->send);
568 ends->send = NULL;
569 ends->numsendopen = 0;
570
571 _channelend_free_all(ends->recv);
572 ends->recv = NULL;
573 ends->numrecvopen = 0;
574}
575
576static void
577_channelends_free(_channelends *ends)
578{
579 _channelends_clear(ends);
580 PyMem_Free(ends);
581}
582
583static _channelend *
584_channelends_add(_channelends *ends, _channelend *prev, int64_t interp,
585 int send)
586{
587 _channelend *end = _channelend_new(interp);
588 if (end == NULL) {
589 return NULL;
590 }
591
592 if (prev == NULL) {
593 if (send) {
594 ends->send = end;
595 }
596 else {
597 ends->recv = end;
598 }
599 }
600 else {
601 prev->next = end;
602 }
603 if (send) {
604 ends->numsendopen += 1;
605 }
606 else {
607 ends->numrecvopen += 1;
608 }
609 return end;
610}
611
612static int
613_channelends_associate(_channelends *ends, int64_t interp, int send)
614{
615 _channelend *prev;
616 _channelend *end = _channelend_find(send ? ends->send : ends->recv,
617 interp, &prev);
618 if (end != NULL) {
619 if (!end->open) {
620 PyErr_SetString(ChannelClosedError, "channel already closed");
621 return -1;
622 }
623 // already associated
624 return 0;
625 }
626 if (_channelends_add(ends, prev, interp, send) == NULL) {
627 return -1;
628 }
629 return 0;
630}
631
632static int
633_channelends_is_open(_channelends *ends)
634{
635 if (ends->numsendopen != 0 || ends->numrecvopen != 0) {
636 return 1;
637 }
638 if (ends->send == NULL && ends->recv == NULL) {
639 return 1;
640 }
641 return 0;
642}
643
644static void
645_channelends_close_end(_channelends *ends, _channelend *end, int send)
646{
647 end->open = 0;
648 if (send) {
649 ends->numsendopen -= 1;
650 }
651 else {
652 ends->numrecvopen -= 1;
653 }
654}
655
656static int
657_channelends_close_interpreter(_channelends *ends, int64_t interp, int which)
658{
659 _channelend *prev;
660 _channelend *end;
661 if (which >= 0) { // send/both
662 end = _channelend_find(ends->send, interp, &prev);
663 if (end == NULL) {
664 // never associated so add it
665 end = _channelends_add(ends, prev, interp, 1);
666 if (end == NULL) {
667 return -1;
668 }
669 }
670 _channelends_close_end(ends, end, 1);
671 }
672 if (which <= 0) { // recv/both
673 end = _channelend_find(ends->recv, interp, &prev);
674 if (end == NULL) {
675 // never associated so add it
676 end = _channelends_add(ends, prev, interp, 0);
677 if (end == NULL) {
678 return -1;
679 }
680 }
681 _channelends_close_end(ends, end, 0);
682 }
683 return 0;
684}
685
686static void
Eric Snow3ab01362018-05-17 10:27:09 -0400687_channelends_close_all(_channelends *ends, int which, int force)
Eric Snow4e9da0d2018-02-02 21:49:49 -0700688{
Eric Snow3ab01362018-05-17 10:27:09 -0400689 // XXX Handle the ends.
690 // XXX Handle force is True.
691
Eric Snow4e9da0d2018-02-02 21:49:49 -0700692 // Ensure all the "send"-associated interpreters are closed.
693 _channelend *end;
694 for (end = ends->send; end != NULL; end = end->next) {
695 _channelends_close_end(ends, end, 1);
696 }
697
698 // Ensure all the "recv"-associated interpreters are closed.
699 for (end = ends->recv; end != NULL; end = end->next) {
700 _channelends_close_end(ends, end, 0);
701 }
702}
703
704/* channels */
705
706struct _channel;
Eric Snow3ab01362018-05-17 10:27:09 -0400707struct _channel_closing;
708static void _channel_clear_closing(struct _channel *);
709static void _channel_finish_closing(struct _channel *);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700710
711typedef struct _channel {
712 PyThread_type_lock mutex;
713 _channelqueue *queue;
714 _channelends *ends;
715 int open;
Eric Snow3ab01362018-05-17 10:27:09 -0400716 struct _channel_closing *closing;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700717} _PyChannelState;
718
719static _PyChannelState *
720_channel_new(void)
721{
722 _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1);
723 if (chan == NULL) {
724 return NULL;
725 }
726 chan->mutex = PyThread_allocate_lock();
727 if (chan->mutex == NULL) {
728 PyMem_Free(chan);
729 PyErr_SetString(ChannelError,
730 "can't initialize mutex for new channel");
731 return NULL;
732 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700733 chan->queue = _channelqueue_new();
734 if (chan->queue == NULL) {
735 PyMem_Free(chan);
736 return NULL;
737 }
738 chan->ends = _channelends_new();
739 if (chan->ends == NULL) {
740 _channelqueue_free(chan->queue);
741 PyMem_Free(chan);
742 return NULL;
743 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700744 chan->open = 1;
Eric Snow3ab01362018-05-17 10:27:09 -0400745 chan->closing = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700746 return chan;
747}
748
Eric Snow4e9da0d2018-02-02 21:49:49 -0700749static void
750_channel_free(_PyChannelState *chan)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700751{
Eric Snow3ab01362018-05-17 10:27:09 -0400752 _channel_clear_closing(chan);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700753 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
754 _channelqueue_free(chan->queue);
755 _channelends_free(chan->ends);
756 PyThread_release_lock(chan->mutex);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700757
Eric Snow4e9da0d2018-02-02 21:49:49 -0700758 PyThread_free_lock(chan->mutex);
759 PyMem_Free(chan);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700760}
761
Eric Snow4e9da0d2018-02-02 21:49:49 -0700762static int
763_channel_add(_PyChannelState *chan, int64_t interp,
764 _PyCrossInterpreterData *data)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700765{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700766 int res = -1;
767 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
768
Eric Snow7f8bfc92018-01-29 18:23:44 -0700769 if (!chan->open) {
770 PyErr_SetString(ChannelClosedError, "channel closed");
Eric Snow4e9da0d2018-02-02 21:49:49 -0700771 goto done;
772 }
773 if (_channelends_associate(chan->ends, interp, 1) != 0) {
774 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700775 }
776
Eric Snow4e9da0d2018-02-02 21:49:49 -0700777 if (_channelqueue_put(chan->queue, data) != 0) {
778 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700779 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700780
781 res = 0;
782done:
783 PyThread_release_lock(chan->mutex);
784 return res;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700785}
786
Eric Snow4e9da0d2018-02-02 21:49:49 -0700787static _PyCrossInterpreterData *
788_channel_next(_PyChannelState *chan, int64_t interp)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700789{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700790 _PyCrossInterpreterData *data = NULL;
791 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
792
793 if (!chan->open) {
794 PyErr_SetString(ChannelClosedError, "channel closed");
795 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700796 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700797 if (_channelends_associate(chan->ends, interp, 0) != 0) {
798 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700799 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700800
801 data = _channelqueue_get(chan->queue);
Eric Snow3ab01362018-05-17 10:27:09 -0400802 if (data == NULL && !PyErr_Occurred() && chan->closing != NULL) {
803 chan->open = 0;
804 }
805
Eric Snow4e9da0d2018-02-02 21:49:49 -0700806done:
807 PyThread_release_lock(chan->mutex);
Eric Snow3ab01362018-05-17 10:27:09 -0400808 if (chan->queue->count == 0) {
809 _channel_finish_closing(chan);
810 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700811 return data;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700812}
813
814static int
Eric Snow3ab01362018-05-17 10:27:09 -0400815_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int end)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700816{
817 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
818
819 int res = -1;
820 if (!chan->open) {
821 PyErr_SetString(ChannelClosedError, "channel already closed");
822 goto done;
823 }
824
Eric Snow3ab01362018-05-17 10:27:09 -0400825 if (_channelends_close_interpreter(chan->ends, interp, end) != 0) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700826 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700827 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700828 chan->open = _channelends_is_open(chan->ends);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700829
830 res = 0;
831done:
832 PyThread_release_lock(chan->mutex);
833 return res;
834}
835
836static int
Eric Snow3ab01362018-05-17 10:27:09 -0400837_channel_close_all(_PyChannelState *chan, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700838{
839 int res = -1;
840 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
841
842 if (!chan->open) {
843 PyErr_SetString(ChannelClosedError, "channel already closed");
844 goto done;
845 }
846
Eric Snow3ab01362018-05-17 10:27:09 -0400847 if (!force && chan->queue->count > 0) {
848 PyErr_SetString(ChannelNotEmptyError,
849 "may not be closed if not empty (try force=True)");
850 goto done;
851 }
852
Eric Snow7f8bfc92018-01-29 18:23:44 -0700853 chan->open = 0;
854
855 // We *could* also just leave these in place, since we've marked
856 // the channel as closed already.
Eric Snow3ab01362018-05-17 10:27:09 -0400857 _channelends_close_all(chan->ends, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700858
859 res = 0;
860done:
861 PyThread_release_lock(chan->mutex);
862 return res;
863}
864
Eric Snow4e9da0d2018-02-02 21:49:49 -0700865/* the set of channels */
Eric Snow7f8bfc92018-01-29 18:23:44 -0700866
867struct _channelref;
868
869typedef struct _channelref {
870 int64_t id;
871 _PyChannelState *chan;
872 struct _channelref *next;
873 Py_ssize_t objcount;
874} _channelref;
875
876static _channelref *
877_channelref_new(int64_t id, _PyChannelState *chan)
878{
879 _channelref *ref = PyMem_NEW(_channelref, 1);
880 if (ref == NULL) {
881 return NULL;
882 }
883 ref->id = id;
884 ref->chan = chan;
885 ref->next = NULL;
886 ref->objcount = 0;
887 return ref;
888}
889
Eric Snow4e9da0d2018-02-02 21:49:49 -0700890//static void
891//_channelref_clear(_channelref *ref)
892//{
893// ref->id = -1;
894// ref->chan = NULL;
895// ref->next = NULL;
896// ref->objcount = 0;
897//}
898
899static void
900_channelref_free(_channelref *ref)
901{
Eric Snow3ab01362018-05-17 10:27:09 -0400902 if (ref->chan != NULL) {
903 _channel_clear_closing(ref->chan);
904 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700905 //_channelref_clear(ref);
906 PyMem_Free(ref);
907}
908
Eric Snow7f8bfc92018-01-29 18:23:44 -0700909static _channelref *
910_channelref_find(_channelref *first, int64_t id, _channelref **pprev)
911{
912 _channelref *prev = NULL;
913 _channelref *ref = first;
914 while (ref != NULL) {
915 if (ref->id == id) {
916 break;
917 }
918 prev = ref;
919 ref = ref->next;
920 }
921 if (pprev != NULL) {
922 *pprev = prev;
923 }
924 return ref;
925}
926
927typedef struct _channels {
928 PyThread_type_lock mutex;
929 _channelref *head;
930 int64_t numopen;
931 int64_t next_id;
932} _channels;
933
934static int
935_channels_init(_channels *channels)
936{
937 if (channels->mutex == NULL) {
938 channels->mutex = PyThread_allocate_lock();
939 if (channels->mutex == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700940 PyErr_SetString(ChannelError,
941 "can't initialize mutex for channel management");
942 return -1;
943 }
944 }
945 channels->head = NULL;
946 channels->numopen = 0;
947 channels->next_id = 0;
948 return 0;
949}
950
951static int64_t
952_channels_next_id(_channels *channels) // needs lock
953{
954 int64_t id = channels->next_id;
955 if (id < 0) {
956 /* overflow */
957 PyErr_SetString(ChannelError,
958 "failed to get a channel ID");
959 return -1;
960 }
961 channels->next_id += 1;
962 return id;
963}
964
965static _PyChannelState *
966_channels_lookup(_channels *channels, int64_t id, PyThread_type_lock *pmutex)
967{
968 _PyChannelState *chan = NULL;
969 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
970 if (pmutex != NULL) {
971 *pmutex = NULL;
972 }
973
974 _channelref *ref = _channelref_find(channels->head, id, NULL);
975 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -0600976 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700977 goto done;
978 }
979 if (ref->chan == NULL || !ref->chan->open) {
Eric Snowab4a1982018-06-13 08:02:39 -0600980 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700981 goto done;
982 }
983
984 if (pmutex != NULL) {
985 // The mutex will be closed by the caller.
986 *pmutex = channels->mutex;
987 }
988
989 chan = ref->chan;
990done:
991 if (pmutex == NULL || *pmutex == NULL) {
992 PyThread_release_lock(channels->mutex);
993 }
994 return chan;
995}
996
997static int64_t
998_channels_add(_channels *channels, _PyChannelState *chan)
999{
1000 int64_t cid = -1;
1001 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1002
1003 // Create a new ref.
1004 int64_t id = _channels_next_id(channels);
1005 if (id < 0) {
1006 goto done;
1007 }
1008 _channelref *ref = _channelref_new(id, chan);
1009 if (ref == NULL) {
1010 goto done;
1011 }
1012
1013 // Add it to the list.
1014 // We assume that the channel is a new one (not already in the list).
1015 ref->next = channels->head;
1016 channels->head = ref;
1017 channels->numopen += 1;
1018
1019 cid = id;
1020done:
1021 PyThread_release_lock(channels->mutex);
1022 return cid;
1023}
1024
Eric Snow3ab01362018-05-17 10:27:09 -04001025/* forward */
1026static int _channel_set_closing(struct _channelref *, PyThread_type_lock);
1027
Eric Snow7f8bfc92018-01-29 18:23:44 -07001028static int
Eric Snow3ab01362018-05-17 10:27:09 -04001029_channels_close(_channels *channels, int64_t cid, _PyChannelState **pchan,
1030 int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001031{
1032 int res = -1;
1033 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1034 if (pchan != NULL) {
1035 *pchan = NULL;
1036 }
1037
1038 _channelref *ref = _channelref_find(channels->head, cid, NULL);
1039 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001040 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001041 goto done;
1042 }
1043
1044 if (ref->chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001045 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001046 goto done;
1047 }
Eric Snow3ab01362018-05-17 10:27:09 -04001048 else if (!force && end == CHANNEL_SEND && ref->chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001049 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001050 goto done;
1051 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001052 else {
Eric Snow3ab01362018-05-17 10:27:09 -04001053 if (_channel_close_all(ref->chan, end, force) != 0) {
1054 if (end == CHANNEL_SEND &&
1055 PyErr_ExceptionMatches(ChannelNotEmptyError)) {
1056 if (ref->chan->closing != NULL) {
Eric Snow6854e802018-06-01 16:26:01 -06001057 PyErr_Format(ChannelClosedError,
Eric Snowab4a1982018-06-13 08:02:39 -06001058 "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001059 goto done;
1060 }
1061 // Mark the channel as closing and return. The channel
1062 // will be cleaned up in _channel_next().
1063 PyErr_Clear();
1064 if (_channel_set_closing(ref, channels->mutex) != 0) {
1065 goto done;
1066 }
1067 if (pchan != NULL) {
1068 *pchan = ref->chan;
1069 }
1070 res = 0;
1071 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001072 goto done;
1073 }
1074 if (pchan != NULL) {
1075 *pchan = ref->chan;
1076 }
Eric Snow3ab01362018-05-17 10:27:09 -04001077 else {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001078 _channel_free(ref->chan);
1079 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001080 ref->chan = NULL;
1081 }
1082
1083 res = 0;
1084done:
1085 PyThread_release_lock(channels->mutex);
1086 return res;
1087}
1088
1089static void
1090_channels_remove_ref(_channels *channels, _channelref *ref, _channelref *prev,
1091 _PyChannelState **pchan)
1092{
1093 if (ref == channels->head) {
1094 channels->head = ref->next;
1095 }
1096 else {
1097 prev->next = ref->next;
1098 }
1099 channels->numopen -= 1;
1100
1101 if (pchan != NULL) {
1102 *pchan = ref->chan;
1103 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001104 _channelref_free(ref);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001105}
1106
1107static int
1108_channels_remove(_channels *channels, int64_t id, _PyChannelState **pchan)
1109{
1110 int res = -1;
1111 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1112
1113 if (pchan != NULL) {
1114 *pchan = NULL;
1115 }
1116
1117 _channelref *prev = NULL;
1118 _channelref *ref = _channelref_find(channels->head, id, &prev);
1119 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001120 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001121 goto done;
1122 }
1123
1124 _channels_remove_ref(channels, ref, prev, pchan);
1125
1126 res = 0;
1127done:
1128 PyThread_release_lock(channels->mutex);
1129 return res;
1130}
1131
1132static int
1133_channels_add_id_object(_channels *channels, int64_t id)
1134{
1135 int res = -1;
1136 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1137
1138 _channelref *ref = _channelref_find(channels->head, id, NULL);
1139 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001140 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001141 goto done;
1142 }
1143 ref->objcount += 1;
1144
1145 res = 0;
1146done:
1147 PyThread_release_lock(channels->mutex);
1148 return res;
1149}
1150
1151static void
1152_channels_drop_id_object(_channels *channels, int64_t id)
1153{
1154 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1155
1156 _channelref *prev = NULL;
1157 _channelref *ref = _channelref_find(channels->head, id, &prev);
1158 if (ref == NULL) {
1159 // Already destroyed.
1160 goto done;
1161 }
1162 ref->objcount -= 1;
1163
1164 // Destroy if no longer used.
1165 if (ref->objcount == 0) {
1166 _PyChannelState *chan = NULL;
1167 _channels_remove_ref(channels, ref, prev, &chan);
1168 if (chan != NULL) {
1169 _channel_free(chan);
1170 }
1171 }
1172
1173done:
1174 PyThread_release_lock(channels->mutex);
1175}
1176
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001177static int64_t *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001178_channels_list_all(_channels *channels, int64_t *count)
1179{
1180 int64_t *cids = NULL;
1181 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001182 int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)(channels->numopen));
1183 if (ids == NULL) {
1184 goto done;
1185 }
1186 _channelref *ref = channels->head;
1187 for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
1188 ids[i] = ref->id;
1189 }
1190 *count = channels->numopen;
1191
1192 cids = ids;
1193done:
1194 PyThread_release_lock(channels->mutex);
1195 return cids;
1196}
1197
Eric Snow3ab01362018-05-17 10:27:09 -04001198/* support for closing non-empty channels */
1199
1200struct _channel_closing {
1201 struct _channelref *ref;
1202};
1203
1204static int
1205_channel_set_closing(struct _channelref *ref, PyThread_type_lock mutex) {
1206 struct _channel *chan = ref->chan;
1207 if (chan == NULL) {
1208 // already closed
1209 return 0;
1210 }
1211 int res = -1;
1212 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1213 if (chan->closing != NULL) {
1214 PyErr_SetString(ChannelClosedError, "channel closed");
1215 goto done;
1216 }
1217 chan->closing = PyMem_NEW(struct _channel_closing, 1);
1218 if (chan->closing == NULL) {
1219 goto done;
1220 }
1221 chan->closing->ref = ref;
1222
1223 res = 0;
1224done:
1225 PyThread_release_lock(chan->mutex);
1226 return res;
1227}
1228
1229static void
1230_channel_clear_closing(struct _channel *chan) {
1231 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1232 if (chan->closing != NULL) {
1233 PyMem_Free(chan->closing);
1234 chan->closing = NULL;
1235 }
1236 PyThread_release_lock(chan->mutex);
1237}
1238
1239static void
1240_channel_finish_closing(struct _channel *chan) {
1241 struct _channel_closing *closing = chan->closing;
1242 if (closing == NULL) {
1243 return;
1244 }
1245 _channelref *ref = closing->ref;
1246 _channel_clear_closing(chan);
1247 // Do the things that would have been done in _channels_close().
1248 ref->chan = NULL;
1249 _channel_free(chan);
Zackery Spytz1a2252e2019-05-06 10:56:51 -06001250}
Eric Snow3ab01362018-05-17 10:27:09 -04001251
Eric Snow7f8bfc92018-01-29 18:23:44 -07001252/* "high"-level channel-related functions */
1253
1254static int64_t
1255_channel_create(_channels *channels)
1256{
1257 _PyChannelState *chan = _channel_new();
1258 if (chan == NULL) {
1259 return -1;
1260 }
1261 int64_t id = _channels_add(channels, chan);
1262 if (id < 0) {
1263 _channel_free(chan);
1264 return -1;
1265 }
1266 return id;
1267}
1268
1269static int
1270_channel_destroy(_channels *channels, int64_t id)
1271{
1272 _PyChannelState *chan = NULL;
1273 if (_channels_remove(channels, id, &chan) != 0) {
1274 return -1;
1275 }
1276 if (chan != NULL) {
1277 _channel_free(chan);
1278 }
1279 return 0;
1280}
1281
1282static int
1283_channel_send(_channels *channels, int64_t id, PyObject *obj)
1284{
1285 PyInterpreterState *interp = _get_current();
1286 if (interp == NULL) {
1287 return -1;
1288 }
1289
1290 // Look up the channel.
1291 PyThread_type_lock mutex = NULL;
1292 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1293 if (chan == NULL) {
1294 return -1;
1295 }
1296 // Past this point we are responsible for releasing the mutex.
1297
Eric Snow3ab01362018-05-17 10:27:09 -04001298 if (chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001299 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow3ab01362018-05-17 10:27:09 -04001300 PyThread_release_lock(mutex);
1301 return -1;
1302 }
1303
Eric Snow7f8bfc92018-01-29 18:23:44 -07001304 // Convert the object to cross-interpreter data.
1305 _PyCrossInterpreterData *data = PyMem_NEW(_PyCrossInterpreterData, 1);
1306 if (data == NULL) {
1307 PyThread_release_lock(mutex);
1308 return -1;
1309 }
1310 if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
Victor Stinner4d61e6e2019-03-04 14:21:28 +01001311 PyThread_release_lock(mutex);
Eric Snowc11183c2019-03-15 16:35:46 -06001312 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001313 return -1;
1314 }
1315
1316 // Add the data to the channel.
Eric Snowc11183c2019-03-15 16:35:46 -06001317 int res = _channel_add(chan, PyInterpreterState_GetID(interp), data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001318 PyThread_release_lock(mutex);
1319 if (res != 0) {
1320 _PyCrossInterpreterData_Release(data);
1321 PyMem_Free(data);
1322 return -1;
1323 }
1324
1325 return 0;
1326}
1327
1328static PyObject *
1329_channel_recv(_channels *channels, int64_t id)
1330{
1331 PyInterpreterState *interp = _get_current();
1332 if (interp == NULL) {
1333 return NULL;
1334 }
1335
1336 // Look up the channel.
1337 PyThread_type_lock mutex = NULL;
1338 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1339 if (chan == NULL) {
1340 return NULL;
1341 }
1342 // Past this point we are responsible for releasing the mutex.
1343
1344 // Pop off the next item from the channel.
Eric Snowc11183c2019-03-15 16:35:46 -06001345 _PyCrossInterpreterData *data = _channel_next(chan, PyInterpreterState_GetID(interp));
Eric Snow7f8bfc92018-01-29 18:23:44 -07001346 PyThread_release_lock(mutex);
1347 if (data == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001348 return NULL;
1349 }
1350
1351 // Convert the data back to an object.
1352 PyObject *obj = _PyCrossInterpreterData_NewObject(data);
Eric Snow5e8c6912020-04-28 17:11:32 -06001353 _PyCrossInterpreterData_Release(data);
1354 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001355 if (obj == NULL) {
1356 return NULL;
1357 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001358
1359 return obj;
1360}
1361
1362static int
1363_channel_drop(_channels *channels, int64_t id, int send, int recv)
1364{
1365 PyInterpreterState *interp = _get_current();
1366 if (interp == NULL) {
1367 return -1;
1368 }
1369
1370 // Look up the channel.
1371 PyThread_type_lock mutex = NULL;
1372 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1373 if (chan == NULL) {
1374 return -1;
1375 }
1376 // Past this point we are responsible for releasing the mutex.
1377
1378 // Close one or both of the two ends.
Eric Snowc11183c2019-03-15 16:35:46 -06001379 int res = _channel_close_interpreter(chan, PyInterpreterState_GetID(interp), send-recv);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001380 PyThread_release_lock(mutex);
1381 return res;
1382}
1383
1384static int
Eric Snow3ab01362018-05-17 10:27:09 -04001385_channel_close(_channels *channels, int64_t id, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001386{
Eric Snow3ab01362018-05-17 10:27:09 -04001387 return _channels_close(channels, id, NULL, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001388}
1389
Lewis Gaulf7bbf582020-04-29 01:18:42 +01001390static int
1391_channel_is_associated(_channels *channels, int64_t cid, int64_t interp,
1392 int send)
1393{
1394 _PyChannelState *chan = _channels_lookup(channels, cid, NULL);
1395 if (chan == NULL) {
1396 return -1;
1397 } else if (send && chan->closing != NULL) {
1398 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
1399 return -1;
1400 }
1401
1402 _channelend *end = _channelend_find(send ? chan->ends->send : chan->ends->recv,
1403 interp, NULL);
1404
1405 return (end != NULL && end->open);
1406}
1407
Eric Snow7f8bfc92018-01-29 18:23:44 -07001408/* ChannelID class */
1409
Eric Snow7f8bfc92018-01-29 18:23:44 -07001410static PyTypeObject ChannelIDtype;
1411
1412typedef struct channelid {
1413 PyObject_HEAD
1414 int64_t id;
1415 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001416 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001417 _channels *channels;
1418} channelid;
1419
Serhiy Storchakabf169912019-09-13 22:50:27 +03001420static int
1421channel_id_converter(PyObject *arg, void *ptr)
1422{
1423 int64_t cid;
1424 if (PyObject_TypeCheck(arg, &ChannelIDtype)) {
1425 cid = ((channelid *)arg)->id;
1426 }
1427 else if (PyIndex_Check(arg)) {
1428 cid = PyLong_AsLongLong(arg);
1429 if (cid == -1 && PyErr_Occurred()) {
1430 return 0;
1431 }
1432 if (cid < 0) {
1433 PyErr_Format(PyExc_ValueError,
1434 "channel ID must be a non-negative int, got %R", arg);
1435 return 0;
1436 }
1437 }
1438 else {
1439 PyErr_Format(PyExc_TypeError,
1440 "channel ID must be an int, got %.100s",
Victor Stinnerdaa97562020-02-07 03:37:06 +01001441 Py_TYPE(arg)->tp_name);
Serhiy Storchakabf169912019-09-13 22:50:27 +03001442 return 0;
1443 }
1444 *(int64_t *)ptr = cid;
1445 return 1;
1446}
1447
Eric Snow7f8bfc92018-01-29 18:23:44 -07001448static channelid *
1449newchannelid(PyTypeObject *cls, int64_t cid, int end, _channels *channels,
Eric Snow6d2cd902018-05-16 15:04:57 -04001450 int force, int resolve)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001451{
1452 channelid *self = PyObject_New(channelid, cls);
1453 if (self == NULL) {
1454 return NULL;
1455 }
1456 self->id = cid;
1457 self->end = end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001458 self->resolve = resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001459 self->channels = channels;
1460
1461 if (_channels_add_id_object(channels, cid) != 0) {
1462 if (force && PyErr_ExceptionMatches(ChannelNotFoundError)) {
1463 PyErr_Clear();
1464 }
1465 else {
1466 Py_DECREF((PyObject *)self);
1467 return NULL;
1468 }
1469 }
1470
1471 return self;
1472}
1473
1474static _channels * _global_channels(void);
1475
1476static PyObject *
1477channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
1478{
Eric Snow6d2cd902018-05-16 15:04:57 -04001479 static char *kwlist[] = {"id", "send", "recv", "force", "_resolve", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03001480 int64_t cid;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001481 int send = -1;
1482 int recv = -1;
1483 int force = 0;
Eric Snow6d2cd902018-05-16 15:04:57 -04001484 int resolve = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001485 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03001486 "O&|$pppp:ChannelID.__new__", kwlist,
1487 channel_id_converter, &cid, &send, &recv, &force, &resolve))
Eric Snow7f8bfc92018-01-29 18:23:44 -07001488 return NULL;
1489
Eric Snow7f8bfc92018-01-29 18:23:44 -07001490 // Handle "send" and "recv".
1491 if (send == 0 && recv == 0) {
1492 PyErr_SetString(PyExc_ValueError,
1493 "'send' and 'recv' cannot both be False");
1494 return NULL;
1495 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001496
Eric Snow7f8bfc92018-01-29 18:23:44 -07001497 int end = 0;
1498 if (send == 1) {
1499 if (recv == 0 || recv == -1) {
1500 end = CHANNEL_SEND;
1501 }
1502 }
1503 else if (recv == 1) {
1504 end = CHANNEL_RECV;
1505 }
1506
Eric Snow6d2cd902018-05-16 15:04:57 -04001507 return (PyObject *)newchannelid(cls, cid, end, _global_channels(),
1508 force, resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001509}
1510
1511static void
1512channelid_dealloc(PyObject *v)
1513{
1514 int64_t cid = ((channelid *)v)->id;
1515 _channels *channels = ((channelid *)v)->channels;
1516 Py_TYPE(v)->tp_free(v);
1517
1518 _channels_drop_id_object(channels, cid);
1519}
1520
1521static PyObject *
1522channelid_repr(PyObject *self)
1523{
1524 PyTypeObject *type = Py_TYPE(self);
1525 const char *name = _PyType_Name(type);
1526
1527 channelid *cid = (channelid *)self;
1528 const char *fmt;
1529 if (cid->end == CHANNEL_SEND) {
Eric Snowab4a1982018-06-13 08:02:39 -06001530 fmt = "%s(%" PRId64 ", send=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001531 }
1532 else if (cid->end == CHANNEL_RECV) {
Eric Snowab4a1982018-06-13 08:02:39 -06001533 fmt = "%s(%" PRId64 ", recv=True)";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001534 }
1535 else {
Eric Snowab4a1982018-06-13 08:02:39 -06001536 fmt = "%s(%" PRId64 ")";
Eric Snow7f8bfc92018-01-29 18:23:44 -07001537 }
1538 return PyUnicode_FromFormat(fmt, name, cid->id);
1539}
1540
Eric Snow6d2cd902018-05-16 15:04:57 -04001541static PyObject *
1542channelid_str(PyObject *self)
1543{
1544 channelid *cid = (channelid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06001545 return PyUnicode_FromFormat("%" PRId64 "", cid->id);
Eric Snow6d2cd902018-05-16 15:04:57 -04001546}
1547
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001548static PyObject *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001549channelid_int(PyObject *self)
1550{
1551 channelid *cid = (channelid *)self;
1552 return PyLong_FromLongLong(cid->id);
1553}
1554
1555static PyNumberMethods channelid_as_number = {
1556 0, /* nb_add */
1557 0, /* nb_subtract */
1558 0, /* nb_multiply */
1559 0, /* nb_remainder */
1560 0, /* nb_divmod */
1561 0, /* nb_power */
1562 0, /* nb_negative */
1563 0, /* nb_positive */
1564 0, /* nb_absolute */
1565 0, /* nb_bool */
1566 0, /* nb_invert */
1567 0, /* nb_lshift */
1568 0, /* nb_rshift */
1569 0, /* nb_and */
1570 0, /* nb_xor */
1571 0, /* nb_or */
1572 (unaryfunc)channelid_int, /* nb_int */
1573 0, /* nb_reserved */
1574 0, /* nb_float */
1575
1576 0, /* nb_inplace_add */
1577 0, /* nb_inplace_subtract */
1578 0, /* nb_inplace_multiply */
1579 0, /* nb_inplace_remainder */
1580 0, /* nb_inplace_power */
1581 0, /* nb_inplace_lshift */
1582 0, /* nb_inplace_rshift */
1583 0, /* nb_inplace_and */
1584 0, /* nb_inplace_xor */
1585 0, /* nb_inplace_or */
1586
1587 0, /* nb_floor_divide */
1588 0, /* nb_true_divide */
1589 0, /* nb_inplace_floor_divide */
1590 0, /* nb_inplace_true_divide */
1591
1592 (unaryfunc)channelid_int, /* nb_index */
1593};
1594
1595static Py_hash_t
1596channelid_hash(PyObject *self)
1597{
1598 channelid *cid = (channelid *)self;
1599 PyObject *id = PyLong_FromLongLong(cid->id);
1600 if (id == NULL) {
1601 return -1;
1602 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001603 Py_hash_t hash = PyObject_Hash(id);
1604 Py_DECREF(id);
1605 return hash;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001606}
1607
1608static PyObject *
1609channelid_richcompare(PyObject *self, PyObject *other, int op)
1610{
1611 if (op != Py_EQ && op != Py_NE) {
1612 Py_RETURN_NOTIMPLEMENTED;
1613 }
1614
1615 if (!PyObject_TypeCheck(self, &ChannelIDtype)) {
1616 Py_RETURN_NOTIMPLEMENTED;
1617 }
1618
1619 channelid *cid = (channelid *)self;
1620 int equal;
1621 if (PyObject_TypeCheck(other, &ChannelIDtype)) {
1622 channelid *othercid = (channelid *)other;
Serhiy Storchakabf169912019-09-13 22:50:27 +03001623 equal = (cid->end == othercid->end) && (cid->id == othercid->id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001624 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03001625 else if (PyLong_Check(other)) {
1626 /* Fast path */
1627 int overflow;
1628 long long othercid = PyLong_AsLongLongAndOverflow(other, &overflow);
1629 if (othercid == -1 && PyErr_Occurred()) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001630 return NULL;
1631 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03001632 equal = !overflow && (othercid >= 0) && (cid->id == othercid);
1633 }
1634 else if (PyNumber_Check(other)) {
1635 PyObject *pyid = PyLong_FromLongLong(cid->id);
1636 if (pyid == NULL) {
1637 return NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001638 }
Serhiy Storchakabf169912019-09-13 22:50:27 +03001639 PyObject *res = PyObject_RichCompare(pyid, other, op);
1640 Py_DECREF(pyid);
1641 return res;
1642 }
1643 else {
1644 Py_RETURN_NOTIMPLEMENTED;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001645 }
1646
1647 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
1648 Py_RETURN_TRUE;
1649 }
1650 Py_RETURN_FALSE;
1651}
1652
Eric Snowab4a1982018-06-13 08:02:39 -06001653static PyObject *
1654_channel_from_cid(PyObject *cid, int end)
1655{
1656 PyObject *highlevel = PyImport_ImportModule("interpreters");
1657 if (highlevel == NULL) {
1658 PyErr_Clear();
1659 highlevel = PyImport_ImportModule("test.support.interpreters");
1660 if (highlevel == NULL) {
1661 return NULL;
1662 }
1663 }
1664 const char *clsname = (end == CHANNEL_RECV) ? "RecvChannel" :
1665 "SendChannel";
1666 PyObject *cls = PyObject_GetAttrString(highlevel, clsname);
1667 Py_DECREF(highlevel);
1668 if (cls == NULL) {
1669 return NULL;
1670 }
1671 PyObject *chan = PyObject_CallFunctionObjArgs(cls, cid, NULL);
1672 Py_DECREF(cls);
1673 if (chan == NULL) {
1674 return NULL;
1675 }
1676 return chan;
1677}
1678
Eric Snow7f8bfc92018-01-29 18:23:44 -07001679struct _channelid_xid {
1680 int64_t id;
1681 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001682 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001683};
1684
1685static PyObject *
1686_channelid_from_xid(_PyCrossInterpreterData *data)
1687{
1688 struct _channelid_xid *xid = (struct _channelid_xid *)data->data;
Eric Snow6d2cd902018-05-16 15:04:57 -04001689 // Note that we do not preserve the "resolve" flag.
1690 PyObject *cid = (PyObject *)newchannelid(&ChannelIDtype, xid->id, xid->end,
1691 _global_channels(), 0, 0);
1692 if (xid->end == 0) {
1693 return cid;
1694 }
1695 if (!xid->resolve) {
1696 return cid;
1697 }
1698
1699 /* Try returning a high-level channel end but fall back to the ID. */
Eric Snowab4a1982018-06-13 08:02:39 -06001700 PyObject *chan = _channel_from_cid(cid, xid->end);
Eric Snow6d2cd902018-05-16 15:04:57 -04001701 if (chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001702 PyErr_Clear();
1703 return cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04001704 }
1705 Py_DECREF(cid);
1706 return chan;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001707}
1708
1709static int
1710_channelid_shared(PyObject *obj, _PyCrossInterpreterData *data)
1711{
1712 struct _channelid_xid *xid = PyMem_NEW(struct _channelid_xid, 1);
1713 if (xid == NULL) {
1714 return -1;
1715 }
1716 xid->id = ((channelid *)obj)->id;
1717 xid->end = ((channelid *)obj)->end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001718 xid->resolve = ((channelid *)obj)->resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001719
1720 data->data = xid;
Eric Snow63799132018-06-01 18:45:20 -06001721 Py_INCREF(obj);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001722 data->obj = obj;
1723 data->new_object = _channelid_from_xid;
1724 data->free = PyMem_Free;
1725 return 0;
1726}
1727
1728static PyObject *
1729channelid_end(PyObject *self, void *end)
1730{
1731 int force = 1;
1732 channelid *cid = (channelid *)self;
1733 if (end != NULL) {
1734 return (PyObject *)newchannelid(Py_TYPE(self), cid->id, *(int *)end,
Eric Snow6d2cd902018-05-16 15:04:57 -04001735 cid->channels, force, cid->resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001736 }
1737
1738 if (cid->end == CHANNEL_SEND) {
1739 return PyUnicode_InternFromString("send");
1740 }
1741 if (cid->end == CHANNEL_RECV) {
1742 return PyUnicode_InternFromString("recv");
1743 }
1744 return PyUnicode_InternFromString("both");
1745}
1746
1747static int _channelid_end_send = CHANNEL_SEND;
1748static int _channelid_end_recv = CHANNEL_RECV;
1749
1750static PyGetSetDef channelid_getsets[] = {
1751 {"end", (getter)channelid_end, NULL,
1752 PyDoc_STR("'send', 'recv', or 'both'")},
1753 {"send", (getter)channelid_end, NULL,
1754 PyDoc_STR("the 'send' end of the channel"), &_channelid_end_send},
1755 {"recv", (getter)channelid_end, NULL,
1756 PyDoc_STR("the 'recv' end of the channel"), &_channelid_end_recv},
1757 {NULL}
1758};
1759
1760PyDoc_STRVAR(channelid_doc,
1761"A channel ID identifies a channel and may be used as an int.");
1762
1763static PyTypeObject ChannelIDtype = {
1764 PyVarObject_HEAD_INIT(&PyType_Type, 0)
1765 "_xxsubinterpreters.ChannelID", /* tp_name */
Peter Eisentraut0e0bc4e2018-09-10 18:46:08 +02001766 sizeof(channelid), /* tp_basicsize */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001767 0, /* tp_itemsize */
1768 (destructor)channelid_dealloc, /* tp_dealloc */
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001769 0, /* tp_vectorcall_offset */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001770 0, /* tp_getattr */
1771 0, /* tp_setattr */
1772 0, /* tp_as_async */
1773 (reprfunc)channelid_repr, /* tp_repr */
1774 &channelid_as_number, /* tp_as_number */
1775 0, /* tp_as_sequence */
1776 0, /* tp_as_mapping */
1777 channelid_hash, /* tp_hash */
1778 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04001779 (reprfunc)channelid_str, /* tp_str */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001780 0, /* tp_getattro */
1781 0, /* tp_setattro */
1782 0, /* tp_as_buffer */
Serhiy Storchakabf169912019-09-13 22:50:27 +03001783 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001784 channelid_doc, /* tp_doc */
1785 0, /* tp_traverse */
1786 0, /* tp_clear */
1787 channelid_richcompare, /* tp_richcompare */
1788 0, /* tp_weaklistoffset */
1789 0, /* tp_iter */
1790 0, /* tp_iternext */
1791 0, /* tp_methods */
1792 0, /* tp_members */
1793 channelid_getsets, /* tp_getset */
1794 0, /* tp_base */
1795 0, /* tp_dict */
1796 0, /* tp_descr_get */
1797 0, /* tp_descr_set */
1798 0, /* tp_dictoffset */
1799 0, /* tp_init */
1800 0, /* tp_alloc */
1801 // Note that we do not set tp_new to channelid_new. Instead we
1802 // set it to NULL, meaning it cannot be instantiated from Python
1803 // code. We do this because there is a strong relationship between
1804 // channel IDs and the channel lifecycle, so this limitation avoids
1805 // related complications.
1806 NULL, /* tp_new */
1807};
1808
Eric Snow4e9da0d2018-02-02 21:49:49 -07001809
1810/* interpreter-specific code ************************************************/
1811
1812static PyObject * RunFailedError = NULL;
1813
1814static int
1815interp_exceptions_init(PyObject *ns)
1816{
1817 // XXX Move the exceptions into per-module memory?
1818
1819 if (RunFailedError == NULL) {
1820 // An uncaught exception came out of interp_run_string().
1821 RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
1822 PyExc_RuntimeError, NULL);
1823 if (RunFailedError == NULL) {
1824 return -1;
1825 }
1826 if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
1827 return -1;
1828 }
1829 }
1830
1831 return 0;
1832}
Eric Snow7f8bfc92018-01-29 18:23:44 -07001833
Eric Snow7f8bfc92018-01-29 18:23:44 -07001834static int
1835_is_running(PyInterpreterState *interp)
1836{
1837 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1838 if (PyThreadState_Next(tstate) != NULL) {
1839 PyErr_SetString(PyExc_RuntimeError,
1840 "interpreter has more than one thread");
1841 return -1;
1842 }
Victor Stinner4386b902020-04-29 03:01:43 +02001843
1844 assert(!PyErr_Occurred());
Victor Stinner30723382020-03-25 19:52:02 +01001845 PyFrameObject *frame = PyThreadState_GetFrame(tstate);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001846 if (frame == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001847 return 0;
1848 }
Victor Stinner4386b902020-04-29 03:01:43 +02001849
1850 int executing = (int)(frame->f_executing);
1851 Py_DECREF(frame);
1852
1853 return executing;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001854}
1855
1856static int
1857_ensure_not_running(PyInterpreterState *interp)
1858{
1859 int is_running = _is_running(interp);
1860 if (is_running < 0) {
1861 return -1;
1862 }
1863 if (is_running) {
1864 PyErr_Format(PyExc_RuntimeError, "interpreter already running");
1865 return -1;
1866 }
1867 return 0;
1868}
1869
1870static int
1871_run_script(PyInterpreterState *interp, const char *codestr,
Victor Stinnerf2c3b682020-05-14 18:46:24 +02001872 _sharedns *shared, _sharedexception **exc)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001873{
Victor Stinnerf2c3b682020-05-14 18:46:24 +02001874 PyObject *exctype = NULL;
1875 PyObject *excval = NULL;
1876 PyObject *tb = NULL;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001877
Eric Snowc11183c2019-03-15 16:35:46 -06001878 PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001879 if (main_mod == NULL) {
1880 goto error;
1881 }
1882 PyObject *ns = PyModule_GetDict(main_mod); // borrowed
1883 Py_DECREF(main_mod);
1884 if (ns == NULL) {
1885 goto error;
1886 }
1887 Py_INCREF(ns);
1888
1889 // Apply the cross-interpreter data.
1890 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001891 if (_sharedns_apply(shared, ns) != 0) {
1892 Py_DECREF(ns);
1893 goto error;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001894 }
1895 }
1896
1897 // Run the string (see PyRun_SimpleStringFlags).
1898 PyObject *result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
1899 Py_DECREF(ns);
1900 if (result == NULL) {
1901 goto error;
1902 }
1903 else {
1904 Py_DECREF(result); // We throw away the result.
1905 }
1906
Victor Stinnerf2c3b682020-05-14 18:46:24 +02001907 *exc = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001908 return 0;
1909
1910error:
Victor Stinnerf2c3b682020-05-14 18:46:24 +02001911 PyErr_Fetch(&exctype, &excval, &tb);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001912
Victor Stinnerf2c3b682020-05-14 18:46:24 +02001913 _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb);
1914 Py_XDECREF(exctype);
1915 Py_XDECREF(excval);
1916 Py_XDECREF(tb);
Eric Snowa1d9e0a2020-05-07 08:56:01 -06001917 if (sharedexc == NULL) {
Victor Stinnerf2c3b682020-05-14 18:46:24 +02001918 fprintf(stderr, "RunFailedError: script raised an uncaught exception");
1919 PyErr_Clear();
1920 sharedexc = NULL;
1921 }
1922 else {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001923 assert(!PyErr_Occurred());
1924 }
Victor Stinnerf2c3b682020-05-14 18:46:24 +02001925 *exc = sharedexc;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001926 return -1;
1927}
1928
1929static int
1930_run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
1931 PyObject *shareables)
1932{
1933 if (_ensure_not_running(interp) < 0) {
1934 return -1;
1935 }
1936
Eric Snow4e9da0d2018-02-02 21:49:49 -07001937 _sharedns *shared = _get_shared_ns(shareables);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001938 if (shared == NULL && PyErr_Occurred()) {
1939 return -1;
1940 }
1941
Victor Stinnerfb2c7c42020-05-05 20:33:06 +02001942#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
1943 // Switch to interpreter.
1944 PyThreadState *new_tstate = PyInterpreterState_ThreadHead(interp);
1945 PyThreadState *save1 = PyEval_SaveThread();
1946
1947 (void)PyThreadState_Swap(new_tstate);
1948
1949 // Run the script.
1950 _sharedexception *exc = NULL;
1951 int result = _run_script(interp, codestr, shared, &exc);
1952
1953 // Switch back.
1954 PyEval_RestoreThread(save1);
1955#else
Eric Snow7f8bfc92018-01-29 18:23:44 -07001956 // Switch to interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07001957 PyThreadState *save_tstate = NULL;
Victor Stinnerbe793732020-03-13 18:15:33 +01001958 if (interp != PyInterpreterState_Get()) {
Eric Snowf53d9f22018-02-20 16:30:17 -07001959 // XXX Using the "head" thread isn't strictly correct.
1960 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1961 // XXX Possible GILState issues?
1962 save_tstate = PyThreadState_Swap(tstate);
1963 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001964
1965 // Run the script.
Victor Stinnerf2c3b682020-05-14 18:46:24 +02001966 _sharedexception *exc = NULL;
1967 int result = _run_script(interp, codestr, shared, &exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001968
1969 // Switch back.
1970 if (save_tstate != NULL) {
1971 PyThreadState_Swap(save_tstate);
1972 }
Victor Stinnerfb2c7c42020-05-05 20:33:06 +02001973#endif
Eric Snow7f8bfc92018-01-29 18:23:44 -07001974
1975 // Propagate any exception out to the caller.
Victor Stinnerf2c3b682020-05-14 18:46:24 +02001976 if (exc != NULL) {
1977 _sharedexception_apply(exc, RunFailedError);
1978 _sharedexception_free(exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001979 }
1980 else if (result != 0) {
1981 // We were unable to allocate a shared exception.
1982 PyErr_NoMemory();
1983 }
1984
1985 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001986 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001987 }
1988
1989 return result;
1990}
1991
1992
1993/* module level code ********************************************************/
1994
1995/* globals is the process-global state for the module. It holds all
1996 the data that we need to share between interpreters, so it cannot
1997 hold PyObject values. */
1998static struct globals {
1999 _channels channels;
2000} _globals = {{0}};
2001
2002static int
2003_init_globals(void)
2004{
2005 if (_channels_init(&_globals.channels) != 0) {
2006 return -1;
2007 }
2008 return 0;
2009}
2010
2011static _channels *
2012_global_channels(void) {
2013 return &_globals.channels;
2014}
2015
2016static PyObject *
Victor Stinner252346a2020-05-01 11:33:44 +02002017interp_create(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002018{
Victor Stinner252346a2020-05-01 11:33:44 +02002019
2020 static char *kwlist[] = {"isolated", NULL};
2021 int isolated = 1;
2022 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$i:create", kwlist,
2023 &isolated)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002024 return NULL;
2025 }
2026
2027 // Create and initialize the new interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07002028 PyThreadState *save_tstate = PyThreadState_Swap(NULL);
2029 // XXX Possible GILState issues?
Victor Stinner252346a2020-05-01 11:33:44 +02002030 PyThreadState *tstate = _Py_NewInterpreter(isolated);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002031 PyThreadState_Swap(save_tstate);
2032 if (tstate == NULL) {
2033 /* Since no new thread state was created, there is no exception to
2034 propagate; raise a fresh one after swapping in the old thread
2035 state. */
2036 PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
2037 return NULL;
2038 }
Victor Stinner30723382020-03-25 19:52:02 +01002039 PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate);
2040 PyObject *idobj = _PyInterpreterState_GetIDObject(interp);
Eric Snowc11183c2019-03-15 16:35:46 -06002041 if (idobj == NULL) {
2042 // XXX Possible GILState issues?
2043 save_tstate = PyThreadState_Swap(tstate);
2044 Py_EndInterpreter(tstate);
2045 PyThreadState_Swap(save_tstate);
2046 return NULL;
2047 }
Victor Stinner30723382020-03-25 19:52:02 +01002048 _PyInterpreterState_RequireIDRef(interp, 1);
Eric Snowc11183c2019-03-15 16:35:46 -06002049 return idobj;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002050}
2051
2052PyDoc_STRVAR(create_doc,
2053"create() -> ID\n\
2054\n\
2055Create a new interpreter and return a unique generated ID.");
2056
2057
2058static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002059interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002060{
Eric Snow6d2cd902018-05-16 15:04:57 -04002061 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002062 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002063 // XXX Use "L" for id?
2064 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2065 "O:destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002066 return NULL;
2067 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002068
2069 // Look up the interpreter.
Eric Snowc11183c2019-03-15 16:35:46 -06002070 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002071 if (interp == NULL) {
2072 return NULL;
2073 }
2074
2075 // Ensure we don't try to destroy the current interpreter.
2076 PyInterpreterState *current = _get_current();
2077 if (current == NULL) {
2078 return NULL;
2079 }
2080 if (interp == current) {
2081 PyErr_SetString(PyExc_RuntimeError,
2082 "cannot destroy the current interpreter");
2083 return NULL;
2084 }
2085
2086 // Ensure the interpreter isn't running.
2087 /* XXX We *could* support destroying a running interpreter but
2088 aren't going to worry about it for now. */
2089 if (_ensure_not_running(interp) < 0) {
2090 return NULL;
2091 }
2092
2093 // Destroy the interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07002094 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
2095 // XXX Possible GILState issues?
2096 PyThreadState *save_tstate = PyThreadState_Swap(tstate);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002097 Py_EndInterpreter(tstate);
2098 PyThreadState_Swap(save_tstate);
2099
2100 Py_RETURN_NONE;
2101}
2102
2103PyDoc_STRVAR(destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002104"destroy(id)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002105\n\
2106Destroy the identified interpreter.\n\
2107\n\
2108Attempting to destroy the current interpreter results in a RuntimeError.\n\
2109So does an unrecognized ID.");
2110
2111
2112static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302113interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002114{
2115 PyObject *ids, *id;
2116 PyInterpreterState *interp;
2117
2118 ids = PyList_New(0);
2119 if (ids == NULL) {
2120 return NULL;
2121 }
2122
2123 interp = PyInterpreterState_Head();
2124 while (interp != NULL) {
Eric Snowc11183c2019-03-15 16:35:46 -06002125 id = _PyInterpreterState_GetIDObject(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002126 if (id == NULL) {
2127 Py_DECREF(ids);
2128 return NULL;
2129 }
2130 // insert at front of list
Eric Snow4e9da0d2018-02-02 21:49:49 -07002131 int res = PyList_Insert(ids, 0, id);
2132 Py_DECREF(id);
2133 if (res < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002134 Py_DECREF(ids);
2135 return NULL;
2136 }
2137
2138 interp = PyInterpreterState_Next(interp);
2139 }
2140
2141 return ids;
2142}
2143
2144PyDoc_STRVAR(list_all_doc,
2145"list_all() -> [ID]\n\
2146\n\
2147Return a list containing the ID of every existing interpreter.");
2148
2149
2150static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302151interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002152{
2153 PyInterpreterState *interp =_get_current();
2154 if (interp == NULL) {
2155 return NULL;
2156 }
Eric Snowc11183c2019-03-15 16:35:46 -06002157 return _PyInterpreterState_GetIDObject(interp);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002158}
2159
2160PyDoc_STRVAR(get_current_doc,
2161"get_current() -> ID\n\
2162\n\
2163Return the ID of current interpreter.");
2164
2165
2166static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302167interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002168{
2169 // Currently, 0 is always the main interpreter.
Victor Stinner1a1bd2e2020-04-17 19:13:06 +02002170 int64_t id = 0;
Eric Snowc11183c2019-03-15 16:35:46 -06002171 return _PyInterpreterID_New(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002172}
2173
2174PyDoc_STRVAR(get_main_doc,
2175"get_main() -> ID\n\
2176\n\
2177Return the ID of main interpreter.");
2178
2179
2180static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002181interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002182{
Eric Snow6d2cd902018-05-16 15:04:57 -04002183 static char *kwlist[] = {"id", "script", "shared", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002184 PyObject *id, *code;
2185 PyObject *shared = NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002186 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2187 "OU|O:run_string", kwlist,
2188 &id, &code, &shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002189 return NULL;
2190 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002191
2192 // Look up the interpreter.
Eric Snowc11183c2019-03-15 16:35:46 -06002193 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002194 if (interp == NULL) {
2195 return NULL;
2196 }
2197
2198 // Extract code.
2199 Py_ssize_t size;
2200 const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
2201 if (codestr == NULL) {
2202 return NULL;
2203 }
2204 if (strlen(codestr) != (size_t)size) {
2205 PyErr_SetString(PyExc_ValueError,
2206 "source code string cannot contain null bytes");
2207 return NULL;
2208 }
2209
2210 // Run the code in the interpreter.
2211 if (_run_script_in_interpreter(interp, codestr, shared) != 0) {
2212 return NULL;
2213 }
2214 Py_RETURN_NONE;
2215}
2216
2217PyDoc_STRVAR(run_string_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002218"run_string(id, script, shared)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002219\n\
2220Execute the provided string in the identified interpreter.\n\
2221\n\
2222See PyRun_SimpleStrings.");
2223
2224
2225static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002226object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002227{
Eric Snow6d2cd902018-05-16 15:04:57 -04002228 static char *kwlist[] = {"obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002229 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002230 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2231 "O:is_shareable", kwlist, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002232 return NULL;
2233 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002234
Eric Snow7f8bfc92018-01-29 18:23:44 -07002235 if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
2236 Py_RETURN_TRUE;
2237 }
2238 PyErr_Clear();
2239 Py_RETURN_FALSE;
2240}
2241
2242PyDoc_STRVAR(is_shareable_doc,
2243"is_shareable(obj) -> bool\n\
2244\n\
2245Return True if the object's data may be shared between interpreters and\n\
2246False otherwise.");
2247
2248
2249static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002250interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002251{
Eric Snow6d2cd902018-05-16 15:04:57 -04002252 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002253 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002254 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2255 "O:is_running", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002256 return NULL;
2257 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002258
Eric Snowc11183c2019-03-15 16:35:46 -06002259 PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002260 if (interp == NULL) {
2261 return NULL;
2262 }
2263 int is_running = _is_running(interp);
2264 if (is_running < 0) {
2265 return NULL;
2266 }
2267 if (is_running) {
2268 Py_RETURN_TRUE;
2269 }
2270 Py_RETURN_FALSE;
2271}
2272
2273PyDoc_STRVAR(is_running_doc,
2274"is_running(id) -> bool\n\
2275\n\
2276Return whether or not the identified interpreter is running.");
2277
2278static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302279channel_create(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002280{
2281 int64_t cid = _channel_create(&_globals.channels);
2282 if (cid < 0) {
2283 return NULL;
2284 }
2285 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, cid, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002286 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002287 if (id == NULL) {
2288 if (_channel_destroy(&_globals.channels, cid) != 0) {
2289 // XXX issue a warning?
2290 }
2291 return NULL;
2292 }
2293 assert(((channelid *)id)->channels != NULL);
2294 return id;
2295}
2296
2297PyDoc_STRVAR(channel_create_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002298"channel_create() -> cid\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002299\n\
2300Create a new cross-interpreter channel and return a unique generated ID.");
2301
2302static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002303channel_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002304{
Eric Snow6d2cd902018-05-16 15:04:57 -04002305 static char *kwlist[] = {"cid", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002306 int64_t cid;
2307 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_destroy", kwlist,
2308 channel_id_converter, &cid)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002309 return NULL;
2310 }
2311
2312 if (_channel_destroy(&_globals.channels, cid) != 0) {
2313 return NULL;
2314 }
2315 Py_RETURN_NONE;
2316}
2317
2318PyDoc_STRVAR(channel_destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002319"channel_destroy(cid)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002320\n\
2321Close and finalize the channel. Afterward attempts to use the channel\n\
2322will behave as though it never existed.");
2323
2324static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302325channel_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002326{
2327 int64_t count = 0;
2328 int64_t *cids = _channels_list_all(&_globals.channels, &count);
2329 if (cids == NULL) {
2330 if (count == 0) {
2331 return PyList_New(0);
2332 }
2333 return NULL;
2334 }
2335 PyObject *ids = PyList_New((Py_ssize_t)count);
2336 if (ids == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07002337 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002338 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002339 int64_t *cur = cids;
2340 for (int64_t i=0; i < count; cur++, i++) {
2341 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cur, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002342 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002343 if (id == NULL) {
2344 Py_DECREF(ids);
2345 ids = NULL;
2346 break;
2347 }
2348 PyList_SET_ITEM(ids, i, id);
2349 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002350
2351finally:
2352 PyMem_Free(cids);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002353 return ids;
2354}
2355
2356PyDoc_STRVAR(channel_list_all_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002357"channel_list_all() -> [cid]\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002358\n\
2359Return the list of all IDs for active channels.");
2360
2361static PyObject *
Lewis Gaulf7bbf582020-04-29 01:18:42 +01002362channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
2363{
2364 static char *kwlist[] = {"cid", "send", NULL};
2365 int64_t cid; /* Channel ID */
2366 int send = 0; /* Send or receive end? */
2367 int64_t id;
2368 PyObject *ids, *id_obj;
2369 PyInterpreterState *interp;
2370
2371 if (!PyArg_ParseTupleAndKeywords(
2372 args, kwds, "O&$p:channel_list_interpreters",
2373 kwlist, channel_id_converter, &cid, &send)) {
2374 return NULL;
2375 }
2376
2377 ids = PyList_New(0);
2378 if (ids == NULL) {
2379 goto except;
2380 }
2381
2382 interp = PyInterpreterState_Head();
2383 while (interp != NULL) {
2384 id = PyInterpreterState_GetID(interp);
2385 assert(id >= 0);
2386 int res = _channel_is_associated(&_globals.channels, cid, id, send);
2387 if (res < 0) {
2388 goto except;
2389 }
2390 if (res) {
2391 id_obj = _PyInterpreterState_GetIDObject(interp);
2392 if (id_obj == NULL) {
2393 goto except;
2394 }
2395 res = PyList_Insert(ids, 0, id_obj);
2396 Py_DECREF(id_obj);
2397 if (res < 0) {
2398 goto except;
2399 }
2400 }
2401 interp = PyInterpreterState_Next(interp);
2402 }
2403
2404 goto finally;
2405
2406except:
2407 Py_XDECREF(ids);
2408 ids = NULL;
2409
2410finally:
2411 return ids;
2412}
2413
2414PyDoc_STRVAR(channel_list_interpreters_doc,
2415"channel_list_interpreters(cid, *, send) -> [id]\n\
2416\n\
2417Return the list of all interpreter IDs associated with an end of the channel.\n\
2418\n\
2419The 'send' argument should be a boolean indicating whether to use the send or\n\
2420receive end.");
2421
2422
2423static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002424channel_send(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002425{
Eric Snow6d2cd902018-05-16 15:04:57 -04002426 static char *kwlist[] = {"cid", "obj", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002427 int64_t cid;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002428 PyObject *obj;
Serhiy Storchakabf169912019-09-13 22:50:27 +03002429 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O:channel_send", kwlist,
2430 channel_id_converter, &cid, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002431 return NULL;
2432 }
2433
2434 if (_channel_send(&_globals.channels, cid, obj) != 0) {
2435 return NULL;
2436 }
2437 Py_RETURN_NONE;
2438}
2439
2440PyDoc_STRVAR(channel_send_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002441"channel_send(cid, obj)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002442\n\
2443Add the object's data to the channel's queue.");
2444
2445static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002446channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002447{
Eric Snow5e8c6912020-04-28 17:11:32 -06002448 static char *kwlist[] = {"cid", "default", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002449 int64_t cid;
Eric Snow5e8c6912020-04-28 17:11:32 -06002450 PyObject *dflt = NULL;
2451 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O:channel_recv", kwlist,
2452 channel_id_converter, &cid, &dflt)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002453 return NULL;
2454 }
Eric Snow5e8c6912020-04-28 17:11:32 -06002455 Py_XINCREF(dflt);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002456
Eric Snow5e8c6912020-04-28 17:11:32 -06002457 PyObject *obj = _channel_recv(&_globals.channels, cid);
2458 if (obj != NULL) {
2459 Py_XDECREF(dflt);
2460 return obj;
2461 } else if (PyErr_Occurred()) {
2462 Py_XDECREF(dflt);
2463 return NULL;
2464 } else if (dflt != NULL) {
2465 return dflt;
2466 } else {
2467 PyErr_Format(ChannelEmptyError, "channel %" PRId64 " is empty", cid);
2468 return NULL;
2469 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002470}
2471
2472PyDoc_STRVAR(channel_recv_doc,
Eric Snow5e8c6912020-04-28 17:11:32 -06002473"channel_recv(cid, [default]) -> obj\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002474\n\
Eric Snow5e8c6912020-04-28 17:11:32 -06002475Return a new object from the data at the front of the channel's queue.\n\
2476\n\
2477If there is nothing to receive then raise ChannelEmptyError, unless\n\
2478a default value is provided. In that case return it.");
Eric Snow7f8bfc92018-01-29 18:23:44 -07002479
2480static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002481channel_close(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002482{
Eric Snow6d2cd902018-05-16 15:04:57 -04002483 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002484 int64_t cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04002485 int send = 0;
2486 int recv = 0;
2487 int force = 0;
2488 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03002489 "O&|$ppp:channel_close", kwlist,
2490 channel_id_converter, &cid, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002491 return NULL;
2492 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002493
Eric Snow3ab01362018-05-17 10:27:09 -04002494 if (_channel_close(&_globals.channels, cid, send-recv, force) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002495 return NULL;
2496 }
2497 Py_RETURN_NONE;
2498}
2499
2500PyDoc_STRVAR(channel_close_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002501"channel_close(cid, *, send=None, recv=None, force=False)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002502\n\
Eric Snow6d2cd902018-05-16 15:04:57 -04002503Close the channel for all interpreters.\n\
2504\n\
2505If the channel is empty then the keyword args are ignored and both\n\
2506ends are immediately closed. Otherwise, if 'force' is True then\n\
2507all queued items are released and both ends are immediately\n\
2508closed.\n\
2509\n\
2510If the channel is not empty *and* 'force' is False then following\n\
2511happens:\n\
2512\n\
2513 * recv is True (regardless of send):\n\
2514 - raise ChannelNotEmptyError\n\
2515 * recv is None and send is None:\n\
2516 - raise ChannelNotEmptyError\n\
2517 * send is True and recv is not True:\n\
2518 - fully close the 'send' end\n\
2519 - close the 'recv' end to interpreters not already receiving\n\
2520 - fully close it once empty\n\
2521\n\
2522Closing an already closed channel results in a ChannelClosedError.\n\
2523\n\
2524Once the channel's ID has no more ref counts in any interpreter\n\
2525the channel will be destroyed.");
Eric Snow7f8bfc92018-01-29 18:23:44 -07002526
2527static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002528channel_release(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002529{
2530 // Note that only the current interpreter is affected.
Eric Snow6d2cd902018-05-16 15:04:57 -04002531 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Serhiy Storchakabf169912019-09-13 22:50:27 +03002532 int64_t cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04002533 int send = 0;
2534 int recv = 0;
2535 int force = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002536 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Serhiy Storchakabf169912019-09-13 22:50:27 +03002537 "O&|$ppp:channel_release", kwlist,
2538 channel_id_converter, &cid, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002539 return NULL;
2540 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002541 if (send == 0 && recv == 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002542 send = 1;
2543 recv = 1;
2544 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002545
2546 // XXX Handle force is True.
2547 // XXX Fix implicit release.
2548
Eric Snow7f8bfc92018-01-29 18:23:44 -07002549 if (_channel_drop(&_globals.channels, cid, send, recv) != 0) {
2550 return NULL;
2551 }
2552 Py_RETURN_NONE;
2553}
2554
Eric Snow6d2cd902018-05-16 15:04:57 -04002555PyDoc_STRVAR(channel_release_doc,
2556"channel_release(cid, *, send=None, recv=None, force=True)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002557\n\
2558Close the channel for the current interpreter. 'send' and 'recv'\n\
2559(bool) may be used to indicate the ends to close. By default both\n\
2560ends are closed. Closing an already closed end is a noop.");
2561
2562static PyObject *
2563channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds)
2564{
2565 return channelid_new(&ChannelIDtype, args, kwds);
2566}
2567
2568static PyMethodDef module_functions[] = {
Victor Stinner252346a2020-05-01 11:33:44 +02002569 {"create", (PyCFunction)(void(*)(void))interp_create,
2570 METH_VARARGS | METH_KEYWORDS, create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002571 {"destroy", (PyCFunction)(void(*)(void))interp_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002572 METH_VARARGS | METH_KEYWORDS, destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302573 {"list_all", interp_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002574 METH_NOARGS, list_all_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302575 {"get_current", interp_get_current,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002576 METH_NOARGS, get_current_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302577 {"get_main", interp_get_main,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002578 METH_NOARGS, get_main_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002579 {"is_running", (PyCFunction)(void(*)(void))interp_is_running,
Eric Snow6d2cd902018-05-16 15:04:57 -04002580 METH_VARARGS | METH_KEYWORDS, is_running_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002581 {"run_string", (PyCFunction)(void(*)(void))interp_run_string,
Eric Snow6d2cd902018-05-16 15:04:57 -04002582 METH_VARARGS | METH_KEYWORDS, run_string_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002583
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002584 {"is_shareable", (PyCFunction)(void(*)(void))object_is_shareable,
Eric Snow6d2cd902018-05-16 15:04:57 -04002585 METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002586
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302587 {"channel_create", channel_create,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002588 METH_NOARGS, channel_create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002589 {"channel_destroy", (PyCFunction)(void(*)(void))channel_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002590 METH_VARARGS | METH_KEYWORDS, channel_destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302591 {"channel_list_all", channel_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002592 METH_NOARGS, channel_list_all_doc},
Lewis Gaulf7bbf582020-04-29 01:18:42 +01002593 {"channel_list_interpreters", (PyCFunction)(void(*)(void))channel_list_interpreters,
2594 METH_VARARGS | METH_KEYWORDS, channel_list_interpreters_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002595 {"channel_send", (PyCFunction)(void(*)(void))channel_send,
Eric Snow6d2cd902018-05-16 15:04:57 -04002596 METH_VARARGS | METH_KEYWORDS, channel_send_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002597 {"channel_recv", (PyCFunction)(void(*)(void))channel_recv,
Eric Snow6d2cd902018-05-16 15:04:57 -04002598 METH_VARARGS | METH_KEYWORDS, channel_recv_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002599 {"channel_close", (PyCFunction)(void(*)(void))channel_close,
Eric Snow6d2cd902018-05-16 15:04:57 -04002600 METH_VARARGS | METH_KEYWORDS, channel_close_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002601 {"channel_release", (PyCFunction)(void(*)(void))channel_release,
Eric Snow6d2cd902018-05-16 15:04:57 -04002602 METH_VARARGS | METH_KEYWORDS, channel_release_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002603 {"_channel_id", (PyCFunction)(void(*)(void))channel__channel_id,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002604 METH_VARARGS | METH_KEYWORDS, NULL},
2605
2606 {NULL, NULL} /* sentinel */
2607};
2608
2609
2610/* initialization function */
2611
2612PyDoc_STRVAR(module_doc,
2613"This module provides primitive operations to manage Python interpreters.\n\
2614The 'interpreters' module provides a more convenient interface.");
2615
2616static struct PyModuleDef interpretersmodule = {
2617 PyModuleDef_HEAD_INIT,
2618 "_xxsubinterpreters", /* m_name */
2619 module_doc, /* m_doc */
2620 -1, /* m_size */
2621 module_functions, /* m_methods */
2622 NULL, /* m_slots */
2623 NULL, /* m_traverse */
2624 NULL, /* m_clear */
2625 NULL /* m_free */
2626};
2627
2628
2629PyMODINIT_FUNC
2630PyInit__xxsubinterpreters(void)
2631{
2632 if (_init_globals() != 0) {
2633 return NULL;
2634 }
2635
2636 /* Initialize types */
Eric Snow7f8bfc92018-01-29 18:23:44 -07002637 if (PyType_Ready(&ChannelIDtype) != 0) {
2638 return NULL;
2639 }
2640
2641 /* Create the module */
2642 PyObject *module = PyModule_Create(&interpretersmodule);
2643 if (module == NULL) {
2644 return NULL;
2645 }
2646
2647 /* Add exception types */
2648 PyObject *ns = PyModule_GetDict(module); // borrowed
2649 if (interp_exceptions_init(ns) != 0) {
2650 return NULL;
2651 }
2652 if (channel_exceptions_init(ns) != 0) {
2653 return NULL;
2654 }
2655
2656 /* Add other types */
2657 Py_INCREF(&ChannelIDtype);
2658 if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
2659 return NULL;
2660 }
Eric Snowc11183c2019-03-15 16:35:46 -06002661 Py_INCREF(&_PyInterpreterID_Type);
2662 if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&_PyInterpreterID_Type) != 0) {
Eric Snow4c6955e2018-02-16 18:53:40 -07002663 return NULL;
2664 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002665
Eric Snowc11183c2019-03-15 16:35:46 -06002666 if (_PyCrossInterpreterData_RegisterClass(&ChannelIDtype, _channelid_shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002667 return NULL;
2668 }
2669
2670 return module;
2671}