blob: 79c9def7262913ce5ac29fdb7a0661c3f0a02336 [file] [log] [blame]
Eric Snow7f8bfc92018-01-29 18:23:44 -07001
2/* interpreters module */
3/* low-level access to interpreter primitives */
4
5#include "Python.h"
6#include "frameobject.h"
Victor Stinner621cebe2018-11-12 16:53:38 +01007#include "pycore_pystate.h"
Eric Snow7f8bfc92018-01-29 18:23:44 -07008
9
Eric Snow4e9da0d2018-02-02 21:49:49 -070010static 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);
Alexey Izbyshevc5839192018-08-22 21:27:32 +030018 if (copied == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -070019 PyErr_NoMemory();
20 return NULL;
21 }
22 strcpy(copied, str);
23 return copied;
24}
25
Eric Snow7f8bfc92018-01-29 18:23:44 -070026static PyInterpreterState *
27_get_current(void)
28{
Victor Stinnercaba55b2018-08-03 15:33:52 +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 Stinnercaba55b2018-08-03 15:33:52 +020031 return _PyInterpreterState_Get();
Eric Snow7f8bfc92018-01-29 18:23:44 -070032}
33
34static int64_t
Eric Snow6854e802018-06-01 16:26:01 -060035_coerce_id(PyObject *orig)
Eric Snow7f8bfc92018-01-29 18:23:44 -070036{
Eric Snow6854e802018-06-01 16:26:01 -060037 PyObject *pyid = PyNumber_Long(orig);
38 if (pyid == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -070039 if (PyErr_ExceptionMatches(PyExc_TypeError)) {
Eric Snow6854e802018-06-01 16:26:01 -060040 PyErr_Format(PyExc_TypeError,
41 "'id' must be a non-negative int, got %R", orig);
Eric Snow7f8bfc92018-01-29 18:23:44 -070042 }
43 else {
Eric Snow6854e802018-06-01 16:26:01 -060044 PyErr_Format(PyExc_ValueError,
45 "'id' must be a non-negative int, got %R", orig);
Eric Snow7f8bfc92018-01-29 18:23:44 -070046 }
47 return -1;
48 }
Eric Snow6854e802018-06-01 16:26:01 -060049 int64_t id = PyLong_AsLongLong(pyid);
50 Py_DECREF(pyid);
51 if (id == -1 && PyErr_Occurred() != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -070052 if (!PyErr_ExceptionMatches(PyExc_OverflowError)) {
Eric Snow6854e802018-06-01 16:26:01 -060053 PyErr_Format(PyExc_ValueError,
54 "'id' must be a non-negative int, got %R", orig);
Eric Snow4e9da0d2018-02-02 21:49:49 -070055 }
Eric Snow7f8bfc92018-01-29 18:23:44 -070056 return -1;
57 }
Eric Snow6854e802018-06-01 16:26:01 -060058 if (id < 0) {
59 PyErr_Format(PyExc_ValueError,
60 "'id' must be a non-negative int, got %R", orig);
Eric Snow7f8bfc92018-01-29 18:23:44 -070061 return -1;
62 }
Eric Snow6854e802018-06-01 16:26:01 -060063 return id;
Eric Snow7f8bfc92018-01-29 18:23:44 -070064}
65
Eric Snow4e9da0d2018-02-02 21:49:49 -070066
Eric Snow7f8bfc92018-01-29 18:23:44 -070067/* data-sharing-specific code ***********************************************/
68
Eric Snow4e9da0d2018-02-02 21:49:49 -070069struct _sharednsitem {
70 char *name;
Eric Snow7f8bfc92018-01-29 18:23:44 -070071 _PyCrossInterpreterData data;
Eric Snow4e9da0d2018-02-02 21:49:49 -070072};
Eric Snow7f8bfc92018-01-29 18:23:44 -070073
Eric Snow4e9da0d2018-02-02 21:49:49 -070074static int
75_sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
Eric Snow7f8bfc92018-01-29 18:23:44 -070076{
Eric Snow4e9da0d2018-02-02 21:49:49 -070077 item->name = _copy_raw_string(key);
78 if (item->name == NULL) {
79 return -1;
Eric Snow7f8bfc92018-01-29 18:23:44 -070080 }
Eric Snow4e9da0d2018-02-02 21:49:49 -070081 if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
82 return -1;
83 }
84 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -070085}
86
Eric Snow4e9da0d2018-02-02 21:49:49 -070087static void
88_sharednsitem_clear(struct _sharednsitem *item)
89{
90 if (item->name != NULL) {
91 PyMem_Free(item->name);
92 }
93 _PyCrossInterpreterData_Release(&item->data);
94}
95
96static int
97_sharednsitem_apply(struct _sharednsitem *item, PyObject *ns)
98{
99 PyObject *name = PyUnicode_FromString(item->name);
100 if (name == NULL) {
101 return -1;
102 }
103 PyObject *value = _PyCrossInterpreterData_NewObject(&item->data);
104 if (value == NULL) {
105 Py_DECREF(name);
106 return -1;
107 }
108 int res = PyDict_SetItem(ns, name, value);
109 Py_DECREF(name);
110 Py_DECREF(value);
111 return res;
112}
113
114typedef struct _sharedns {
115 Py_ssize_t len;
116 struct _sharednsitem* items;
117} _sharedns;
118
119static _sharedns *
120_sharedns_new(Py_ssize_t len)
121{
122 _sharedns *shared = PyMem_NEW(_sharedns, 1);
123 if (shared == NULL) {
124 PyErr_NoMemory();
125 return NULL;
126 }
127 shared->len = len;
128 shared->items = PyMem_NEW(struct _sharednsitem, len);
129 if (shared->items == NULL) {
130 PyErr_NoMemory();
131 PyMem_Free(shared);
132 return NULL;
133 }
134 return shared;
135}
136
137static void
138_sharedns_free(_sharedns *shared)
139{
140 for (Py_ssize_t i=0; i < shared->len; i++) {
141 _sharednsitem_clear(&shared->items[i]);
142 }
143 PyMem_Free(shared->items);
144 PyMem_Free(shared);
145}
146
147static _sharedns *
148_get_shared_ns(PyObject *shareable)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700149{
150 if (shareable == NULL || shareable == Py_None) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700151 return NULL;
152 }
153 Py_ssize_t len = PyDict_Size(shareable);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700154 if (len == 0) {
155 return NULL;
156 }
157
Eric Snow4e9da0d2018-02-02 21:49:49 -0700158 _sharedns *shared = _sharedns_new(len);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700159 if (shared == NULL) {
160 return NULL;
161 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700162 Py_ssize_t pos = 0;
163 for (Py_ssize_t i=0; i < len; i++) {
164 PyObject *key, *value;
165 if (PyDict_Next(shareable, &pos, &key, &value) == 0) {
166 break;
167 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700168 if (_sharednsitem_init(&shared->items[i], key, value) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700169 break;
170 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700171 }
172 if (PyErr_Occurred()) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700173 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700174 return NULL;
175 }
176 return shared;
177}
178
179static int
Eric Snow4e9da0d2018-02-02 21:49:49 -0700180_sharedns_apply(_sharedns *shared, PyObject *ns)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700181{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700182 for (Py_ssize_t i=0; i < shared->len; i++) {
183 if (_sharednsitem_apply(&shared->items[i], ns) != 0) {
184 return -1;
185 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700186 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700187 return 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700188}
189
190// Ultimately we'd like to preserve enough information about the
191// exception and traceback that we could re-constitute (or at least
192// simulate, a la traceback.TracebackException), and even chain, a copy
193// of the exception in the calling interpreter.
194
195typedef struct _sharedexception {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700196 char *name;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700197 char *msg;
198} _sharedexception;
199
200static _sharedexception *
Eric Snow4e9da0d2018-02-02 21:49:49 -0700201_sharedexception_new(void)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700202{
203 _sharedexception *err = PyMem_NEW(_sharedexception, 1);
204 if (err == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700205 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -0700206 return NULL;
207 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700208 err->name = NULL;
209 err->msg = NULL;
210 return err;
211}
212
213static void
214_sharedexception_clear(_sharedexception *exc)
215{
216 if (exc->name != NULL) {
217 PyMem_Free(exc->name);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700218 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700219 if (exc->msg != NULL) {
220 PyMem_Free(exc->msg);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700221 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700222}
223
224static void
225_sharedexception_free(_sharedexception *exc)
226{
227 _sharedexception_clear(exc);
228 PyMem_Free(exc);
229}
230
231static _sharedexception *
232_sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb)
233{
234 assert(exctype != NULL);
235 char *failure = NULL;
236
237 _sharedexception *err = _sharedexception_new();
238 if (err == NULL) {
239 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700240 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700241
242 PyObject *name = PyUnicode_FromFormat("%S", exctype);
243 if (name == NULL) {
244 failure = "unable to format exception type name";
245 goto finally;
246 }
247 err->name = _copy_raw_string(name);
248 Py_DECREF(name);
249 if (err->name == NULL) {
250 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
251 failure = "out of memory copying exception type name";
252 }
253 failure = "unable to encode and copy exception type name";
254 goto finally;
255 }
256
257 if (exc != NULL) {
258 PyObject *msg = PyUnicode_FromFormat("%S", exc);
259 if (msg == NULL) {
260 failure = "unable to format exception message";
261 goto finally;
262 }
263 err->msg = _copy_raw_string(msg);
264 Py_DECREF(msg);
265 if (err->msg == NULL) {
266 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
267 failure = "out of memory copying exception message";
268 }
269 failure = "unable to encode and copy exception message";
270 goto finally;
271 }
272 }
273
274finally:
275 if (failure != NULL) {
276 PyErr_Clear();
277 if (err->name != NULL) {
278 PyMem_Free(err->name);
279 err->name = NULL;
280 }
281 err->msg = failure;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700282 }
283 return err;
284}
285
Eric Snow7f8bfc92018-01-29 18:23:44 -0700286static void
Eric Snow4e9da0d2018-02-02 21:49:49 -0700287_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700288{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700289 if (exc->name != NULL) {
290 if (exc->msg != NULL) {
291 PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg);
292 }
293 else {
294 PyErr_SetString(wrapperclass, exc->name);
295 }
296 }
297 else if (exc->msg != NULL) {
298 PyErr_SetString(wrapperclass, exc->msg);
299 }
300 else {
301 PyErr_SetNone(wrapperclass);
302 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700303}
304
Eric Snow4e9da0d2018-02-02 21:49:49 -0700305
306/* channel-specific code ****************************************************/
Eric Snow7f8bfc92018-01-29 18:23:44 -0700307
Eric Snow3ab01362018-05-17 10:27:09 -0400308#define CHANNEL_SEND 1
309#define CHANNEL_BOTH 0
310#define CHANNEL_RECV -1
311
Eric Snow7f8bfc92018-01-29 18:23:44 -0700312static PyObject *ChannelError;
313static PyObject *ChannelNotFoundError;
314static PyObject *ChannelClosedError;
315static PyObject *ChannelEmptyError;
Eric Snow3ab01362018-05-17 10:27:09 -0400316static PyObject *ChannelNotEmptyError;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700317
318static int
319channel_exceptions_init(PyObject *ns)
320{
321 // XXX Move the exceptions into per-module memory?
322
323 // A channel-related operation failed.
324 ChannelError = PyErr_NewException("_xxsubinterpreters.ChannelError",
325 PyExc_RuntimeError, NULL);
326 if (ChannelError == NULL) {
327 return -1;
328 }
329 if (PyDict_SetItemString(ns, "ChannelError", ChannelError) != 0) {
330 return -1;
331 }
332
333 // An operation tried to use a channel that doesn't exist.
334 ChannelNotFoundError = PyErr_NewException(
335 "_xxsubinterpreters.ChannelNotFoundError", ChannelError, NULL);
336 if (ChannelNotFoundError == NULL) {
337 return -1;
338 }
339 if (PyDict_SetItemString(ns, "ChannelNotFoundError", ChannelNotFoundError) != 0) {
340 return -1;
341 }
342
343 // An operation tried to use a closed channel.
344 ChannelClosedError = PyErr_NewException(
345 "_xxsubinterpreters.ChannelClosedError", ChannelError, NULL);
346 if (ChannelClosedError == NULL) {
347 return -1;
348 }
349 if (PyDict_SetItemString(ns, "ChannelClosedError", ChannelClosedError) != 0) {
350 return -1;
351 }
352
353 // An operation tried to pop from an empty channel.
354 ChannelEmptyError = PyErr_NewException(
355 "_xxsubinterpreters.ChannelEmptyError", ChannelError, NULL);
356 if (ChannelEmptyError == NULL) {
357 return -1;
358 }
359 if (PyDict_SetItemString(ns, "ChannelEmptyError", ChannelEmptyError) != 0) {
360 return -1;
361 }
362
Eric Snow3ab01362018-05-17 10:27:09 -0400363 // An operation tried to close a non-empty channel.
364 ChannelNotEmptyError = PyErr_NewException(
365 "_xxsubinterpreters.ChannelNotEmptyError", ChannelError, NULL);
366 if (ChannelNotEmptyError == NULL) {
367 return -1;
368 }
369 if (PyDict_SetItemString(ns, "ChannelNotEmptyError", ChannelNotEmptyError) != 0) {
370 return -1;
371 }
372
Eric Snow7f8bfc92018-01-29 18:23:44 -0700373 return 0;
374}
375
Eric Snow4e9da0d2018-02-02 21:49:49 -0700376/* the channel queue */
377
378struct _channelitem;
379
380typedef struct _channelitem {
381 _PyCrossInterpreterData *data;
382 struct _channelitem *next;
383} _channelitem;
384
385static _channelitem *
386_channelitem_new(void)
387{
388 _channelitem *item = PyMem_NEW(_channelitem, 1);
389 if (item == NULL) {
390 PyErr_NoMemory();
391 return NULL;
392 }
393 item->data = NULL;
394 item->next = NULL;
395 return item;
396}
397
398static void
399_channelitem_clear(_channelitem *item)
400{
401 if (item->data != NULL) {
402 _PyCrossInterpreterData_Release(item->data);
403 PyMem_Free(item->data);
404 item->data = NULL;
405 }
406 item->next = NULL;
407}
408
409static void
410_channelitem_free(_channelitem *item)
411{
412 _channelitem_clear(item);
413 PyMem_Free(item);
414}
415
416static void
417_channelitem_free_all(_channelitem *item)
418{
419 while (item != NULL) {
420 _channelitem *last = item;
421 item = item->next;
422 _channelitem_free(last);
423 }
424}
425
426static _PyCrossInterpreterData *
427_channelitem_popped(_channelitem *item)
428{
429 _PyCrossInterpreterData *data = item->data;
430 item->data = NULL;
431 _channelitem_free(item);
432 return data;
433}
434
435typedef struct _channelqueue {
436 int64_t count;
437 _channelitem *first;
438 _channelitem *last;
439} _channelqueue;
440
441static _channelqueue *
442_channelqueue_new(void)
443{
444 _channelqueue *queue = PyMem_NEW(_channelqueue, 1);
445 if (queue == NULL) {
446 PyErr_NoMemory();
447 return NULL;
448 }
449 queue->count = 0;
450 queue->first = NULL;
451 queue->last = NULL;
452 return queue;
453}
454
455static void
456_channelqueue_clear(_channelqueue *queue)
457{
458 _channelitem_free_all(queue->first);
459 queue->count = 0;
460 queue->first = NULL;
461 queue->last = NULL;
462}
463
464static void
465_channelqueue_free(_channelqueue *queue)
466{
467 _channelqueue_clear(queue);
468 PyMem_Free(queue);
469}
470
471static int
472_channelqueue_put(_channelqueue *queue, _PyCrossInterpreterData *data)
473{
474 _channelitem *item = _channelitem_new();
475 if (item == NULL) {
476 return -1;
477 }
478 item->data = data;
479
480 queue->count += 1;
481 if (queue->first == NULL) {
482 queue->first = item;
483 }
484 else {
485 queue->last->next = item;
486 }
487 queue->last = item;
488 return 0;
489}
490
491static _PyCrossInterpreterData *
492_channelqueue_get(_channelqueue *queue)
493{
494 _channelitem *item = queue->first;
495 if (item == NULL) {
496 return NULL;
497 }
498 queue->first = item->next;
499 if (queue->last == item) {
500 queue->last = NULL;
501 }
502 queue->count -= 1;
503
504 return _channelitem_popped(item);
505}
506
507/* channel-interpreter associations */
508
Eric Snow7f8bfc92018-01-29 18:23:44 -0700509struct _channelend;
510
511typedef struct _channelend {
512 struct _channelend *next;
513 int64_t interp;
514 int open;
515} _channelend;
516
517static _channelend *
518_channelend_new(int64_t interp)
519{
520 _channelend *end = PyMem_NEW(_channelend, 1);
521 if (end == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700522 PyErr_NoMemory();
Eric Snow7f8bfc92018-01-29 18:23:44 -0700523 return NULL;
524 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700525 end->next = NULL;
526 end->interp = interp;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700527 end->open = 1;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700528 return end;
529}
530
531static void
Eric Snow4e9da0d2018-02-02 21:49:49 -0700532_channelend_free(_channelend *end)
533{
534 PyMem_Free(end);
535}
536
537static void
538_channelend_free_all(_channelend *end)
539{
Eric Snow7f8bfc92018-01-29 18:23:44 -0700540 while (end != NULL) {
541 _channelend *last = end;
542 end = end->next;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700543 _channelend_free(last);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700544 }
545}
546
547static _channelend *
548_channelend_find(_channelend *first, int64_t interp, _channelend **pprev)
549{
550 _channelend *prev = NULL;
551 _channelend *end = first;
552 while (end != NULL) {
553 if (end->interp == interp) {
554 break;
555 }
556 prev = end;
557 end = end->next;
558 }
559 if (pprev != NULL) {
560 *pprev = prev;
561 }
562 return end;
563}
564
Eric Snow4e9da0d2018-02-02 21:49:49 -0700565typedef struct _channelassociations {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700566 // Note that the list entries are never removed for interpreter
567 // for which the channel is closed. This should be a problem in
568 // practice. Also, a channel isn't automatically closed when an
569 // interpreter is destroyed.
570 int64_t numsendopen;
571 int64_t numrecvopen;
572 _channelend *send;
573 _channelend *recv;
Eric Snow4e9da0d2018-02-02 21:49:49 -0700574} _channelends;
575
576static _channelends *
577_channelends_new(void)
578{
579 _channelends *ends = PyMem_NEW(_channelends, 1);
580 if (ends== NULL) {
581 return NULL;
582 }
583 ends->numsendopen = 0;
584 ends->numrecvopen = 0;
585 ends->send = NULL;
586 ends->recv = NULL;
587 return ends;
588}
589
590static void
591_channelends_clear(_channelends *ends)
592{
593 _channelend_free_all(ends->send);
594 ends->send = NULL;
595 ends->numsendopen = 0;
596
597 _channelend_free_all(ends->recv);
598 ends->recv = NULL;
599 ends->numrecvopen = 0;
600}
601
602static void
603_channelends_free(_channelends *ends)
604{
605 _channelends_clear(ends);
606 PyMem_Free(ends);
607}
608
609static _channelend *
610_channelends_add(_channelends *ends, _channelend *prev, int64_t interp,
611 int send)
612{
613 _channelend *end = _channelend_new(interp);
614 if (end == NULL) {
615 return NULL;
616 }
617
618 if (prev == NULL) {
619 if (send) {
620 ends->send = end;
621 }
622 else {
623 ends->recv = end;
624 }
625 }
626 else {
627 prev->next = end;
628 }
629 if (send) {
630 ends->numsendopen += 1;
631 }
632 else {
633 ends->numrecvopen += 1;
634 }
635 return end;
636}
637
638static int
639_channelends_associate(_channelends *ends, int64_t interp, int send)
640{
641 _channelend *prev;
642 _channelend *end = _channelend_find(send ? ends->send : ends->recv,
643 interp, &prev);
644 if (end != NULL) {
645 if (!end->open) {
646 PyErr_SetString(ChannelClosedError, "channel already closed");
647 return -1;
648 }
649 // already associated
650 return 0;
651 }
652 if (_channelends_add(ends, prev, interp, send) == NULL) {
653 return -1;
654 }
655 return 0;
656}
657
658static int
659_channelends_is_open(_channelends *ends)
660{
661 if (ends->numsendopen != 0 || ends->numrecvopen != 0) {
662 return 1;
663 }
664 if (ends->send == NULL && ends->recv == NULL) {
665 return 1;
666 }
667 return 0;
668}
669
670static void
671_channelends_close_end(_channelends *ends, _channelend *end, int send)
672{
673 end->open = 0;
674 if (send) {
675 ends->numsendopen -= 1;
676 }
677 else {
678 ends->numrecvopen -= 1;
679 }
680}
681
682static int
683_channelends_close_interpreter(_channelends *ends, int64_t interp, int which)
684{
685 _channelend *prev;
686 _channelend *end;
687 if (which >= 0) { // send/both
688 end = _channelend_find(ends->send, interp, &prev);
689 if (end == NULL) {
690 // never associated so add it
691 end = _channelends_add(ends, prev, interp, 1);
692 if (end == NULL) {
693 return -1;
694 }
695 }
696 _channelends_close_end(ends, end, 1);
697 }
698 if (which <= 0) { // recv/both
699 end = _channelend_find(ends->recv, interp, &prev);
700 if (end == NULL) {
701 // never associated so add it
702 end = _channelends_add(ends, prev, interp, 0);
703 if (end == NULL) {
704 return -1;
705 }
706 }
707 _channelends_close_end(ends, end, 0);
708 }
709 return 0;
710}
711
712static void
Eric Snow3ab01362018-05-17 10:27:09 -0400713_channelends_close_all(_channelends *ends, int which, int force)
Eric Snow4e9da0d2018-02-02 21:49:49 -0700714{
Eric Snow3ab01362018-05-17 10:27:09 -0400715 // XXX Handle the ends.
716 // XXX Handle force is True.
717
Eric Snow4e9da0d2018-02-02 21:49:49 -0700718 // Ensure all the "send"-associated interpreters are closed.
719 _channelend *end;
720 for (end = ends->send; end != NULL; end = end->next) {
721 _channelends_close_end(ends, end, 1);
722 }
723
724 // Ensure all the "recv"-associated interpreters are closed.
725 for (end = ends->recv; end != NULL; end = end->next) {
726 _channelends_close_end(ends, end, 0);
727 }
728}
729
730/* channels */
731
732struct _channel;
Eric Snow3ab01362018-05-17 10:27:09 -0400733struct _channel_closing;
734static void _channel_clear_closing(struct _channel *);
735static void _channel_finish_closing(struct _channel *);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700736
737typedef struct _channel {
738 PyThread_type_lock mutex;
739 _channelqueue *queue;
740 _channelends *ends;
741 int open;
Eric Snow3ab01362018-05-17 10:27:09 -0400742 struct _channel_closing *closing;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700743} _PyChannelState;
744
745static _PyChannelState *
746_channel_new(void)
747{
748 _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1);
749 if (chan == NULL) {
750 return NULL;
751 }
752 chan->mutex = PyThread_allocate_lock();
753 if (chan->mutex == NULL) {
754 PyMem_Free(chan);
755 PyErr_SetString(ChannelError,
756 "can't initialize mutex for new channel");
757 return NULL;
758 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700759 chan->queue = _channelqueue_new();
760 if (chan->queue == NULL) {
761 PyMem_Free(chan);
762 return NULL;
763 }
764 chan->ends = _channelends_new();
765 if (chan->ends == NULL) {
766 _channelqueue_free(chan->queue);
767 PyMem_Free(chan);
768 return NULL;
769 }
Eric Snow7f8bfc92018-01-29 18:23:44 -0700770 chan->open = 1;
Eric Snow3ab01362018-05-17 10:27:09 -0400771 chan->closing = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700772 return chan;
773}
774
Eric Snow4e9da0d2018-02-02 21:49:49 -0700775static void
776_channel_free(_PyChannelState *chan)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700777{
Eric Snow3ab01362018-05-17 10:27:09 -0400778 _channel_clear_closing(chan);
Eric Snow4e9da0d2018-02-02 21:49:49 -0700779 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
780 _channelqueue_free(chan->queue);
781 _channelends_free(chan->ends);
782 PyThread_release_lock(chan->mutex);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700783
Eric Snow4e9da0d2018-02-02 21:49:49 -0700784 PyThread_free_lock(chan->mutex);
785 PyMem_Free(chan);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700786}
787
Eric Snow4e9da0d2018-02-02 21:49:49 -0700788static int
789_channel_add(_PyChannelState *chan, int64_t interp,
790 _PyCrossInterpreterData *data)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700791{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700792 int res = -1;
793 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
794
Eric Snow7f8bfc92018-01-29 18:23:44 -0700795 if (!chan->open) {
796 PyErr_SetString(ChannelClosedError, "channel closed");
Eric Snow4e9da0d2018-02-02 21:49:49 -0700797 goto done;
798 }
799 if (_channelends_associate(chan->ends, interp, 1) != 0) {
800 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700801 }
802
Eric Snow4e9da0d2018-02-02 21:49:49 -0700803 if (_channelqueue_put(chan->queue, data) != 0) {
804 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700805 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700806
807 res = 0;
808done:
809 PyThread_release_lock(chan->mutex);
810 return res;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700811}
812
Eric Snow4e9da0d2018-02-02 21:49:49 -0700813static _PyCrossInterpreterData *
814_channel_next(_PyChannelState *chan, int64_t interp)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700815{
Eric Snow4e9da0d2018-02-02 21:49:49 -0700816 _PyCrossInterpreterData *data = NULL;
817 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
818
819 if (!chan->open) {
820 PyErr_SetString(ChannelClosedError, "channel closed");
821 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700822 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700823 if (_channelends_associate(chan->ends, interp, 0) != 0) {
824 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700825 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700826
827 data = _channelqueue_get(chan->queue);
Eric Snow3ab01362018-05-17 10:27:09 -0400828 if (data == NULL && !PyErr_Occurred() && chan->closing != NULL) {
829 chan->open = 0;
830 }
831
Eric Snow4e9da0d2018-02-02 21:49:49 -0700832done:
833 PyThread_release_lock(chan->mutex);
Eric Snow3ab01362018-05-17 10:27:09 -0400834 if (chan->queue->count == 0) {
835 _channel_finish_closing(chan);
836 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700837 return data;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700838}
839
840static int
Eric Snow3ab01362018-05-17 10:27:09 -0400841_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int end)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700842{
843 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
844
845 int res = -1;
846 if (!chan->open) {
847 PyErr_SetString(ChannelClosedError, "channel already closed");
848 goto done;
849 }
850
Eric Snow3ab01362018-05-17 10:27:09 -0400851 if (_channelends_close_interpreter(chan->ends, interp, end) != 0) {
Eric Snow4e9da0d2018-02-02 21:49:49 -0700852 goto done;
Eric Snow7f8bfc92018-01-29 18:23:44 -0700853 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700854 chan->open = _channelends_is_open(chan->ends);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700855
856 res = 0;
857done:
858 PyThread_release_lock(chan->mutex);
859 return res;
860}
861
862static int
Eric Snow3ab01362018-05-17 10:27:09 -0400863_channel_close_all(_PyChannelState *chan, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -0700864{
865 int res = -1;
866 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
867
868 if (!chan->open) {
869 PyErr_SetString(ChannelClosedError, "channel already closed");
870 goto done;
871 }
872
Eric Snow3ab01362018-05-17 10:27:09 -0400873 if (!force && chan->queue->count > 0) {
874 PyErr_SetString(ChannelNotEmptyError,
875 "may not be closed if not empty (try force=True)");
876 goto done;
877 }
878
Eric Snow7f8bfc92018-01-29 18:23:44 -0700879 chan->open = 0;
880
881 // We *could* also just leave these in place, since we've marked
882 // the channel as closed already.
Eric Snow3ab01362018-05-17 10:27:09 -0400883 _channelends_close_all(chan->ends, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -0700884
885 res = 0;
886done:
887 PyThread_release_lock(chan->mutex);
888 return res;
889}
890
Eric Snow4e9da0d2018-02-02 21:49:49 -0700891/* the set of channels */
Eric Snow7f8bfc92018-01-29 18:23:44 -0700892
893struct _channelref;
894
895typedef struct _channelref {
896 int64_t id;
897 _PyChannelState *chan;
898 struct _channelref *next;
899 Py_ssize_t objcount;
900} _channelref;
901
902static _channelref *
903_channelref_new(int64_t id, _PyChannelState *chan)
904{
905 _channelref *ref = PyMem_NEW(_channelref, 1);
906 if (ref == NULL) {
907 return NULL;
908 }
909 ref->id = id;
910 ref->chan = chan;
911 ref->next = NULL;
912 ref->objcount = 0;
913 return ref;
914}
915
Eric Snow4e9da0d2018-02-02 21:49:49 -0700916//static void
917//_channelref_clear(_channelref *ref)
918//{
919// ref->id = -1;
920// ref->chan = NULL;
921// ref->next = NULL;
922// ref->objcount = 0;
923//}
924
925static void
926_channelref_free(_channelref *ref)
927{
Eric Snow3ab01362018-05-17 10:27:09 -0400928 if (ref->chan != NULL) {
929 _channel_clear_closing(ref->chan);
930 }
Eric Snow4e9da0d2018-02-02 21:49:49 -0700931 //_channelref_clear(ref);
932 PyMem_Free(ref);
933}
934
Eric Snow7f8bfc92018-01-29 18:23:44 -0700935static _channelref *
936_channelref_find(_channelref *first, int64_t id, _channelref **pprev)
937{
938 _channelref *prev = NULL;
939 _channelref *ref = first;
940 while (ref != NULL) {
941 if (ref->id == id) {
942 break;
943 }
944 prev = ref;
945 ref = ref->next;
946 }
947 if (pprev != NULL) {
948 *pprev = prev;
949 }
950 return ref;
951}
952
953typedef struct _channels {
954 PyThread_type_lock mutex;
955 _channelref *head;
956 int64_t numopen;
957 int64_t next_id;
958} _channels;
959
960static int
961_channels_init(_channels *channels)
962{
963 if (channels->mutex == NULL) {
964 channels->mutex = PyThread_allocate_lock();
965 if (channels->mutex == NULL) {
Eric Snow7f8bfc92018-01-29 18:23:44 -0700966 PyErr_SetString(ChannelError,
967 "can't initialize mutex for channel management");
968 return -1;
969 }
970 }
971 channels->head = NULL;
972 channels->numopen = 0;
973 channels->next_id = 0;
974 return 0;
975}
976
977static int64_t
978_channels_next_id(_channels *channels) // needs lock
979{
980 int64_t id = channels->next_id;
981 if (id < 0) {
982 /* overflow */
983 PyErr_SetString(ChannelError,
984 "failed to get a channel ID");
985 return -1;
986 }
987 channels->next_id += 1;
988 return id;
989}
990
991static _PyChannelState *
992_channels_lookup(_channels *channels, int64_t id, PyThread_type_lock *pmutex)
993{
994 _PyChannelState *chan = NULL;
995 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
996 if (pmutex != NULL) {
997 *pmutex = NULL;
998 }
999
1000 _channelref *ref = _channelref_find(channels->head, id, NULL);
1001 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001002 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001003 goto done;
1004 }
1005 if (ref->chan == NULL || !ref->chan->open) {
Eric Snowab4a1982018-06-13 08:02:39 -06001006 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001007 goto done;
1008 }
1009
1010 if (pmutex != NULL) {
1011 // The mutex will be closed by the caller.
1012 *pmutex = channels->mutex;
1013 }
1014
1015 chan = ref->chan;
1016done:
1017 if (pmutex == NULL || *pmutex == NULL) {
1018 PyThread_release_lock(channels->mutex);
1019 }
1020 return chan;
1021}
1022
1023static int64_t
1024_channels_add(_channels *channels, _PyChannelState *chan)
1025{
1026 int64_t cid = -1;
1027 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1028
1029 // Create a new ref.
1030 int64_t id = _channels_next_id(channels);
1031 if (id < 0) {
1032 goto done;
1033 }
1034 _channelref *ref = _channelref_new(id, chan);
1035 if (ref == NULL) {
1036 goto done;
1037 }
1038
1039 // Add it to the list.
1040 // We assume that the channel is a new one (not already in the list).
1041 ref->next = channels->head;
1042 channels->head = ref;
1043 channels->numopen += 1;
1044
1045 cid = id;
1046done:
1047 PyThread_release_lock(channels->mutex);
1048 return cid;
1049}
1050
Eric Snow3ab01362018-05-17 10:27:09 -04001051/* forward */
1052static int _channel_set_closing(struct _channelref *, PyThread_type_lock);
1053
Eric Snow7f8bfc92018-01-29 18:23:44 -07001054static int
Eric Snow3ab01362018-05-17 10:27:09 -04001055_channels_close(_channels *channels, int64_t cid, _PyChannelState **pchan,
1056 int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001057{
1058 int res = -1;
1059 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1060 if (pchan != NULL) {
1061 *pchan = NULL;
1062 }
1063
1064 _channelref *ref = _channelref_find(channels->head, cid, NULL);
1065 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001066 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001067 goto done;
1068 }
1069
1070 if (ref->chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001071 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001072 goto done;
1073 }
Eric Snow3ab01362018-05-17 10:27:09 -04001074 else if (!force && end == CHANNEL_SEND && ref->chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001075 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001076 goto done;
1077 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001078 else {
Eric Snow3ab01362018-05-17 10:27:09 -04001079 if (_channel_close_all(ref->chan, end, force) != 0) {
1080 if (end == CHANNEL_SEND &&
1081 PyErr_ExceptionMatches(ChannelNotEmptyError)) {
1082 if (ref->chan->closing != NULL) {
Eric Snow6854e802018-06-01 16:26:01 -06001083 PyErr_Format(ChannelClosedError,
Eric Snowab4a1982018-06-13 08:02:39 -06001084 "channel %" PRId64 " closed", cid);
Eric Snow3ab01362018-05-17 10:27:09 -04001085 goto done;
1086 }
1087 // Mark the channel as closing and return. The channel
1088 // will be cleaned up in _channel_next().
1089 PyErr_Clear();
1090 if (_channel_set_closing(ref, channels->mutex) != 0) {
1091 goto done;
1092 }
1093 if (pchan != NULL) {
1094 *pchan = ref->chan;
1095 }
1096 res = 0;
1097 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001098 goto done;
1099 }
1100 if (pchan != NULL) {
1101 *pchan = ref->chan;
1102 }
Eric Snow3ab01362018-05-17 10:27:09 -04001103 else {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001104 _channel_free(ref->chan);
1105 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001106 ref->chan = NULL;
1107 }
1108
1109 res = 0;
1110done:
1111 PyThread_release_lock(channels->mutex);
1112 return res;
1113}
1114
1115static void
1116_channels_remove_ref(_channels *channels, _channelref *ref, _channelref *prev,
1117 _PyChannelState **pchan)
1118{
1119 if (ref == channels->head) {
1120 channels->head = ref->next;
1121 }
1122 else {
1123 prev->next = ref->next;
1124 }
1125 channels->numopen -= 1;
1126
1127 if (pchan != NULL) {
1128 *pchan = ref->chan;
1129 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001130 _channelref_free(ref);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001131}
1132
1133static int
1134_channels_remove(_channels *channels, int64_t id, _PyChannelState **pchan)
1135{
1136 int res = -1;
1137 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1138
1139 if (pchan != NULL) {
1140 *pchan = NULL;
1141 }
1142
1143 _channelref *prev = NULL;
1144 _channelref *ref = _channelref_find(channels->head, id, &prev);
1145 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001146 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001147 goto done;
1148 }
1149
1150 _channels_remove_ref(channels, ref, prev, pchan);
1151
1152 res = 0;
1153done:
1154 PyThread_release_lock(channels->mutex);
1155 return res;
1156}
1157
1158static int
1159_channels_add_id_object(_channels *channels, int64_t id)
1160{
1161 int res = -1;
1162 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1163
1164 _channelref *ref = _channelref_find(channels->head, id, NULL);
1165 if (ref == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001166 PyErr_Format(ChannelNotFoundError, "channel %" PRId64 " not found", id);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001167 goto done;
1168 }
1169 ref->objcount += 1;
1170
1171 res = 0;
1172done:
1173 PyThread_release_lock(channels->mutex);
1174 return res;
1175}
1176
1177static void
1178_channels_drop_id_object(_channels *channels, int64_t id)
1179{
1180 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1181
1182 _channelref *prev = NULL;
1183 _channelref *ref = _channelref_find(channels->head, id, &prev);
1184 if (ref == NULL) {
1185 // Already destroyed.
1186 goto done;
1187 }
1188 ref->objcount -= 1;
1189
1190 // Destroy if no longer used.
1191 if (ref->objcount == 0) {
1192 _PyChannelState *chan = NULL;
1193 _channels_remove_ref(channels, ref, prev, &chan);
1194 if (chan != NULL) {
1195 _channel_free(chan);
1196 }
1197 }
1198
1199done:
1200 PyThread_release_lock(channels->mutex);
1201}
1202
Benjamin Peterson4629c0d2018-07-06 23:28:35 -07001203static int64_t *
Eric Snow7f8bfc92018-01-29 18:23:44 -07001204_channels_list_all(_channels *channels, int64_t *count)
1205{
1206 int64_t *cids = NULL;
1207 PyThread_acquire_lock(channels->mutex, WAIT_LOCK);
1208 int64_t numopen = channels->numopen;
1209 if (numopen >= PY_SSIZE_T_MAX) {
1210 PyErr_SetString(PyExc_RuntimeError, "too many channels open");
1211 goto done;
1212 }
1213 int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)(channels->numopen));
1214 if (ids == NULL) {
1215 goto done;
1216 }
1217 _channelref *ref = channels->head;
1218 for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
1219 ids[i] = ref->id;
1220 }
1221 *count = channels->numopen;
1222
1223 cids = ids;
1224done:
1225 PyThread_release_lock(channels->mutex);
1226 return cids;
1227}
1228
Eric Snow3ab01362018-05-17 10:27:09 -04001229/* support for closing non-empty channels */
1230
1231struct _channel_closing {
1232 struct _channelref *ref;
1233};
1234
1235static int
1236_channel_set_closing(struct _channelref *ref, PyThread_type_lock mutex) {
1237 struct _channel *chan = ref->chan;
1238 if (chan == NULL) {
1239 // already closed
1240 return 0;
1241 }
1242 int res = -1;
1243 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1244 if (chan->closing != NULL) {
1245 PyErr_SetString(ChannelClosedError, "channel closed");
1246 goto done;
1247 }
1248 chan->closing = PyMem_NEW(struct _channel_closing, 1);
1249 if (chan->closing == NULL) {
1250 goto done;
1251 }
1252 chan->closing->ref = ref;
1253
1254 res = 0;
1255done:
1256 PyThread_release_lock(chan->mutex);
1257 return res;
1258}
1259
1260static void
1261_channel_clear_closing(struct _channel *chan) {
1262 PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
1263 if (chan->closing != NULL) {
1264 PyMem_Free(chan->closing);
1265 chan->closing = NULL;
1266 }
1267 PyThread_release_lock(chan->mutex);
1268}
1269
1270static void
1271_channel_finish_closing(struct _channel *chan) {
1272 struct _channel_closing *closing = chan->closing;
1273 if (closing == NULL) {
1274 return;
1275 }
1276 _channelref *ref = closing->ref;
1277 _channel_clear_closing(chan);
1278 // Do the things that would have been done in _channels_close().
1279 ref->chan = NULL;
1280 _channel_free(chan);
1281};
1282
Eric Snow7f8bfc92018-01-29 18:23:44 -07001283/* "high"-level channel-related functions */
1284
1285static int64_t
1286_channel_create(_channels *channels)
1287{
1288 _PyChannelState *chan = _channel_new();
1289 if (chan == NULL) {
1290 return -1;
1291 }
1292 int64_t id = _channels_add(channels, chan);
1293 if (id < 0) {
1294 _channel_free(chan);
1295 return -1;
1296 }
1297 return id;
1298}
1299
1300static int
1301_channel_destroy(_channels *channels, int64_t id)
1302{
1303 _PyChannelState *chan = NULL;
1304 if (_channels_remove(channels, id, &chan) != 0) {
1305 return -1;
1306 }
1307 if (chan != NULL) {
1308 _channel_free(chan);
1309 }
1310 return 0;
1311}
1312
1313static int
1314_channel_send(_channels *channels, int64_t id, PyObject *obj)
1315{
1316 PyInterpreterState *interp = _get_current();
1317 if (interp == NULL) {
1318 return -1;
1319 }
1320
1321 // Look up the channel.
1322 PyThread_type_lock mutex = NULL;
1323 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1324 if (chan == NULL) {
1325 return -1;
1326 }
1327 // Past this point we are responsible for releasing the mutex.
1328
Eric Snow3ab01362018-05-17 10:27:09 -04001329 if (chan->closing != NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001330 PyErr_Format(ChannelClosedError, "channel %" PRId64 " closed", id);
Eric Snow3ab01362018-05-17 10:27:09 -04001331 PyThread_release_lock(mutex);
1332 return -1;
1333 }
1334
Eric Snow7f8bfc92018-01-29 18:23:44 -07001335 // Convert the object to cross-interpreter data.
1336 _PyCrossInterpreterData *data = PyMem_NEW(_PyCrossInterpreterData, 1);
1337 if (data == NULL) {
1338 PyThread_release_lock(mutex);
1339 return -1;
1340 }
1341 if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
Alexey Izbyshev36433222019-02-16 01:28:58 +03001342 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001343 PyThread_release_lock(mutex);
1344 return -1;
1345 }
1346
1347 // Add the data to the channel.
1348 int res = _channel_add(chan, interp->id, data);
1349 PyThread_release_lock(mutex);
1350 if (res != 0) {
1351 _PyCrossInterpreterData_Release(data);
1352 PyMem_Free(data);
1353 return -1;
1354 }
1355
1356 return 0;
1357}
1358
1359static PyObject *
1360_channel_recv(_channels *channels, int64_t id)
1361{
1362 PyInterpreterState *interp = _get_current();
1363 if (interp == NULL) {
1364 return NULL;
1365 }
1366
1367 // Look up the channel.
1368 PyThread_type_lock mutex = NULL;
1369 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1370 if (chan == NULL) {
1371 return NULL;
1372 }
1373 // Past this point we are responsible for releasing the mutex.
1374
1375 // Pop off the next item from the channel.
1376 _PyCrossInterpreterData *data = _channel_next(chan, interp->id);
1377 PyThread_release_lock(mutex);
1378 if (data == NULL) {
Eric Snow6d2cd902018-05-16 15:04:57 -04001379 if (!PyErr_Occurred()) {
Eric Snowab4a1982018-06-13 08:02:39 -06001380 PyErr_Format(ChannelEmptyError, "channel %" PRId64 " is empty", id);
Eric Snow6d2cd902018-05-16 15:04:57 -04001381 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001382 return NULL;
1383 }
1384
1385 // Convert the data back to an object.
1386 PyObject *obj = _PyCrossInterpreterData_NewObject(data);
1387 if (obj == NULL) {
1388 return NULL;
1389 }
1390 _PyCrossInterpreterData_Release(data);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001391 PyMem_Free(data);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001392
1393 return obj;
1394}
1395
1396static int
1397_channel_drop(_channels *channels, int64_t id, int send, int recv)
1398{
1399 PyInterpreterState *interp = _get_current();
1400 if (interp == NULL) {
1401 return -1;
1402 }
1403
1404 // Look up the channel.
1405 PyThread_type_lock mutex = NULL;
1406 _PyChannelState *chan = _channels_lookup(channels, id, &mutex);
1407 if (chan == NULL) {
1408 return -1;
1409 }
1410 // Past this point we are responsible for releasing the mutex.
1411
1412 // Close one or both of the two ends.
Eric Snow4e9da0d2018-02-02 21:49:49 -07001413 int res = _channel_close_interpreter(chan, interp->id, send-recv);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001414 PyThread_release_lock(mutex);
1415 return res;
1416}
1417
1418static int
Eric Snow3ab01362018-05-17 10:27:09 -04001419_channel_close(_channels *channels, int64_t id, int end, int force)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001420{
Eric Snow3ab01362018-05-17 10:27:09 -04001421 return _channels_close(channels, id, NULL, end, force);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001422}
1423
1424/* ChannelID class */
1425
Eric Snow7f8bfc92018-01-29 18:23:44 -07001426static PyTypeObject ChannelIDtype;
1427
1428typedef struct channelid {
1429 PyObject_HEAD
1430 int64_t id;
1431 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001432 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001433 _channels *channels;
1434} channelid;
1435
1436static channelid *
1437newchannelid(PyTypeObject *cls, int64_t cid, int end, _channels *channels,
Eric Snow6d2cd902018-05-16 15:04:57 -04001438 int force, int resolve)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001439{
1440 channelid *self = PyObject_New(channelid, cls);
1441 if (self == NULL) {
1442 return NULL;
1443 }
1444 self->id = cid;
1445 self->end = end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001446 self->resolve = resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001447 self->channels = channels;
1448
1449 if (_channels_add_id_object(channels, cid) != 0) {
1450 if (force && PyErr_ExceptionMatches(ChannelNotFoundError)) {
1451 PyErr_Clear();
1452 }
1453 else {
1454 Py_DECREF((PyObject *)self);
1455 return NULL;
1456 }
1457 }
1458
1459 return self;
1460}
1461
1462static _channels * _global_channels(void);
1463
1464static PyObject *
1465channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
1466{
Eric Snow6d2cd902018-05-16 15:04:57 -04001467 static char *kwlist[] = {"id", "send", "recv", "force", "_resolve", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07001468 PyObject *id;
1469 int send = -1;
1470 int recv = -1;
1471 int force = 0;
Eric Snow6d2cd902018-05-16 15:04:57 -04001472 int resolve = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001473 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Eric Snow6d2cd902018-05-16 15:04:57 -04001474 "O|$pppp:ChannelID.__new__", kwlist,
1475 &id, &send, &recv, &force, &resolve))
Eric Snow7f8bfc92018-01-29 18:23:44 -07001476 return NULL;
1477
1478 // Coerce and check the ID.
1479 int64_t cid;
1480 if (PyObject_TypeCheck(id, &ChannelIDtype)) {
1481 cid = ((channelid *)id)->id;
1482 }
1483 else {
1484 cid = _coerce_id(id);
1485 if (cid < 0) {
1486 return NULL;
1487 }
1488 }
1489
1490 // 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;
1623 if (cid->end != othercid->end) {
1624 equal = 0;
1625 }
1626 else {
1627 equal = (cid->id == othercid->id);
1628 }
1629 }
1630 else {
1631 other = PyNumber_Long(other);
1632 if (other == NULL) {
1633 PyErr_Clear();
1634 Py_RETURN_NOTIMPLEMENTED;
1635 }
1636 int64_t othercid = PyLong_AsLongLong(other);
Eric Snow4e9da0d2018-02-02 21:49:49 -07001637 Py_DECREF(other);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001638 if (othercid == -1 && PyErr_Occurred() != NULL) {
1639 return NULL;
1640 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07001641 if (othercid < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07001642 equal = 0;
1643 }
1644 else {
1645 equal = (cid->id == othercid);
1646 }
1647 }
1648
1649 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
1650 Py_RETURN_TRUE;
1651 }
1652 Py_RETURN_FALSE;
1653}
1654
Eric Snowab4a1982018-06-13 08:02:39 -06001655static PyObject *
1656_channel_from_cid(PyObject *cid, int end)
1657{
1658 PyObject *highlevel = PyImport_ImportModule("interpreters");
1659 if (highlevel == NULL) {
1660 PyErr_Clear();
1661 highlevel = PyImport_ImportModule("test.support.interpreters");
1662 if (highlevel == NULL) {
1663 return NULL;
1664 }
1665 }
1666 const char *clsname = (end == CHANNEL_RECV) ? "RecvChannel" :
1667 "SendChannel";
1668 PyObject *cls = PyObject_GetAttrString(highlevel, clsname);
1669 Py_DECREF(highlevel);
1670 if (cls == NULL) {
1671 return NULL;
1672 }
1673 PyObject *chan = PyObject_CallFunctionObjArgs(cls, cid, NULL);
1674 Py_DECREF(cls);
1675 if (chan == NULL) {
1676 return NULL;
1677 }
1678 return chan;
1679}
1680
Eric Snow7f8bfc92018-01-29 18:23:44 -07001681struct _channelid_xid {
1682 int64_t id;
1683 int end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001684 int resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001685};
1686
1687static PyObject *
1688_channelid_from_xid(_PyCrossInterpreterData *data)
1689{
1690 struct _channelid_xid *xid = (struct _channelid_xid *)data->data;
Eric Snow6d2cd902018-05-16 15:04:57 -04001691 // Note that we do not preserve the "resolve" flag.
1692 PyObject *cid = (PyObject *)newchannelid(&ChannelIDtype, xid->id, xid->end,
1693 _global_channels(), 0, 0);
1694 if (xid->end == 0) {
1695 return cid;
1696 }
1697 if (!xid->resolve) {
1698 return cid;
1699 }
1700
1701 /* Try returning a high-level channel end but fall back to the ID. */
Eric Snowab4a1982018-06-13 08:02:39 -06001702 PyObject *chan = _channel_from_cid(cid, xid->end);
Eric Snow6d2cd902018-05-16 15:04:57 -04001703 if (chan == NULL) {
Eric Snowab4a1982018-06-13 08:02:39 -06001704 PyErr_Clear();
1705 return cid;
Eric Snow6d2cd902018-05-16 15:04:57 -04001706 }
1707 Py_DECREF(cid);
1708 return chan;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001709}
1710
1711static int
1712_channelid_shared(PyObject *obj, _PyCrossInterpreterData *data)
1713{
1714 struct _channelid_xid *xid = PyMem_NEW(struct _channelid_xid, 1);
1715 if (xid == NULL) {
1716 return -1;
1717 }
1718 xid->id = ((channelid *)obj)->id;
1719 xid->end = ((channelid *)obj)->end;
Eric Snow6d2cd902018-05-16 15:04:57 -04001720 xid->resolve = ((channelid *)obj)->resolve;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001721
1722 data->data = xid;
Eric Snow63799132018-06-01 18:45:20 -06001723 Py_INCREF(obj);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001724 data->obj = obj;
1725 data->new_object = _channelid_from_xid;
1726 data->free = PyMem_Free;
1727 return 0;
1728}
1729
1730static PyObject *
1731channelid_end(PyObject *self, void *end)
1732{
1733 int force = 1;
1734 channelid *cid = (channelid *)self;
1735 if (end != NULL) {
1736 return (PyObject *)newchannelid(Py_TYPE(self), cid->id, *(int *)end,
Eric Snow6d2cd902018-05-16 15:04:57 -04001737 cid->channels, force, cid->resolve);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001738 }
1739
1740 if (cid->end == CHANNEL_SEND) {
1741 return PyUnicode_InternFromString("send");
1742 }
1743 if (cid->end == CHANNEL_RECV) {
1744 return PyUnicode_InternFromString("recv");
1745 }
1746 return PyUnicode_InternFromString("both");
1747}
1748
1749static int _channelid_end_send = CHANNEL_SEND;
1750static int _channelid_end_recv = CHANNEL_RECV;
1751
1752static PyGetSetDef channelid_getsets[] = {
1753 {"end", (getter)channelid_end, NULL,
1754 PyDoc_STR("'send', 'recv', or 'both'")},
1755 {"send", (getter)channelid_end, NULL,
1756 PyDoc_STR("the 'send' end of the channel"), &_channelid_end_send},
1757 {"recv", (getter)channelid_end, NULL,
1758 PyDoc_STR("the 'recv' end of the channel"), &_channelid_end_recv},
1759 {NULL}
1760};
1761
1762PyDoc_STRVAR(channelid_doc,
1763"A channel ID identifies a channel and may be used as an int.");
1764
1765static PyTypeObject ChannelIDtype = {
1766 PyVarObject_HEAD_INIT(&PyType_Type, 0)
1767 "_xxsubinterpreters.ChannelID", /* tp_name */
Peter Eisentraut0e0bc4e2018-09-10 18:46:08 +02001768 sizeof(channelid), /* tp_basicsize */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001769 0, /* tp_itemsize */
1770 (destructor)channelid_dealloc, /* tp_dealloc */
1771 0, /* tp_print */
1772 0, /* tp_getattr */
1773 0, /* tp_setattr */
1774 0, /* tp_as_async */
1775 (reprfunc)channelid_repr, /* tp_repr */
1776 &channelid_as_number, /* tp_as_number */
1777 0, /* tp_as_sequence */
1778 0, /* tp_as_mapping */
1779 channelid_hash, /* tp_hash */
1780 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04001781 (reprfunc)channelid_str, /* tp_str */
Eric Snow7f8bfc92018-01-29 18:23:44 -07001782 0, /* tp_getattro */
1783 0, /* tp_setattro */
1784 0, /* tp_as_buffer */
1785 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
1786 Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
1787 channelid_doc, /* tp_doc */
1788 0, /* tp_traverse */
1789 0, /* tp_clear */
1790 channelid_richcompare, /* tp_richcompare */
1791 0, /* tp_weaklistoffset */
1792 0, /* tp_iter */
1793 0, /* tp_iternext */
1794 0, /* tp_methods */
1795 0, /* tp_members */
1796 channelid_getsets, /* tp_getset */
1797 0, /* tp_base */
1798 0, /* tp_dict */
1799 0, /* tp_descr_get */
1800 0, /* tp_descr_set */
1801 0, /* tp_dictoffset */
1802 0, /* tp_init */
1803 0, /* tp_alloc */
1804 // Note that we do not set tp_new to channelid_new. Instead we
1805 // set it to NULL, meaning it cannot be instantiated from Python
1806 // code. We do this because there is a strong relationship between
1807 // channel IDs and the channel lifecycle, so this limitation avoids
1808 // related complications.
1809 NULL, /* tp_new */
1810};
1811
Eric Snow4e9da0d2018-02-02 21:49:49 -07001812
1813/* interpreter-specific code ************************************************/
1814
1815static PyObject * RunFailedError = NULL;
1816
1817static int
1818interp_exceptions_init(PyObject *ns)
1819{
1820 // XXX Move the exceptions into per-module memory?
1821
1822 if (RunFailedError == NULL) {
1823 // An uncaught exception came out of interp_run_string().
1824 RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
1825 PyExc_RuntimeError, NULL);
1826 if (RunFailedError == NULL) {
1827 return -1;
1828 }
1829 if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
1830 return -1;
1831 }
1832 }
1833
1834 return 0;
1835}
Eric Snow7f8bfc92018-01-29 18:23:44 -07001836
Eric Snow7f8bfc92018-01-29 18:23:44 -07001837static int
1838_is_running(PyInterpreterState *interp)
1839{
1840 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1841 if (PyThreadState_Next(tstate) != NULL) {
1842 PyErr_SetString(PyExc_RuntimeError,
1843 "interpreter has more than one thread");
1844 return -1;
1845 }
1846 PyFrameObject *frame = tstate->frame;
1847 if (frame == NULL) {
1848 if (PyErr_Occurred() != NULL) {
1849 return -1;
1850 }
1851 return 0;
1852 }
1853 return (int)(frame->f_executing);
1854}
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,
Eric Snow4e9da0d2018-02-02 21:49:49 -07001872 _sharedns *shared, _sharedexception **exc)
Eric Snow7f8bfc92018-01-29 18:23:44 -07001873{
Eric Snow4e9da0d2018-02-02 21:49:49 -07001874 PyObject *exctype = NULL;
1875 PyObject *excval = NULL;
1876 PyObject *tb = NULL;
1877
Eric Snow7f8bfc92018-01-29 18:23:44 -07001878 PyObject *main_mod = PyMapping_GetItemString(interp->modules, "__main__");
1879 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
Eric Snow4e9da0d2018-02-02 21:49:49 -07001907 *exc = NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07001908 return 0;
1909
1910error:
Eric Snow4e9da0d2018-02-02 21:49:49 -07001911 PyErr_Fetch(&exctype, &excval, &tb);
1912
1913 _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb);
1914 Py_XDECREF(exctype);
1915 Py_XDECREF(excval);
1916 Py_XDECREF(tb);
1917 if (sharedexc == NULL) {
1918 fprintf(stderr, "RunFailedError: script raised an uncaught exception");
1919 PyErr_Clear();
1920 sharedexc = NULL;
1921 }
1922 else {
1923 assert(!PyErr_Occurred());
1924 }
1925 *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
1942 // Switch to interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07001943 PyThreadState *save_tstate = NULL;
Victor Stinnercaba55b2018-08-03 15:33:52 +02001944 if (interp != _PyInterpreterState_Get()) {
Eric Snowf53d9f22018-02-20 16:30:17 -07001945 // XXX Using the "head" thread isn't strictly correct.
1946 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1947 // XXX Possible GILState issues?
1948 save_tstate = PyThreadState_Swap(tstate);
1949 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07001950
1951 // Run the script.
1952 _sharedexception *exc = NULL;
Eric Snow4e9da0d2018-02-02 21:49:49 -07001953 int result = _run_script(interp, codestr, shared, &exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001954
1955 // Switch back.
1956 if (save_tstate != NULL) {
1957 PyThreadState_Swap(save_tstate);
1958 }
1959
1960 // Propagate any exception out to the caller.
1961 if (exc != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001962 _sharedexception_apply(exc, RunFailedError);
1963 _sharedexception_free(exc);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001964 }
1965 else if (result != 0) {
1966 // We were unable to allocate a shared exception.
1967 PyErr_NoMemory();
1968 }
1969
1970 if (shared != NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07001971 _sharedns_free(shared);
Eric Snow7f8bfc92018-01-29 18:23:44 -07001972 }
1973
1974 return result;
1975}
1976
Eric Snow4c6955e2018-02-16 18:53:40 -07001977/* InterpreterID class */
1978
1979static PyTypeObject InterpreterIDtype;
1980
1981typedef struct interpid {
1982 PyObject_HEAD
1983 int64_t id;
1984} interpid;
1985
1986static interpid *
1987newinterpid(PyTypeObject *cls, int64_t id, int force)
1988{
1989 PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
1990 if (interp == NULL) {
1991 if (force) {
1992 PyErr_Clear();
1993 }
1994 else {
1995 return NULL;
1996 }
1997 }
1998
1999 interpid *self = PyObject_New(interpid, cls);
2000 if (self == NULL) {
2001 return NULL;
2002 }
2003 self->id = id;
2004
2005 if (interp != NULL) {
2006 _PyInterpreterState_IDIncref(interp);
2007 }
2008 return self;
2009}
2010
2011static PyObject *
2012interpid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
2013{
2014 static char *kwlist[] = {"id", "force", NULL};
2015 PyObject *idobj;
2016 int force = 0;
2017 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2018 "O|$p:InterpreterID.__init__", kwlist,
2019 &idobj, &force)) {
2020 return NULL;
2021 }
2022
2023 // Coerce and check the ID.
2024 int64_t id;
2025 if (PyObject_TypeCheck(idobj, &InterpreterIDtype)) {
2026 id = ((interpid *)idobj)->id;
2027 }
2028 else {
2029 id = _coerce_id(idobj);
2030 if (id < 0) {
2031 return NULL;
2032 }
2033 }
2034
2035 return (PyObject *)newinterpid(cls, id, force);
2036}
2037
2038static void
2039interpid_dealloc(PyObject *v)
2040{
2041 int64_t id = ((interpid *)v)->id;
2042 PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
2043 if (interp != NULL) {
2044 _PyInterpreterState_IDDecref(interp);
2045 }
2046 else {
2047 // already deleted
2048 PyErr_Clear();
2049 }
2050 Py_TYPE(v)->tp_free(v);
2051}
2052
2053static PyObject *
2054interpid_repr(PyObject *self)
2055{
2056 PyTypeObject *type = Py_TYPE(self);
2057 const char *name = _PyType_Name(type);
2058 interpid *id = (interpid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06002059 return PyUnicode_FromFormat("%s(%" PRId64 ")", name, id->id);
Eric Snow4c6955e2018-02-16 18:53:40 -07002060}
2061
Eric Snow6d2cd902018-05-16 15:04:57 -04002062static PyObject *
2063interpid_str(PyObject *self)
2064{
2065 interpid *id = (interpid *)self;
Eric Snowab4a1982018-06-13 08:02:39 -06002066 return PyUnicode_FromFormat("%" PRId64 "", id->id);
Eric Snow6d2cd902018-05-16 15:04:57 -04002067}
2068
Eric Snow4c6955e2018-02-16 18:53:40 -07002069PyObject *
2070interpid_int(PyObject *self)
2071{
2072 interpid *id = (interpid *)self;
2073 return PyLong_FromLongLong(id->id);
2074}
2075
2076static PyNumberMethods interpid_as_number = {
2077 0, /* nb_add */
2078 0, /* nb_subtract */
2079 0, /* nb_multiply */
2080 0, /* nb_remainder */
2081 0, /* nb_divmod */
2082 0, /* nb_power */
2083 0, /* nb_negative */
2084 0, /* nb_positive */
2085 0, /* nb_absolute */
2086 0, /* nb_bool */
2087 0, /* nb_invert */
2088 0, /* nb_lshift */
2089 0, /* nb_rshift */
2090 0, /* nb_and */
2091 0, /* nb_xor */
2092 0, /* nb_or */
2093 (unaryfunc)interpid_int, /* nb_int */
2094 0, /* nb_reserved */
2095 0, /* nb_float */
2096
2097 0, /* nb_inplace_add */
2098 0, /* nb_inplace_subtract */
2099 0, /* nb_inplace_multiply */
2100 0, /* nb_inplace_remainder */
2101 0, /* nb_inplace_power */
2102 0, /* nb_inplace_lshift */
2103 0, /* nb_inplace_rshift */
2104 0, /* nb_inplace_and */
2105 0, /* nb_inplace_xor */
2106 0, /* nb_inplace_or */
2107
2108 0, /* nb_floor_divide */
2109 0, /* nb_true_divide */
2110 0, /* nb_inplace_floor_divide */
2111 0, /* nb_inplace_true_divide */
2112
2113 (unaryfunc)interpid_int, /* nb_index */
2114};
2115
2116static Py_hash_t
2117interpid_hash(PyObject *self)
2118{
2119 interpid *id = (interpid *)self;
2120 PyObject *obj = PyLong_FromLongLong(id->id);
2121 if (obj == NULL) {
2122 return -1;
2123 }
2124 Py_hash_t hash = PyObject_Hash(obj);
2125 Py_DECREF(obj);
2126 return hash;
2127}
2128
2129static PyObject *
2130interpid_richcompare(PyObject *self, PyObject *other, int op)
2131{
2132 if (op != Py_EQ && op != Py_NE) {
2133 Py_RETURN_NOTIMPLEMENTED;
2134 }
2135
2136 if (!PyObject_TypeCheck(self, &InterpreterIDtype)) {
2137 Py_RETURN_NOTIMPLEMENTED;
2138 }
2139
2140 interpid *id = (interpid *)self;
2141 int equal;
2142 if (PyObject_TypeCheck(other, &InterpreterIDtype)) {
2143 interpid *otherid = (interpid *)other;
2144 equal = (id->id == otherid->id);
2145 }
2146 else {
2147 other = PyNumber_Long(other);
2148 if (other == NULL) {
2149 PyErr_Clear();
2150 Py_RETURN_NOTIMPLEMENTED;
2151 }
2152 int64_t otherid = PyLong_AsLongLong(other);
2153 Py_DECREF(other);
2154 if (otherid == -1 && PyErr_Occurred() != NULL) {
2155 return NULL;
2156 }
2157 if (otherid < 0) {
2158 equal = 0;
2159 }
2160 else {
2161 equal = (id->id == otherid);
2162 }
2163 }
2164
2165 if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
2166 Py_RETURN_TRUE;
2167 }
2168 Py_RETURN_FALSE;
2169}
2170
2171PyDoc_STRVAR(interpid_doc,
2172"A interpreter ID identifies a interpreter and may be used as an int.");
2173
2174static PyTypeObject InterpreterIDtype = {
2175 PyVarObject_HEAD_INIT(&PyType_Type, 0)
2176 "interpreters.InterpreterID", /* tp_name */
Peter Eisentraut0e0bc4e2018-09-10 18:46:08 +02002177 sizeof(interpid), /* tp_basicsize */
Eric Snow4c6955e2018-02-16 18:53:40 -07002178 0, /* tp_itemsize */
2179 (destructor)interpid_dealloc, /* tp_dealloc */
2180 0, /* tp_print */
2181 0, /* tp_getattr */
2182 0, /* tp_setattr */
2183 0, /* tp_as_async */
2184 (reprfunc)interpid_repr, /* tp_repr */
2185 &interpid_as_number, /* tp_as_number */
2186 0, /* tp_as_sequence */
2187 0, /* tp_as_mapping */
2188 interpid_hash, /* tp_hash */
2189 0, /* tp_call */
Eric Snow6d2cd902018-05-16 15:04:57 -04002190 (reprfunc)interpid_str, /* tp_str */
Eric Snow4c6955e2018-02-16 18:53:40 -07002191 0, /* tp_getattro */
2192 0, /* tp_setattro */
2193 0, /* tp_as_buffer */
2194 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
2195 Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
2196 interpid_doc, /* tp_doc */
2197 0, /* tp_traverse */
2198 0, /* tp_clear */
2199 interpid_richcompare, /* tp_richcompare */
2200 0, /* tp_weaklistoffset */
2201 0, /* tp_iter */
2202 0, /* tp_iternext */
2203 0, /* tp_methods */
2204 0, /* tp_members */
2205 0, /* tp_getset */
2206 0, /* tp_base */
2207 0, /* tp_dict */
2208 0, /* tp_descr_get */
2209 0, /* tp_descr_set */
2210 0, /* tp_dictoffset */
2211 0, /* tp_init */
2212 0, /* tp_alloc */
2213 interpid_new, /* tp_new */
2214};
2215
2216static PyObject *
2217_get_id(PyInterpreterState *interp)
2218{
2219 PY_INT64_T id = PyInterpreterState_GetID(interp);
2220 if (id < 0) {
2221 return NULL;
2222 }
2223 return (PyObject *)newinterpid(&InterpreterIDtype, id, 0);
2224}
2225
2226static PyInterpreterState *
2227_look_up(PyObject *requested_id)
2228{
2229 int64_t id;
2230 if (PyObject_TypeCheck(requested_id, &InterpreterIDtype)) {
2231 id = ((interpid *)requested_id)->id;
2232 }
2233 else {
2234 id = PyLong_AsLongLong(requested_id);
2235 if (id == -1 && PyErr_Occurred() != NULL) {
2236 return NULL;
2237 }
2238 assert(id <= INT64_MAX);
2239 }
2240 return _PyInterpreterState_LookUpID(id);
2241}
2242
Eric Snow7f8bfc92018-01-29 18:23:44 -07002243
2244/* module level code ********************************************************/
2245
2246/* globals is the process-global state for the module. It holds all
2247 the data that we need to share between interpreters, so it cannot
2248 hold PyObject values. */
2249static struct globals {
2250 _channels channels;
2251} _globals = {{0}};
2252
2253static int
2254_init_globals(void)
2255{
2256 if (_channels_init(&_globals.channels) != 0) {
2257 return -1;
2258 }
2259 return 0;
2260}
2261
2262static _channels *
2263_global_channels(void) {
2264 return &_globals.channels;
2265}
2266
2267static PyObject *
2268interp_create(PyObject *self, PyObject *args)
2269{
2270 if (!PyArg_UnpackTuple(args, "create", 0, 0)) {
2271 return NULL;
2272 }
2273
2274 // Create and initialize the new interpreter.
Eric Snowf53d9f22018-02-20 16:30:17 -07002275 PyThreadState *save_tstate = PyThreadState_Swap(NULL);
2276 // XXX Possible GILState issues?
2277 PyThreadState *tstate = Py_NewInterpreter();
Eric Snow7f8bfc92018-01-29 18:23:44 -07002278 PyThreadState_Swap(save_tstate);
2279 if (tstate == NULL) {
2280 /* Since no new thread state was created, there is no exception to
2281 propagate; raise a fresh one after swapping in the old thread
2282 state. */
2283 PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
2284 return NULL;
2285 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002286 if (_PyInterpreterState_IDInitref(tstate->interp) != 0) {
2287 goto error;
2288 };
Eric Snow7f8bfc92018-01-29 18:23:44 -07002289 return _get_id(tstate->interp);
Eric Snow4c6955e2018-02-16 18:53:40 -07002290
2291error:
Eric Snowf53d9f22018-02-20 16:30:17 -07002292 // XXX Possible GILState issues?
Eric Snow4c6955e2018-02-16 18:53:40 -07002293 save_tstate = PyThreadState_Swap(tstate);
2294 Py_EndInterpreter(tstate);
2295 PyThreadState_Swap(save_tstate);
2296 return NULL;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002297}
2298
2299PyDoc_STRVAR(create_doc,
2300"create() -> ID\n\
2301\n\
2302Create a new interpreter and return a unique generated ID.");
2303
2304
2305static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002306interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002307{
Eric Snow6d2cd902018-05-16 15:04:57 -04002308 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002309 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002310 // XXX Use "L" for id?
2311 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2312 "O:destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002313 return NULL;
2314 }
2315 if (!PyLong_Check(id)) {
2316 PyErr_SetString(PyExc_TypeError, "ID must be an int");
2317 return NULL;
2318 }
2319
2320 // Look up the interpreter.
2321 PyInterpreterState *interp = _look_up(id);
2322 if (interp == NULL) {
2323 return NULL;
2324 }
2325
2326 // Ensure we don't try to destroy the current interpreter.
2327 PyInterpreterState *current = _get_current();
2328 if (current == NULL) {
2329 return NULL;
2330 }
2331 if (interp == current) {
2332 PyErr_SetString(PyExc_RuntimeError,
2333 "cannot destroy the current interpreter");
2334 return NULL;
2335 }
2336
2337 // Ensure the interpreter isn't running.
2338 /* XXX We *could* support destroying a running interpreter but
2339 aren't going to worry about it for now. */
2340 if (_ensure_not_running(interp) < 0) {
2341 return NULL;
2342 }
2343
2344 // Destroy the interpreter.
2345 //PyInterpreterState_Delete(interp);
Eric Snowf53d9f22018-02-20 16:30:17 -07002346 PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
2347 // XXX Possible GILState issues?
2348 PyThreadState *save_tstate = PyThreadState_Swap(tstate);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002349 Py_EndInterpreter(tstate);
2350 PyThreadState_Swap(save_tstate);
2351
2352 Py_RETURN_NONE;
2353}
2354
2355PyDoc_STRVAR(destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002356"destroy(id)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002357\n\
2358Destroy the identified interpreter.\n\
2359\n\
2360Attempting to destroy the current interpreter results in a RuntimeError.\n\
2361So does an unrecognized ID.");
2362
2363
2364static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302365interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002366{
2367 PyObject *ids, *id;
2368 PyInterpreterState *interp;
2369
2370 ids = PyList_New(0);
2371 if (ids == NULL) {
2372 return NULL;
2373 }
2374
2375 interp = PyInterpreterState_Head();
2376 while (interp != NULL) {
2377 id = _get_id(interp);
2378 if (id == NULL) {
2379 Py_DECREF(ids);
2380 return NULL;
2381 }
2382 // insert at front of list
Eric Snow4e9da0d2018-02-02 21:49:49 -07002383 int res = PyList_Insert(ids, 0, id);
2384 Py_DECREF(id);
2385 if (res < 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002386 Py_DECREF(ids);
2387 return NULL;
2388 }
2389
2390 interp = PyInterpreterState_Next(interp);
2391 }
2392
2393 return ids;
2394}
2395
2396PyDoc_STRVAR(list_all_doc,
2397"list_all() -> [ID]\n\
2398\n\
2399Return a list containing the ID of every existing interpreter.");
2400
2401
2402static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302403interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002404{
2405 PyInterpreterState *interp =_get_current();
2406 if (interp == NULL) {
2407 return NULL;
2408 }
2409 return _get_id(interp);
2410}
2411
2412PyDoc_STRVAR(get_current_doc,
2413"get_current() -> ID\n\
2414\n\
2415Return the ID of current interpreter.");
2416
2417
2418static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302419interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002420{
2421 // Currently, 0 is always the main interpreter.
Eric Snow6d2cd902018-05-16 15:04:57 -04002422 PY_INT64_T id = 0;
2423 return (PyObject *)newinterpid(&InterpreterIDtype, id, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002424}
2425
2426PyDoc_STRVAR(get_main_doc,
2427"get_main() -> ID\n\
2428\n\
2429Return the ID of main interpreter.");
2430
2431
2432static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002433interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002434{
Eric Snow6d2cd902018-05-16 15:04:57 -04002435 static char *kwlist[] = {"id", "script", "shared", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002436 PyObject *id, *code;
2437 PyObject *shared = NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002438 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2439 "OU|O:run_string", kwlist,
2440 &id, &code, &shared)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002441 return NULL;
2442 }
2443 if (!PyLong_Check(id)) {
2444 PyErr_SetString(PyExc_TypeError, "first arg (ID) must be an int");
2445 return NULL;
2446 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002447
2448 // Look up the interpreter.
2449 PyInterpreterState *interp = _look_up(id);
2450 if (interp == NULL) {
2451 return NULL;
2452 }
2453
2454 // Extract code.
2455 Py_ssize_t size;
2456 const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
2457 if (codestr == NULL) {
2458 return NULL;
2459 }
2460 if (strlen(codestr) != (size_t)size) {
2461 PyErr_SetString(PyExc_ValueError,
2462 "source code string cannot contain null bytes");
2463 return NULL;
2464 }
2465
2466 // Run the code in the interpreter.
2467 if (_run_script_in_interpreter(interp, codestr, shared) != 0) {
2468 return NULL;
2469 }
2470 Py_RETURN_NONE;
2471}
2472
2473PyDoc_STRVAR(run_string_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002474"run_string(id, script, shared)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002475\n\
2476Execute the provided string in the identified interpreter.\n\
2477\n\
2478See PyRun_SimpleStrings.");
2479
2480
2481static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002482object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002483{
Eric Snow6d2cd902018-05-16 15:04:57 -04002484 static char *kwlist[] = {"obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002485 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002486 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2487 "O:is_shareable", kwlist, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002488 return NULL;
2489 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002490
Eric Snow7f8bfc92018-01-29 18:23:44 -07002491 if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
2492 Py_RETURN_TRUE;
2493 }
2494 PyErr_Clear();
2495 Py_RETURN_FALSE;
2496}
2497
2498PyDoc_STRVAR(is_shareable_doc,
2499"is_shareable(obj) -> bool\n\
2500\n\
2501Return True if the object's data may be shared between interpreters and\n\
2502False otherwise.");
2503
2504
2505static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002506interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002507{
Eric Snow6d2cd902018-05-16 15:04:57 -04002508 static char *kwlist[] = {"id", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002509 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002510 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2511 "O:is_running", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002512 return NULL;
2513 }
2514 if (!PyLong_Check(id)) {
2515 PyErr_SetString(PyExc_TypeError, "ID must be an int");
2516 return NULL;
2517 }
2518
2519 PyInterpreterState *interp = _look_up(id);
2520 if (interp == NULL) {
2521 return NULL;
2522 }
2523 int is_running = _is_running(interp);
2524 if (is_running < 0) {
2525 return NULL;
2526 }
2527 if (is_running) {
2528 Py_RETURN_TRUE;
2529 }
2530 Py_RETURN_FALSE;
2531}
2532
2533PyDoc_STRVAR(is_running_doc,
2534"is_running(id) -> bool\n\
2535\n\
2536Return whether or not the identified interpreter is running.");
2537
2538static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302539channel_create(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002540{
2541 int64_t cid = _channel_create(&_globals.channels);
2542 if (cid < 0) {
2543 return NULL;
2544 }
2545 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, cid, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002546 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002547 if (id == NULL) {
2548 if (_channel_destroy(&_globals.channels, cid) != 0) {
2549 // XXX issue a warning?
2550 }
2551 return NULL;
2552 }
2553 assert(((channelid *)id)->channels != NULL);
2554 return id;
2555}
2556
2557PyDoc_STRVAR(channel_create_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002558"channel_create() -> cid\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002559\n\
2560Create a new cross-interpreter channel and return a unique generated ID.");
2561
2562static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002563channel_destroy(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002564{
Eric Snow6d2cd902018-05-16 15:04:57 -04002565 static char *kwlist[] = {"cid", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002566 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002567 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2568 "O:channel_destroy", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002569 return NULL;
2570 }
2571 int64_t cid = _coerce_id(id);
2572 if (cid < 0) {
2573 return NULL;
2574 }
2575
2576 if (_channel_destroy(&_globals.channels, cid) != 0) {
2577 return NULL;
2578 }
2579 Py_RETURN_NONE;
2580}
2581
2582PyDoc_STRVAR(channel_destroy_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002583"channel_destroy(cid)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002584\n\
2585Close and finalize the channel. Afterward attempts to use the channel\n\
2586will behave as though it never existed.");
2587
2588static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302589channel_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
Eric Snow7f8bfc92018-01-29 18:23:44 -07002590{
2591 int64_t count = 0;
2592 int64_t *cids = _channels_list_all(&_globals.channels, &count);
2593 if (cids == NULL) {
2594 if (count == 0) {
2595 return PyList_New(0);
2596 }
2597 return NULL;
2598 }
2599 PyObject *ids = PyList_New((Py_ssize_t)count);
2600 if (ids == NULL) {
Eric Snow4e9da0d2018-02-02 21:49:49 -07002601 goto finally;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002602 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002603 int64_t *cur = cids;
2604 for (int64_t i=0; i < count; cur++, i++) {
2605 PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cur, 0,
Eric Snow6d2cd902018-05-16 15:04:57 -04002606 &_globals.channels, 0, 0);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002607 if (id == NULL) {
2608 Py_DECREF(ids);
2609 ids = NULL;
2610 break;
2611 }
2612 PyList_SET_ITEM(ids, i, id);
2613 }
Eric Snow4e9da0d2018-02-02 21:49:49 -07002614
2615finally:
2616 PyMem_Free(cids);
Eric Snow7f8bfc92018-01-29 18:23:44 -07002617 return ids;
2618}
2619
2620PyDoc_STRVAR(channel_list_all_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002621"channel_list_all() -> [cid]\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002622\n\
2623Return the list of all IDs for active channels.");
2624
2625static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002626channel_send(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002627{
Eric Snow6d2cd902018-05-16 15:04:57 -04002628 static char *kwlist[] = {"cid", "obj", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002629 PyObject *id;
2630 PyObject *obj;
Eric Snow6d2cd902018-05-16 15:04:57 -04002631 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2632 "OO:channel_send", kwlist, &id, &obj)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002633 return NULL;
2634 }
2635 int64_t cid = _coerce_id(id);
2636 if (cid < 0) {
2637 return NULL;
2638 }
2639
2640 if (_channel_send(&_globals.channels, cid, obj) != 0) {
2641 return NULL;
2642 }
2643 Py_RETURN_NONE;
2644}
2645
2646PyDoc_STRVAR(channel_send_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002647"channel_send(cid, obj)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002648\n\
2649Add the object's data to the channel's queue.");
2650
2651static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002652channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002653{
Eric Snow6d2cd902018-05-16 15:04:57 -04002654 static char *kwlist[] = {"cid", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002655 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002656 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2657 "O:channel_recv", kwlist, &id)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002658 return NULL;
2659 }
2660 int64_t cid = _coerce_id(id);
2661 if (cid < 0) {
2662 return NULL;
2663 }
2664
2665 return _channel_recv(&_globals.channels, cid);
2666}
2667
2668PyDoc_STRVAR(channel_recv_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002669"channel_recv(cid) -> obj\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002670\n\
2671Return a new object from the data at the from of the channel's queue.");
2672
2673static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002674channel_close(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002675{
Eric Snow6d2cd902018-05-16 15:04:57 -04002676 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
2677 PyObject *id;
2678 int send = 0;
2679 int recv = 0;
2680 int force = 0;
2681 if (!PyArg_ParseTupleAndKeywords(args, kwds,
2682 "O|$ppp:channel_close", kwlist,
2683 &id, &send, &recv, &force)) {
2684 return NULL;
2685 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002686 int64_t cid = _coerce_id(id);
2687 if (cid < 0) {
2688 return NULL;
2689 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002690
Eric Snow3ab01362018-05-17 10:27:09 -04002691 if (_channel_close(&_globals.channels, cid, send-recv, force) != 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002692 return NULL;
2693 }
2694 Py_RETURN_NONE;
2695}
2696
2697PyDoc_STRVAR(channel_close_doc,
Eric Snow6d2cd902018-05-16 15:04:57 -04002698"channel_close(cid, *, send=None, recv=None, force=False)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002699\n\
Eric Snow6d2cd902018-05-16 15:04:57 -04002700Close the channel for all interpreters.\n\
2701\n\
2702If the channel is empty then the keyword args are ignored and both\n\
2703ends are immediately closed. Otherwise, if 'force' is True then\n\
2704all queued items are released and both ends are immediately\n\
2705closed.\n\
2706\n\
2707If the channel is not empty *and* 'force' is False then following\n\
2708happens:\n\
2709\n\
2710 * recv is True (regardless of send):\n\
2711 - raise ChannelNotEmptyError\n\
2712 * recv is None and send is None:\n\
2713 - raise ChannelNotEmptyError\n\
2714 * send is True and recv is not True:\n\
2715 - fully close the 'send' end\n\
2716 - close the 'recv' end to interpreters not already receiving\n\
2717 - fully close it once empty\n\
2718\n\
2719Closing an already closed channel results in a ChannelClosedError.\n\
2720\n\
2721Once the channel's ID has no more ref counts in any interpreter\n\
2722the channel will be destroyed.");
Eric Snow7f8bfc92018-01-29 18:23:44 -07002723
2724static PyObject *
Eric Snow6d2cd902018-05-16 15:04:57 -04002725channel_release(PyObject *self, PyObject *args, PyObject *kwds)
Eric Snow7f8bfc92018-01-29 18:23:44 -07002726{
2727 // Note that only the current interpreter is affected.
Eric Snow6d2cd902018-05-16 15:04:57 -04002728 static char *kwlist[] = {"cid", "send", "recv", "force", NULL};
Eric Snow7f8bfc92018-01-29 18:23:44 -07002729 PyObject *id;
Eric Snow6d2cd902018-05-16 15:04:57 -04002730 int send = 0;
2731 int recv = 0;
2732 int force = 0;
Eric Snow7f8bfc92018-01-29 18:23:44 -07002733 if (!PyArg_ParseTupleAndKeywords(args, kwds,
Eric Snow6d2cd902018-05-16 15:04:57 -04002734 "O|$ppp:channel_release", kwlist,
2735 &id, &send, &recv, &force)) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002736 return NULL;
Eric Snow6d2cd902018-05-16 15:04:57 -04002737 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002738 int64_t cid = _coerce_id(id);
2739 if (cid < 0) {
2740 return NULL;
2741 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002742 if (send == 0 && recv == 0) {
Eric Snow7f8bfc92018-01-29 18:23:44 -07002743 send = 1;
2744 recv = 1;
2745 }
Eric Snow6d2cd902018-05-16 15:04:57 -04002746
2747 // XXX Handle force is True.
2748 // XXX Fix implicit release.
2749
Eric Snow7f8bfc92018-01-29 18:23:44 -07002750 if (_channel_drop(&_globals.channels, cid, send, recv) != 0) {
2751 return NULL;
2752 }
2753 Py_RETURN_NONE;
2754}
2755
Eric Snow6d2cd902018-05-16 15:04:57 -04002756PyDoc_STRVAR(channel_release_doc,
2757"channel_release(cid, *, send=None, recv=None, force=True)\n\
Eric Snow7f8bfc92018-01-29 18:23:44 -07002758\n\
2759Close the channel for the current interpreter. 'send' and 'recv'\n\
2760(bool) may be used to indicate the ends to close. By default both\n\
2761ends are closed. Closing an already closed end is a noop.");
2762
2763static PyObject *
2764channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds)
2765{
2766 return channelid_new(&ChannelIDtype, args, kwds);
2767}
2768
2769static PyMethodDef module_functions[] = {
2770 {"create", (PyCFunction)interp_create,
2771 METH_VARARGS, create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002772 {"destroy", (PyCFunction)(void(*)(void))interp_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002773 METH_VARARGS | METH_KEYWORDS, destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302774 {"list_all", interp_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002775 METH_NOARGS, list_all_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302776 {"get_current", interp_get_current,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002777 METH_NOARGS, get_current_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302778 {"get_main", interp_get_main,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002779 METH_NOARGS, get_main_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002780 {"is_running", (PyCFunction)(void(*)(void))interp_is_running,
Eric Snow6d2cd902018-05-16 15:04:57 -04002781 METH_VARARGS | METH_KEYWORDS, is_running_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002782 {"run_string", (PyCFunction)(void(*)(void))interp_run_string,
Eric Snow6d2cd902018-05-16 15:04:57 -04002783 METH_VARARGS | METH_KEYWORDS, run_string_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002784
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002785 {"is_shareable", (PyCFunction)(void(*)(void))object_is_shareable,
Eric Snow6d2cd902018-05-16 15:04:57 -04002786 METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
Eric Snow7f8bfc92018-01-29 18:23:44 -07002787
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302788 {"channel_create", channel_create,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002789 METH_NOARGS, channel_create_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002790 {"channel_destroy", (PyCFunction)(void(*)(void))channel_destroy,
Eric Snow6d2cd902018-05-16 15:04:57 -04002791 METH_VARARGS | METH_KEYWORDS, channel_destroy_doc},
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +05302792 {"channel_list_all", channel_list_all,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002793 METH_NOARGS, channel_list_all_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002794 {"channel_send", (PyCFunction)(void(*)(void))channel_send,
Eric Snow6d2cd902018-05-16 15:04:57 -04002795 METH_VARARGS | METH_KEYWORDS, channel_send_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002796 {"channel_recv", (PyCFunction)(void(*)(void))channel_recv,
Eric Snow6d2cd902018-05-16 15:04:57 -04002797 METH_VARARGS | METH_KEYWORDS, channel_recv_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002798 {"channel_close", (PyCFunction)(void(*)(void))channel_close,
Eric Snow6d2cd902018-05-16 15:04:57 -04002799 METH_VARARGS | METH_KEYWORDS, channel_close_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002800 {"channel_release", (PyCFunction)(void(*)(void))channel_release,
Eric Snow6d2cd902018-05-16 15:04:57 -04002801 METH_VARARGS | METH_KEYWORDS, channel_release_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +02002802 {"_channel_id", (PyCFunction)(void(*)(void))channel__channel_id,
Eric Snow7f8bfc92018-01-29 18:23:44 -07002803 METH_VARARGS | METH_KEYWORDS, NULL},
2804
2805 {NULL, NULL} /* sentinel */
2806};
2807
2808
2809/* initialization function */
2810
2811PyDoc_STRVAR(module_doc,
2812"This module provides primitive operations to manage Python interpreters.\n\
2813The 'interpreters' module provides a more convenient interface.");
2814
2815static struct PyModuleDef interpretersmodule = {
2816 PyModuleDef_HEAD_INIT,
2817 "_xxsubinterpreters", /* m_name */
2818 module_doc, /* m_doc */
2819 -1, /* m_size */
2820 module_functions, /* m_methods */
2821 NULL, /* m_slots */
2822 NULL, /* m_traverse */
2823 NULL, /* m_clear */
2824 NULL /* m_free */
2825};
2826
2827
2828PyMODINIT_FUNC
2829PyInit__xxsubinterpreters(void)
2830{
2831 if (_init_globals() != 0) {
2832 return NULL;
2833 }
2834
2835 /* Initialize types */
2836 ChannelIDtype.tp_base = &PyLong_Type;
2837 if (PyType_Ready(&ChannelIDtype) != 0) {
2838 return NULL;
2839 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002840 InterpreterIDtype.tp_base = &PyLong_Type;
2841 if (PyType_Ready(&InterpreterIDtype) != 0) {
2842 return NULL;
2843 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002844
2845 /* Create the module */
2846 PyObject *module = PyModule_Create(&interpretersmodule);
2847 if (module == NULL) {
2848 return NULL;
2849 }
2850
2851 /* Add exception types */
2852 PyObject *ns = PyModule_GetDict(module); // borrowed
2853 if (interp_exceptions_init(ns) != 0) {
2854 return NULL;
2855 }
2856 if (channel_exceptions_init(ns) != 0) {
2857 return NULL;
2858 }
2859
2860 /* Add other types */
2861 Py_INCREF(&ChannelIDtype);
2862 if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
2863 return NULL;
2864 }
Eric Snow4c6955e2018-02-16 18:53:40 -07002865 Py_INCREF(&InterpreterIDtype);
2866 if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&InterpreterIDtype) != 0) {
2867 return NULL;
2868 }
Eric Snow7f8bfc92018-01-29 18:23:44 -07002869
2870 if (_PyCrossInterpreterData_Register_Class(&ChannelIDtype, _channelid_shared)) {
2871 return NULL;
2872 }
2873
2874 return module;
2875}