mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	gh-132781: Cleanup Code Related to NotShareableError (gh-132782)
The following are added to the internal C-API: * _PyErr_FormatV() * _PyErr_SetModuleNotFoundError() * _PyXIData_GetNotShareableErrorType() * _PyXIData_FormatNotShareableError() We also drop _PyXIData_lookup_context_t and _PyXIData_GetLookupContext().
This commit is contained in:
		
							parent
							
								
									4c20f46fa0
								
							
						
					
					
						commit
						cd9536a087
					
				
					 14 changed files with 322 additions and 177 deletions
				
			
		|  | @ -97,26 +97,22 @@ PyAPI_FUNC(void) _PyXIData_Free(_PyXIData_t *data); | ||||||
| 
 | 
 | ||||||
| typedef int (*xidatafunc)(PyThreadState *tstate, PyObject *, _PyXIData_t *); | typedef int (*xidatafunc)(PyThreadState *tstate, PyObject *, _PyXIData_t *); | ||||||
| 
 | 
 | ||||||
| typedef struct _xid_lookup_state _PyXIData_lookup_t; | PyAPI_FUNC(PyObject *) _PyXIData_GetNotShareableErrorType(PyThreadState *); | ||||||
| 
 | PyAPI_FUNC(void) _PyXIData_SetNotShareableError(PyThreadState *, const char *); | ||||||
| typedef struct { | PyAPI_FUNC(void) _PyXIData_FormatNotShareableError( | ||||||
|     _PyXIData_lookup_t *global; |         PyThreadState *, | ||||||
|     _PyXIData_lookup_t *local; |         const char *, | ||||||
|     PyObject *PyExc_NotShareableError; |         ...); | ||||||
| } _PyXIData_lookup_context_t; |  | ||||||
| 
 |  | ||||||
| PyAPI_FUNC(int) _PyXIData_GetLookupContext( |  | ||||||
|         PyInterpreterState *, |  | ||||||
|         _PyXIData_lookup_context_t *); |  | ||||||
| 
 | 
 | ||||||
| PyAPI_FUNC(xidatafunc) _PyXIData_Lookup( | PyAPI_FUNC(xidatafunc) _PyXIData_Lookup( | ||||||
|         _PyXIData_lookup_context_t *, |         PyThreadState *, | ||||||
|         PyObject *); |         PyObject *); | ||||||
| PyAPI_FUNC(int) _PyObject_CheckXIData( | PyAPI_FUNC(int) _PyObject_CheckXIData( | ||||||
|         _PyXIData_lookup_context_t *, |         PyThreadState *, | ||||||
|         PyObject *); |         PyObject *); | ||||||
|  | 
 | ||||||
| PyAPI_FUNC(int) _PyObject_GetXIData( | PyAPI_FUNC(int) _PyObject_GetXIData( | ||||||
|         _PyXIData_lookup_context_t *, |         PyThreadState *, | ||||||
|         PyObject *, |         PyObject *, | ||||||
|         _PyXIData_t *); |         _PyXIData_t *); | ||||||
| 
 | 
 | ||||||
|  | @ -171,6 +167,8 @@ PyAPI_FUNC(void) _PyXIData_Clear( PyInterpreterState *, _PyXIData_t *); | ||||||
| /* runtime state & lifecycle */ | /* runtime state & lifecycle */ | ||||||
| /*****************************/ | /*****************************/ | ||||||
| 
 | 
 | ||||||
|  | typedef struct _xid_lookup_state _PyXIData_lookup_t; | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     // builtin types
 |     // builtin types
 | ||||||
|     _PyXIData_lookup_t data_lookup; |     _PyXIData_lookup_t data_lookup; | ||||||
|  |  | ||||||
|  | @ -28,11 +28,11 @@ typedef struct { | ||||||
| } _PyXIData_registry_t; | } _PyXIData_registry_t; | ||||||
| 
 | 
 | ||||||
| PyAPI_FUNC(int) _PyXIData_RegisterClass( | PyAPI_FUNC(int) _PyXIData_RegisterClass( | ||||||
|     _PyXIData_lookup_context_t *, |     PyThreadState *, | ||||||
|     PyTypeObject *, |     PyTypeObject *, | ||||||
|     xidatafunc); |     xidatafunc); | ||||||
| PyAPI_FUNC(int) _PyXIData_UnregisterClass( | PyAPI_FUNC(int) _PyXIData_UnregisterClass( | ||||||
|     _PyXIData_lookup_context_t *, |     PyThreadState *, | ||||||
|     PyTypeObject *); |     PyTypeObject *); | ||||||
| 
 | 
 | ||||||
| struct _xid_lookup_state { | struct _xid_lookup_state { | ||||||
|  |  | ||||||
|  | @ -60,6 +60,7 @@ extern PyObject* _PyErr_SetImportErrorWithNameFrom( | ||||||
|         PyObject *, |         PyObject *, | ||||||
|         PyObject *, |         PyObject *, | ||||||
|         PyObject *); |         PyObject *); | ||||||
|  | extern int _PyErr_SetModuleNotFoundError(PyObject *name); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* runtime lifecycle */ | /* runtime lifecycle */ | ||||||
|  | @ -113,6 +114,7 @@ extern void _PyErr_SetObject( | ||||||
|     PyObject *value); |     PyObject *value); | ||||||
| 
 | 
 | ||||||
| extern void _PyErr_ChainStackItem(void); | extern void _PyErr_ChainStackItem(void); | ||||||
|  | extern void _PyErr_ChainExceptions1Tstate(PyThreadState *, PyObject *); | ||||||
| 
 | 
 | ||||||
| PyAPI_FUNC(void) _PyErr_Clear(PyThreadState *tstate); | PyAPI_FUNC(void) _PyErr_Clear(PyThreadState *tstate); | ||||||
| 
 | 
 | ||||||
|  | @ -148,6 +150,12 @@ PyAPI_FUNC(PyObject*) _PyErr_Format( | ||||||
|     const char *format, |     const char *format, | ||||||
|     ...); |     ...); | ||||||
| 
 | 
 | ||||||
|  | PyAPI_FUNC(PyObject*) _PyErr_FormatV( | ||||||
|  |     PyThreadState *tstate, | ||||||
|  |     PyObject *exception, | ||||||
|  |     const char *format, | ||||||
|  |     va_list vargs); | ||||||
|  | 
 | ||||||
| extern void _PyErr_NormalizeException( | extern void _PyErr_NormalizeException( | ||||||
|     PyThreadState *tstate, |     PyThreadState *tstate, | ||||||
|     PyObject **exc, |     PyObject **exc, | ||||||
|  |  | ||||||
|  | @ -15,7 +15,7 @@ | ||||||
| 
 | 
 | ||||||
| _interpreters = import_helper.import_module('_interpreters') | _interpreters = import_helper.import_module('_interpreters') | ||||||
| _testinternalcapi = import_helper.import_module('_testinternalcapi') | _testinternalcapi = import_helper.import_module('_testinternalcapi') | ||||||
| from _interpreters import InterpreterNotFoundError | from _interpreters import InterpreterNotFoundError, NotShareableError | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ################################## | ################################## | ||||||
|  | @ -189,8 +189,9 @@ def test_non_shareable_int(self): | ||||||
|         ] |         ] | ||||||
|         for i in ints: |         for i in ints: | ||||||
|             with self.subTest(i): |             with self.subTest(i): | ||||||
|                 with self.assertRaises(OverflowError): |                 with self.assertRaises(NotShareableError) as cm: | ||||||
|                     _testinternalcapi.get_crossinterp_data(i) |                     _testinternalcapi.get_crossinterp_data(i) | ||||||
|  |                 self.assertIsInstance(cm.exception.__cause__, OverflowError) | ||||||
| 
 | 
 | ||||||
|     def test_bool(self): |     def test_bool(self): | ||||||
|         self._assert_values([True, False]) |         self._assert_values([True, False]) | ||||||
|  | @ -215,14 +216,12 @@ def test_tuples_containing_non_shareable_types(self): | ||||||
|         for s in non_shareables: |         for s in non_shareables: | ||||||
|             value = tuple([0, 1.0, s]) |             value = tuple([0, 1.0, s]) | ||||||
|             with self.subTest(repr(value)): |             with self.subTest(repr(value)): | ||||||
|                 # XXX Assert the NotShareableError when it is exported |                 with self.assertRaises(NotShareableError): | ||||||
|                 with self.assertRaises(ValueError): |  | ||||||
|                     _testinternalcapi.get_crossinterp_data(value) |                     _testinternalcapi.get_crossinterp_data(value) | ||||||
|             # Check nested as well |             # Check nested as well | ||||||
|             value = tuple([0, 1., (s,)]) |             value = tuple([0, 1., (s,)]) | ||||||
|             with self.subTest("nested " + repr(value)): |             with self.subTest("nested " + repr(value)): | ||||||
|                 # XXX Assert the NotShareableError when it is exported |                 with self.assertRaises(NotShareableError): | ||||||
|                 with self.assertRaises(ValueError): |  | ||||||
|                     _testinternalcapi.get_crossinterp_data(value) |                     _testinternalcapi.get_crossinterp_data(value) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -693,8 +693,7 @@ def test_dict_and_kwargs(self): | ||||||
| 
 | 
 | ||||||
|     def test_not_shareable(self): |     def test_not_shareable(self): | ||||||
|         interp = interpreters.create() |         interp = interpreters.create() | ||||||
|         # XXX TypeError? |         with self.assertRaises(interpreters.NotShareableError): | ||||||
|         with self.assertRaises(ValueError): |  | ||||||
|             interp.prepare_main(spam={'spam': 'eggs', 'foo': 'bar'}) |             interp.prepare_main(spam={'spam': 'eggs', 'foo': 'bar'}) | ||||||
| 
 | 
 | ||||||
|         # Make sure neither was actually bound. |         # Make sure neither was actually bound. | ||||||
|  |  | ||||||
|  | @ -1754,17 +1754,10 @@ static int | ||||||
| channel_send(_channels *channels, int64_t cid, PyObject *obj, | channel_send(_channels *channels, int64_t cid, PyObject *obj, | ||||||
|              _waiting_t *waiting, int unboundop) |              _waiting_t *waiting, int unboundop) | ||||||
| { | { | ||||||
|     PyInterpreterState *interp = _get_current_interp(); |     PyThreadState *tstate = _PyThreadState_GET(); | ||||||
|     if (interp == NULL) { |     PyInterpreterState *interp = tstate->interp; | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
|     int64_t interpid = PyInterpreterState_GetID(interp); |     int64_t interpid = PyInterpreterState_GetID(interp); | ||||||
| 
 | 
 | ||||||
|     _PyXIData_lookup_context_t ctx; |  | ||||||
|     if (_PyXIData_GetLookupContext(interp, &ctx) < 0) { |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Look up the channel.
 |     // Look up the channel.
 | ||||||
|     PyThread_type_lock mutex = NULL; |     PyThread_type_lock mutex = NULL; | ||||||
|     _channel_state *chan = NULL; |     _channel_state *chan = NULL; | ||||||
|  | @ -1786,7 +1779,7 @@ channel_send(_channels *channels, int64_t cid, PyObject *obj, | ||||||
|         PyThread_release_lock(mutex); |         PyThread_release_lock(mutex); | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|     if (_PyObject_GetXIData(&ctx, obj, data) != 0) { |     if (_PyObject_GetXIData(tstate, obj, data) != 0) { | ||||||
|         PyThread_release_lock(mutex); |         PyThread_release_lock(mutex); | ||||||
|         GLOBAL_FREE(data); |         GLOBAL_FREE(data); | ||||||
|         return -1; |         return -1; | ||||||
|  |  | ||||||
|  | @ -1127,11 +1127,7 @@ queue_destroy(_queues *queues, int64_t qid) | ||||||
| static int | static int | ||||||
| queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt, int unboundop) | queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt, int unboundop) | ||||||
| { | { | ||||||
|     PyInterpreterState *interp = PyInterpreterState_Get(); |     PyThreadState *tstate = PyThreadState_Get(); | ||||||
|     _PyXIData_lookup_context_t ctx; |  | ||||||
|     if (_PyXIData_GetLookupContext(interp, &ctx) < 0) { |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // Look up the queue.
 |     // Look up the queue.
 | ||||||
|     _queue *queue = NULL; |     _queue *queue = NULL; | ||||||
|  | @ -1147,12 +1143,13 @@ queue_put(_queues *queues, int64_t qid, PyObject *obj, int fmt, int unboundop) | ||||||
|         _queue_unmark_waiter(queue, queues->mutex); |         _queue_unmark_waiter(queue, queues->mutex); | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|     if (_PyObject_GetXIData(&ctx, obj, data) != 0) { |     if (_PyObject_GetXIData(tstate, obj, data) != 0) { | ||||||
|         _queue_unmark_waiter(queue, queues->mutex); |         _queue_unmark_waiter(queue, queues->mutex); | ||||||
|         GLOBAL_FREE(data); |         GLOBAL_FREE(data); | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|     assert(_PyXIData_INTERPID(data) == PyInterpreterState_GetID(interp)); |     assert(_PyXIData_INTERPID(data) == | ||||||
|  |             PyInterpreterState_GetID(tstate->interp)); | ||||||
| 
 | 
 | ||||||
|     // Add the data to the queue.
 |     // Add the data to the queue.
 | ||||||
|     int64_t interpid = -1;  // _queueitem_init() will set it.
 |     int64_t interpid = -1;  // _queueitem_init() will set it.
 | ||||||
|  |  | ||||||
|  | @ -8,24 +8,16 @@ | ||||||
| static int | static int | ||||||
| ensure_xid_class(PyTypeObject *cls, xidatafunc getdata) | ensure_xid_class(PyTypeObject *cls, xidatafunc getdata) | ||||||
| { | { | ||||||
|     PyInterpreterState *interp = PyInterpreterState_Get(); |     PyThreadState *tstate = PyThreadState_Get(); | ||||||
|     _PyXIData_lookup_context_t ctx; |     return _PyXIData_RegisterClass(tstate, cls, getdata); | ||||||
|     if (_PyXIData_GetLookupContext(interp, &ctx) < 0) { |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
|     return _PyXIData_RegisterClass(&ctx, cls, getdata); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef REGISTERS_HEAP_TYPES | #ifdef REGISTERS_HEAP_TYPES | ||||||
| static int | static int | ||||||
| clear_xid_class(PyTypeObject *cls) | clear_xid_class(PyTypeObject *cls) | ||||||
| { | { | ||||||
|     PyInterpreterState *interp = PyInterpreterState_Get(); |     PyThreadState *tstate = PyThreadState_Get(); | ||||||
|     _PyXIData_lookup_context_t ctx; |     return _PyXIData_UnregisterClass(tstate, cls); | ||||||
|     if (_PyXIData_GetLookupContext(interp, &ctx) < 0) { |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
|     return _PyXIData_UnregisterClass(&ctx, cls); |  | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1278,13 +1278,8 @@ object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds) | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     PyInterpreterState *interp = PyInterpreterState_Get(); |     PyThreadState *tstate = _PyThreadState_GET(); | ||||||
|     _PyXIData_lookup_context_t ctx; |     if (_PyObject_CheckXIData(tstate, obj) == 0) { | ||||||
|     if (_PyXIData_GetLookupContext(interp, &ctx) < 0) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (_PyObject_CheckXIData(&ctx, obj) == 0) { |  | ||||||
|         Py_RETURN_TRUE; |         Py_RETURN_TRUE; | ||||||
|     } |     } | ||||||
|     PyErr_Clear(); |     PyErr_Clear(); | ||||||
|  | @ -1577,14 +1572,9 @@ The 'interpreters' module provides a more convenient interface."); | ||||||
| static int | static int | ||||||
| module_exec(PyObject *mod) | module_exec(PyObject *mod) | ||||||
| { | { | ||||||
|     PyInterpreterState *interp = PyInterpreterState_Get(); |     PyThreadState *tstate = _PyThreadState_GET(); | ||||||
|     module_state *state = get_module_state(mod); |     module_state *state = get_module_state(mod); | ||||||
| 
 | 
 | ||||||
|     _PyXIData_lookup_context_t ctx; |  | ||||||
|     if (_PyXIData_GetLookupContext(interp, &ctx) < 0) { |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| #define ADD_WHENCE(NAME) \ | #define ADD_WHENCE(NAME) \ | ||||||
|     if (PyModule_AddIntConstant(mod, "WHENCE_" #NAME,                   \ |     if (PyModule_AddIntConstant(mod, "WHENCE_" #NAME,                   \ | ||||||
|                                 _PyInterpreterState_WHENCE_##NAME) < 0) \ |                                 _PyInterpreterState_WHENCE_##NAME) < 0) \ | ||||||
|  | @ -1606,7 +1596,8 @@ module_exec(PyObject *mod) | ||||||
|     if (PyModule_AddType(mod, (PyTypeObject *)PyExc_InterpreterNotFoundError) < 0) { |     if (PyModule_AddType(mod, (PyTypeObject *)PyExc_InterpreterNotFoundError) < 0) { | ||||||
|         goto error; |         goto error; | ||||||
|     } |     } | ||||||
|     if (PyModule_AddType(mod, (PyTypeObject *)ctx.PyExc_NotShareableError) < 0) { |     PyObject *exctype = _PyXIData_GetNotShareableErrorType(tstate); | ||||||
|  |     if (PyModule_AddType(mod, (PyTypeObject *)exctype) < 0) { | ||||||
|         goto error; |         goto error; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1696,11 +1696,7 @@ _xid_capsule_destructor(PyObject *capsule) | ||||||
| static PyObject * | static PyObject * | ||||||
| get_crossinterp_data(PyObject *self, PyObject *args) | get_crossinterp_data(PyObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     PyInterpreterState *interp = PyInterpreterState_Get(); |     PyThreadState *tstate = _PyThreadState_GET(); | ||||||
|     _PyXIData_lookup_context_t ctx; |  | ||||||
|     if (_PyXIData_GetLookupContext(interp, &ctx) < 0) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     PyObject *obj = NULL; |     PyObject *obj = NULL; | ||||||
|     if (!PyArg_ParseTuple(args, "O:get_crossinterp_data", &obj)) { |     if (!PyArg_ParseTuple(args, "O:get_crossinterp_data", &obj)) { | ||||||
|  | @ -1711,7 +1707,7 @@ get_crossinterp_data(PyObject *self, PyObject *args) | ||||||
|     if (data == NULL) { |     if (data == NULL) { | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|     if (_PyObject_GetXIData(&ctx, obj, data) != 0) { |     if (_PyObject_GetXIData(tstate, obj, data) != 0) { | ||||||
|         _PyXIData_Free(data); |         _PyXIData_Free(data); | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -64,7 +64,8 @@ _Py_CallInInterpreterAndRawFree(PyInterpreterState *interp, | ||||||
| 
 | 
 | ||||||
| static void xid_lookup_init(_PyXIData_lookup_t *); | static void xid_lookup_init(_PyXIData_lookup_t *); | ||||||
| static void xid_lookup_fini(_PyXIData_lookup_t *); | static void xid_lookup_fini(_PyXIData_lookup_t *); | ||||||
| static xidatafunc lookup_getdata(_PyXIData_lookup_context_t *, PyObject *); | struct _dlcontext; | ||||||
|  | static xidatafunc lookup_getdata(struct _dlcontext *, PyObject *); | ||||||
| #include "crossinterp_data_lookup.h" | #include "crossinterp_data_lookup.h" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -198,31 +199,34 @@ _check_xidata(PyThreadState *tstate, _PyXIData_t *data) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void | static inline void | ||||||
| _set_xid_lookup_failure(dlcontext_t *ctx, PyObject *obj, const char *msg) | _set_xid_lookup_failure(PyThreadState *tstate, PyObject *obj, const char *msg, | ||||||
|  |                         PyObject *cause) | ||||||
| { | { | ||||||
|     PyObject *exctype = ctx->PyExc_NotShareableError; |  | ||||||
|     assert(exctype != NULL); |  | ||||||
|     if (msg != NULL) { |     if (msg != NULL) { | ||||||
|         assert(obj == NULL); |         assert(obj == NULL); | ||||||
|         PyErr_SetString(exctype, msg); |         set_notshareableerror(tstate, cause, 0, msg); | ||||||
|     } |     } | ||||||
|     else if (obj == NULL) { |     else if (obj == NULL) { | ||||||
|         PyErr_SetString(exctype, |         msg = "object does not support cross-interpreter data"; | ||||||
|                         "object does not support cross-interpreter data"); |         set_notshareableerror(tstate, cause, 0, msg); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|         PyErr_Format(exctype, |         msg = "%S does not support cross-interpreter data"; | ||||||
|                      "%S does not support cross-interpreter data", obj); |         format_notshareableerror(tstate, cause, 0, msg, obj); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | int | ||||||
| _PyObject_CheckXIData(_PyXIData_lookup_context_t *ctx, PyObject *obj) | _PyObject_CheckXIData(PyThreadState *tstate, PyObject *obj) | ||||||
| { | { | ||||||
|     xidatafunc getdata = lookup_getdata(ctx, obj); |     dlcontext_t ctx; | ||||||
|  |     if (get_lookup_context(tstate, &ctx) < 0) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     xidatafunc getdata = lookup_getdata(&ctx, obj); | ||||||
|     if (getdata == NULL) { |     if (getdata == NULL) { | ||||||
|         if (!PyErr_Occurred()) { |         if (!_PyErr_Occurred(tstate)) { | ||||||
|             _set_xid_lookup_failure(ctx, obj, NULL); |             _set_xid_lookup_failure(tstate, obj, NULL, NULL); | ||||||
|         } |         } | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|  | @ -230,10 +234,9 @@ _PyObject_CheckXIData(_PyXIData_lookup_context_t *ctx, PyObject *obj) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | int | ||||||
| _PyObject_GetXIData(_PyXIData_lookup_context_t *ctx, | _PyObject_GetXIData(PyThreadState *tstate, | ||||||
|                     PyObject *obj, _PyXIData_t *data) |                     PyObject *obj, _PyXIData_t *data) | ||||||
| { | { | ||||||
|     PyThreadState *tstate = PyThreadState_Get(); |  | ||||||
|     PyInterpreterState *interp = tstate->interp; |     PyInterpreterState *interp = tstate->interp; | ||||||
| 
 | 
 | ||||||
|     // Reset data before re-populating.
 |     // Reset data before re-populating.
 | ||||||
|  | @ -241,18 +244,26 @@ _PyObject_GetXIData(_PyXIData_lookup_context_t *ctx, | ||||||
|     _PyXIData_INTERPID(data) = -1; |     _PyXIData_INTERPID(data) = -1; | ||||||
| 
 | 
 | ||||||
|     // Call the "getdata" func for the object.
 |     // Call the "getdata" func for the object.
 | ||||||
|  |     dlcontext_t ctx; | ||||||
|  |     if (get_lookup_context(tstate, &ctx) < 0) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|     Py_INCREF(obj); |     Py_INCREF(obj); | ||||||
|     xidatafunc getdata = lookup_getdata(ctx, obj); |     xidatafunc getdata = lookup_getdata(&ctx, obj); | ||||||
|     if (getdata == NULL) { |     if (getdata == NULL) { | ||||||
|         Py_DECREF(obj); |         Py_DECREF(obj); | ||||||
|         if (!PyErr_Occurred()) { |         if (!_PyErr_Occurred(tstate)) { | ||||||
|             _set_xid_lookup_failure(ctx, obj, NULL); |             _set_xid_lookup_failure(tstate, obj, NULL, NULL); | ||||||
|         } |         } | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|     int res = getdata(tstate, obj, data); |     int res = getdata(tstate, obj, data); | ||||||
|     Py_DECREF(obj); |     Py_DECREF(obj); | ||||||
|     if (res != 0) { |     if (res != 0) { | ||||||
|  |         PyObject *cause = _PyErr_GetRaisedException(tstate); | ||||||
|  |         assert(cause != NULL); | ||||||
|  |         _set_xid_lookup_failure(tstate, obj, NULL, cause); | ||||||
|  |         Py_XDECREF(cause); | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -966,7 +977,7 @@ _PyXI_ClearExcInfo(_PyXI_excinfo *info) | ||||||
| static int | static int | ||||||
| _PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp) | _PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp) | ||||||
| { | { | ||||||
|     dlcontext_t ctx; |     PyThreadState *tstate = _PyThreadState_GET(); | ||||||
| 
 | 
 | ||||||
|     assert(!PyErr_Occurred()); |     assert(!PyErr_Occurred()); | ||||||
|     switch (code) { |     switch (code) { | ||||||
|  | @ -997,10 +1008,7 @@ _PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp) | ||||||
|                         "failed to apply namespace to __main__"); |                         "failed to apply namespace to __main__"); | ||||||
|         break; |         break; | ||||||
|     case _PyXI_ERR_NOT_SHAREABLE: |     case _PyXI_ERR_NOT_SHAREABLE: | ||||||
|         if (_PyXIData_GetLookupContext(interp, &ctx) < 0) { |         _set_xid_lookup_failure(tstate, NULL, NULL, NULL); | ||||||
|             return -1; |  | ||||||
|         } |  | ||||||
|         _set_xid_lookup_failure(&ctx, NULL, NULL); |  | ||||||
|         break; |         break; | ||||||
|     default: |     default: | ||||||
| #ifdef Py_DEBUG | #ifdef Py_DEBUG | ||||||
|  | @ -1056,17 +1064,15 @@ _PyXI_InitError(_PyXI_error *error, PyObject *excobj, _PyXI_errcode code) | ||||||
| PyObject * | PyObject * | ||||||
| _PyXI_ApplyError(_PyXI_error *error) | _PyXI_ApplyError(_PyXI_error *error) | ||||||
| { | { | ||||||
|  |     PyThreadState *tstate = PyThreadState_Get(); | ||||||
|     if (error->code == _PyXI_ERR_UNCAUGHT_EXCEPTION) { |     if (error->code == _PyXI_ERR_UNCAUGHT_EXCEPTION) { | ||||||
|         // Raise an exception that proxies the propagated exception.
 |         // Raise an exception that proxies the propagated exception.
 | ||||||
|        return _PyXI_excinfo_AsObject(&error->uncaught); |        return _PyXI_excinfo_AsObject(&error->uncaught); | ||||||
|     } |     } | ||||||
|     else if (error->code == _PyXI_ERR_NOT_SHAREABLE) { |     else if (error->code == _PyXI_ERR_NOT_SHAREABLE) { | ||||||
|         // Propagate the exception directly.
 |         // Propagate the exception directly.
 | ||||||
|         dlcontext_t ctx; |         assert(!_PyErr_Occurred(tstate)); | ||||||
|         if (_PyXIData_GetLookupContext(error->interp, &ctx) < 0) { |         _set_xid_lookup_failure(tstate, NULL, error->uncaught.msg, NULL); | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
|         _set_xid_lookup_failure(&ctx, NULL, error->uncaught.msg); |  | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|         // Raise an exception corresponding to the code.
 |         // Raise an exception corresponding to the code.
 | ||||||
|  | @ -1153,12 +1159,8 @@ _sharednsitem_set_value(_PyXI_namespace_item *item, PyObject *value) | ||||||
|         PyErr_NoMemory(); |         PyErr_NoMemory(); | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|     PyInterpreterState *interp = PyInterpreterState_Get(); |     PyThreadState *tstate = PyThreadState_Get(); | ||||||
|     dlcontext_t ctx; |     if (_PyObject_GetXIData(tstate, value, item->data) != 0) { | ||||||
|     if (_PyXIData_GetLookupContext(interp, &ctx) < 0) { |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
|     if (_PyObject_GetXIData(&ctx, value, item->data) != 0) { |  | ||||||
|         PyMem_RawFree(item->data); |         PyMem_RawFree(item->data); | ||||||
|         item->data = NULL; |         item->data = NULL; | ||||||
|         // The caller may want to propagate PyExc_NotShareableError
 |         // The caller may want to propagate PyExc_NotShareableError
 | ||||||
|  | @ -1615,14 +1617,14 @@ _propagate_not_shareable_error(_PyXI_session *session) | ||||||
|     if (session == NULL) { |     if (session == NULL) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     PyInterpreterState *interp = PyInterpreterState_Get(); |     PyThreadState *tstate = PyThreadState_Get(); | ||||||
|     dlcontext_t ctx; |     PyObject *exctype = get_notshareableerror_type(tstate); | ||||||
|     if (_PyXIData_GetLookupContext(interp, &ctx) < 0) { |     if (exctype == NULL) { | ||||||
|         PyErr_FormatUnraisable( |         PyErr_FormatUnraisable( | ||||||
|                 "Exception ignored while propagating not shareable error"); |                 "Exception ignored while propagating not shareable error"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     if (PyErr_ExceptionMatches(ctx.PyExc_NotShareableError)) { |     if (PyErr_ExceptionMatches(exctype)) { | ||||||
|         // We want to propagate the exception directly.
 |         // We want to propagate the exception directly.
 | ||||||
|         session->_error_override = _PyXI_ERR_NOT_SHAREABLE; |         session->_error_override = _PyXI_ERR_NOT_SHAREABLE; | ||||||
|         session->error_override = &session->_error_override; |         session->error_override = &session->_error_override; | ||||||
|  |  | ||||||
|  | @ -1,7 +1,10 @@ | ||||||
| #include "pycore_weakref.h"       // _PyWeakref_GET_REF() | #include "pycore_weakref.h"       // _PyWeakref_GET_REF() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| typedef _PyXIData_lookup_context_t dlcontext_t; | typedef struct _dlcontext { | ||||||
|  |     _PyXIData_lookup_t *global; | ||||||
|  |     _PyXIData_lookup_t *local; | ||||||
|  | } dlcontext_t; | ||||||
| typedef _PyXIData_registry_t dlregistry_t; | typedef _PyXIData_registry_t dlregistry_t; | ||||||
| typedef _PyXIData_regitem_t dlregitem_t; | typedef _PyXIData_regitem_t dlregitem_t; | ||||||
| 
 | 
 | ||||||
|  | @ -26,6 +29,26 @@ xid_lookup_fini(_PyXIData_lookup_t *state) | ||||||
|     _xidregistry_fini(&state->registry); |     _xidregistry_fini(&state->registry); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int | ||||||
|  | get_lookup_context(PyThreadState *tstate, dlcontext_t *res) | ||||||
|  | { | ||||||
|  |     _PyXI_global_state_t *global = _PyXI_GET_GLOBAL_STATE(tstate->interp); | ||||||
|  |     if (global == NULL) { | ||||||
|  |         assert(PyErr_Occurred()); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     _PyXI_state_t *local = _PyXI_GET_STATE(tstate->interp); | ||||||
|  |     if (local == NULL) { | ||||||
|  |         assert(PyErr_Occurred()); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     *res = (dlcontext_t){ | ||||||
|  |         .global = &global->data_lookup, | ||||||
|  |         .local = &local->data_lookup, | ||||||
|  |     }; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static xidatafunc | static xidatafunc | ||||||
| lookup_getdata(dlcontext_t *ctx, PyObject *obj) | lookup_getdata(dlcontext_t *ctx, PyObject *obj) | ||||||
| { | { | ||||||
|  | @ -38,32 +61,41 @@ lookup_getdata(dlcontext_t *ctx, PyObject *obj) | ||||||
| 
 | 
 | ||||||
| /* exported API */ | /* exported API */ | ||||||
| 
 | 
 | ||||||
| int | PyObject * | ||||||
| _PyXIData_GetLookupContext(PyInterpreterState *interp, | _PyXIData_GetNotShareableErrorType(PyThreadState *tstate) | ||||||
|                            _PyXIData_lookup_context_t *res) |  | ||||||
| { | { | ||||||
|     _PyXI_global_state_t *global = _PyXI_GET_GLOBAL_STATE(interp); |     PyObject *exctype = get_notshareableerror_type(tstate); | ||||||
|     if (global == NULL) { |     assert(exctype != NULL); | ||||||
|         assert(PyErr_Occurred()); |     return exctype; | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
|     _PyXI_state_t *local = _PyXI_GET_STATE(interp); |  | ||||||
|     if (local == NULL) { |  | ||||||
|         assert(PyErr_Occurred()); |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
|     *res = (dlcontext_t){ |  | ||||||
|         .global = &global->data_lookup, |  | ||||||
|         .local = &local->data_lookup, |  | ||||||
|         .PyExc_NotShareableError = local->exceptions.PyExc_NotShareableError, |  | ||||||
|     }; |  | ||||||
|     return 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| xidatafunc | void | ||||||
| _PyXIData_Lookup(_PyXIData_lookup_context_t *ctx, PyObject *obj) | _PyXIData_SetNotShareableError(PyThreadState *tstate, const char *msg) | ||||||
| { | { | ||||||
|     return lookup_getdata(ctx, obj); |     PyObject *cause = NULL; | ||||||
|  |     set_notshareableerror(tstate, cause, 1, msg); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | _PyXIData_FormatNotShareableError(PyThreadState *tstate, | ||||||
|  |                                   const char *format, ...) | ||||||
|  | { | ||||||
|  |     PyObject *cause = NULL; | ||||||
|  |     va_list vargs; | ||||||
|  |     va_start(vargs, format); | ||||||
|  |     format_notshareableerror_v(tstate, cause, 1, format, vargs); | ||||||
|  |     va_end(vargs); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | xidatafunc | ||||||
|  | _PyXIData_Lookup(PyThreadState *tstate, PyObject *obj) | ||||||
|  | { | ||||||
|  |     dlcontext_t ctx; | ||||||
|  |     if (get_lookup_context(tstate, &ctx) < 0) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     return lookup_getdata(&ctx, obj); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -250,7 +282,7 @@ _xidregistry_clear(dlregistry_t *xidregistry) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | int | ||||||
| _PyXIData_RegisterClass(_PyXIData_lookup_context_t *ctx, | _PyXIData_RegisterClass(PyThreadState *tstate, | ||||||
|                         PyTypeObject *cls, xidatafunc getdata) |                         PyTypeObject *cls, xidatafunc getdata) | ||||||
| { | { | ||||||
|     if (!PyType_Check(cls)) { |     if (!PyType_Check(cls)) { | ||||||
|  | @ -263,7 +295,11 @@ _PyXIData_RegisterClass(_PyXIData_lookup_context_t *ctx, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     int res = 0; |     int res = 0; | ||||||
|     dlregistry_t *xidregistry = _get_xidregistry_for_type(ctx, cls); |     dlcontext_t ctx; | ||||||
|  |     if (get_lookup_context(tstate, &ctx) < 0) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     dlregistry_t *xidregistry = _get_xidregistry_for_type(&ctx, cls); | ||||||
|     _xidregistry_lock(xidregistry); |     _xidregistry_lock(xidregistry); | ||||||
| 
 | 
 | ||||||
|     dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls); |     dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls); | ||||||
|  | @ -281,10 +317,14 @@ _PyXIData_RegisterClass(_PyXIData_lookup_context_t *ctx, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | int | ||||||
| _PyXIData_UnregisterClass(_PyXIData_lookup_context_t *ctx, PyTypeObject *cls) | _PyXIData_UnregisterClass(PyThreadState *tstate, PyTypeObject *cls) | ||||||
| { | { | ||||||
|     int res = 0; |     int res = 0; | ||||||
|     dlregistry_t *xidregistry = _get_xidregistry_for_type(ctx, cls); |     dlcontext_t ctx; | ||||||
|  |     if (get_lookup_context(tstate, &ctx) < 0) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     dlregistry_t *xidregistry = _get_xidregistry_for_type(&ctx, cls); | ||||||
|     _xidregistry_lock(xidregistry); |     _xidregistry_lock(xidregistry); | ||||||
| 
 | 
 | ||||||
|     dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls); |     dlregitem_t *matched = _xidregistry_find_type(xidregistry, cls); | ||||||
|  | @ -508,11 +548,6 @@ _tuple_shared_free(void* data) | ||||||
| static int | static int | ||||||
| _tuple_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data) | _tuple_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data) | ||||||
| { | { | ||||||
|     dlcontext_t ctx; |  | ||||||
|     if (_PyXIData_GetLookupContext(tstate->interp, &ctx) < 0) { |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     Py_ssize_t len = PyTuple_GET_SIZE(obj); |     Py_ssize_t len = PyTuple_GET_SIZE(obj); | ||||||
|     if (len < 0) { |     if (len < 0) { | ||||||
|         return -1; |         return -1; | ||||||
|  | @ -539,7 +574,7 @@ _tuple_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data) | ||||||
| 
 | 
 | ||||||
|         int res = -1; |         int res = -1; | ||||||
|         if (!_Py_EnterRecursiveCallTstate(tstate, " while sharing a tuple")) { |         if (!_Py_EnterRecursiveCallTstate(tstate, " while sharing a tuple")) { | ||||||
|             res = _PyObject_GetXIData(&ctx, item, data); |             res = _PyObject_GetXIData(tstate, item, data); | ||||||
|             _Py_LeaveRecursiveCallTstate(tstate); |             _Py_LeaveRecursiveCallTstate(tstate); | ||||||
|         } |         } | ||||||
|         if (res < 0) { |         if (res < 0) { | ||||||
|  |  | ||||||
|  | @ -1,4 +1,25 @@ | ||||||
| 
 | 
 | ||||||
|  | static void | ||||||
|  | _ensure_current_cause(PyThreadState *tstate, PyObject *cause) | ||||||
|  | { | ||||||
|  |     if (cause == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     PyObject *exc = _PyErr_GetRaisedException(tstate); | ||||||
|  |     assert(exc != NULL); | ||||||
|  |     PyObject *ctx = PyException_GetContext(exc); | ||||||
|  |     if (ctx == NULL) { | ||||||
|  |         PyException_SetContext(exc, Py_NewRef(cause)); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         Py_DECREF(ctx); | ||||||
|  |     } | ||||||
|  |     assert(PyException_GetCause(exc) == NULL); | ||||||
|  |     PyException_SetCause(exc, Py_NewRef(cause)); | ||||||
|  |     _PyErr_SetRaisedException(tstate, exc); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /* InterpreterError extends Exception */ | /* InterpreterError extends Exception */ | ||||||
| 
 | 
 | ||||||
| static PyTypeObject _PyExc_InterpreterError = { | static PyTypeObject _PyExc_InterpreterError = { | ||||||
|  | @ -25,6 +46,97 @@ static PyTypeObject _PyExc_InterpreterNotFoundError = { | ||||||
| }; | }; | ||||||
| PyObject *PyExc_InterpreterNotFoundError = (PyObject *)&_PyExc_InterpreterNotFoundError; | PyObject *PyExc_InterpreterNotFoundError = (PyObject *)&_PyExc_InterpreterNotFoundError; | ||||||
| 
 | 
 | ||||||
|  | /* NotShareableError extends ValueError */ | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | _init_notshareableerror(exceptions_t *state) | ||||||
|  | { | ||||||
|  |     const char *name = "interpreters.NotShareableError"; | ||||||
|  |     // XXX Inherit from TypeError.
 | ||||||
|  |     PyObject *base = PyExc_ValueError; | ||||||
|  |     PyObject *ns = NULL; | ||||||
|  |     PyObject *exctype = PyErr_NewException(name, base, ns); | ||||||
|  |     if (exctype == NULL) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     state->PyExc_NotShareableError = exctype; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | _fini_notshareableerror(exceptions_t *state) | ||||||
|  | { | ||||||
|  |     Py_CLEAR(state->PyExc_NotShareableError); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | get_notshareableerror_type(PyThreadState *tstate) | ||||||
|  | { | ||||||
|  |     _PyXI_state_t *local = _PyXI_GET_STATE(tstate->interp); | ||||||
|  |     if (local == NULL) { | ||||||
|  |         PyErr_Clear(); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     return local->exceptions.PyExc_NotShareableError; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | _ensure_notshareableerror(PyThreadState *tstate, | ||||||
|  |                           PyObject *cause, int force, PyObject *msgobj) | ||||||
|  | { | ||||||
|  |     PyObject *ctx = _PyErr_GetRaisedException(tstate); | ||||||
|  |     PyObject *exctype = get_notshareableerror_type(tstate); | ||||||
|  |     if (exctype != NULL) { | ||||||
|  |         if (!force && ctx != NULL && Py_TYPE(ctx) == (PyTypeObject *)exctype) { | ||||||
|  |             // A NotShareableError instance is already set.
 | ||||||
|  |             assert(cause == NULL); | ||||||
|  |             _PyErr_SetRaisedException(tstate, ctx); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         exctype = PyExc_ValueError; | ||||||
|  |     } | ||||||
|  |     _PyErr_SetObject(tstate, exctype, msgobj); | ||||||
|  |     // We have to set the context manually since _PyErr_SetObject() doesn't.
 | ||||||
|  |     _PyErr_ChainExceptions1Tstate(tstate, ctx); | ||||||
|  |     _ensure_current_cause(tstate, cause); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | set_notshareableerror(PyThreadState *tstate, PyObject *cause, int force, const char *msg) | ||||||
|  | { | ||||||
|  |     PyObject *msgobj = PyUnicode_FromString(msg); | ||||||
|  |     if (msgobj == NULL) { | ||||||
|  |         assert(_PyErr_Occurred(tstate)); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         _ensure_notshareableerror(tstate, cause, force, msgobj); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | format_notshareableerror_v(PyThreadState *tstate, PyObject *cause, int force, | ||||||
|  |                            const char *format, va_list vargs) | ||||||
|  | { | ||||||
|  |     PyObject *msgobj = PyUnicode_FromFormatV(format, vargs); | ||||||
|  |     if (msgobj == NULL) { | ||||||
|  |         assert(_PyErr_Occurred(tstate)); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         _ensure_notshareableerror(tstate, cause, force, msgobj); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | format_notshareableerror(PyThreadState *tstate, PyObject *cause, int force, | ||||||
|  |                          const char *format, ...) | ||||||
|  | { | ||||||
|  |     va_list vargs; | ||||||
|  |     va_start(vargs, format); | ||||||
|  |     format_notshareableerror_v(tstate, cause, force, format, vargs); | ||||||
|  |     va_end(vargs); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| /* lifecycle */ | /* lifecycle */ | ||||||
| 
 | 
 | ||||||
|  | @ -76,18 +188,9 @@ fini_static_exctypes(exceptions_t *state, PyInterpreterState *interp) | ||||||
| static int | static int | ||||||
| init_heap_exctypes(exceptions_t *state) | init_heap_exctypes(exceptions_t *state) | ||||||
| { | { | ||||||
|     PyObject *exctype; |     if (_init_notshareableerror(state) < 0) { | ||||||
| 
 |  | ||||||
|     /* NotShareableError extends ValueError */ |  | ||||||
|     const char *name = "interpreters.NotShareableError"; |  | ||||||
|     PyObject *base = PyExc_ValueError; |  | ||||||
|     PyObject *ns = NULL; |  | ||||||
|     exctype = PyErr_NewException(name, base, ns); |  | ||||||
|     if (exctype == NULL) { |  | ||||||
|         goto error; |         goto error; | ||||||
|     } |     } | ||||||
|     state->PyExc_NotShareableError = exctype; |  | ||||||
| 
 |  | ||||||
|     return 0; |     return 0; | ||||||
| 
 | 
 | ||||||
| error: | error: | ||||||
|  | @ -98,5 +201,5 @@ init_heap_exctypes(exceptions_t *state) | ||||||
| static void | static void | ||||||
| fini_heap_exctypes(exceptions_t *state) | fini_heap_exctypes(exceptions_t *state) | ||||||
| { | { | ||||||
|     Py_CLEAR(state->PyExc_NotShareableError); |     _fini_notshareableerror(state); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -21,11 +21,6 @@ | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Forward declarations */ |  | ||||||
| static PyObject * |  | ||||||
| _PyErr_FormatV(PyThreadState *tstate, PyObject *exception, |  | ||||||
|                const char *format, va_list vargs); |  | ||||||
| 
 |  | ||||||
| void | void | ||||||
| _PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc) | _PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc) | ||||||
| { | { | ||||||
|  | @ -699,12 +694,11 @@ _PyErr_ChainExceptions(PyObject *typ, PyObject *val, PyObject *tb) | ||||||
|    The caller is responsible for ensuring that this call won't create |    The caller is responsible for ensuring that this call won't create | ||||||
|    any cycles in the exception context chain. */ |    any cycles in the exception context chain. */ | ||||||
| void | void | ||||||
| _PyErr_ChainExceptions1(PyObject *exc) | _PyErr_ChainExceptions1Tstate(PyThreadState *tstate, PyObject *exc) | ||||||
| { | { | ||||||
|     if (exc == NULL) { |     if (exc == NULL) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     PyThreadState *tstate = _PyThreadState_GET(); |  | ||||||
|     if (_PyErr_Occurred(tstate)) { |     if (_PyErr_Occurred(tstate)) { | ||||||
|         PyObject *exc2 = _PyErr_GetRaisedException(tstate); |         PyObject *exc2 = _PyErr_GetRaisedException(tstate); | ||||||
|         PyException_SetContext(exc2, exc); |         PyException_SetContext(exc2, exc); | ||||||
|  | @ -715,6 +709,13 @@ _PyErr_ChainExceptions1(PyObject *exc) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void | ||||||
|  | _PyErr_ChainExceptions1(PyObject *exc) | ||||||
|  | { | ||||||
|  |     PyThreadState *tstate = _PyThreadState_GET(); | ||||||
|  |     _PyErr_ChainExceptions1Tstate(tstate, exc); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* If the current thread is handling an exception (exc_info is ), set this
 | /* If the current thread is handling an exception (exc_info is ), set this
 | ||||||
|    exception as the context of the current raised exception. |    exception as the context of the current raised exception. | ||||||
| 
 | 
 | ||||||
|  | @ -1061,15 +1062,14 @@ PyObject *PyErr_SetFromWindowsErrWithFilename( | ||||||
| #endif /* MS_WINDOWS */ | #endif /* MS_WINDOWS */ | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| _PyErr_SetImportErrorSubclassWithNameFrom( | new_importerror( | ||||||
|     PyObject *exception, PyObject *msg, |     PyThreadState *tstate, PyObject *exctype, PyObject *msg, | ||||||
|     PyObject *name, PyObject *path, PyObject* from_name) |     PyObject *name, PyObject *path, PyObject* from_name) | ||||||
| { | { | ||||||
|     PyThreadState *tstate = _PyThreadState_GET(); |     PyObject *exc = NULL; | ||||||
|     int issubclass; |     PyObject *kwargs = NULL; | ||||||
|     PyObject *kwargs, *error; |  | ||||||
| 
 | 
 | ||||||
|     issubclass = PyObject_IsSubclass(exception, PyExc_ImportError); |     int issubclass = PyObject_IsSubclass(exctype, PyExc_ImportError); | ||||||
|     if (issubclass < 0) { |     if (issubclass < 0) { | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|  | @ -1095,29 +1095,38 @@ _PyErr_SetImportErrorSubclassWithNameFrom( | ||||||
|         from_name = Py_None; |         from_name = Py_None; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     kwargs = PyDict_New(); |     kwargs = PyDict_New(); | ||||||
|     if (kwargs == NULL) { |     if (kwargs == NULL) { | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|     if (PyDict_SetItemString(kwargs, "name", name) < 0) { |     if (PyDict_SetItemString(kwargs, "name", name) < 0) { | ||||||
|         goto done; |         goto finally; | ||||||
|     } |     } | ||||||
|     if (PyDict_SetItemString(kwargs, "path", path) < 0) { |     if (PyDict_SetItemString(kwargs, "path", path) < 0) { | ||||||
|         goto done; |         goto finally; | ||||||
|     } |     } | ||||||
|     if (PyDict_SetItemString(kwargs, "name_from", from_name) < 0) { |     if (PyDict_SetItemString(kwargs, "name_from", from_name) < 0) { | ||||||
|         goto done; |         goto finally; | ||||||
|  |     } | ||||||
|  |     exc = PyObject_VectorcallDict(exctype, &msg, 1, kwargs); | ||||||
|  | 
 | ||||||
|  | finally: | ||||||
|  |     Py_DECREF(kwargs); | ||||||
|  |     return exc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|     error = PyObject_VectorcallDict(exception, &msg, 1, kwargs); | static PyObject * | ||||||
|  | _PyErr_SetImportErrorSubclassWithNameFrom( | ||||||
|  |     PyObject *exception, PyObject *msg, | ||||||
|  |     PyObject *name, PyObject *path, PyObject* from_name) | ||||||
|  | { | ||||||
|  |     PyThreadState *tstate = _PyThreadState_GET(); | ||||||
|  |     PyObject *error = new_importerror( | ||||||
|  |                         tstate, exception, msg, name, path, from_name); | ||||||
|     if (error != NULL) { |     if (error != NULL) { | ||||||
|         _PyErr_SetObject(tstate, (PyObject *)Py_TYPE(error), error); |         _PyErr_SetObject(tstate, (PyObject *)Py_TYPE(error), error); | ||||||
|         Py_DECREF(error); |         Py_DECREF(error); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| done: |  | ||||||
|     Py_DECREF(kwargs); |  | ||||||
|     return NULL; |     return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1141,6 +1150,29 @@ PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) | ||||||
|     return PyErr_SetImportErrorSubclass(PyExc_ImportError, msg, name, path); |     return PyErr_SetImportErrorSubclass(PyExc_ImportError, msg, name, path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int | ||||||
|  | _PyErr_SetModuleNotFoundError(PyObject *name) | ||||||
|  | { | ||||||
|  |     PyThreadState *tstate = _PyThreadState_GET(); | ||||||
|  |     if (name == NULL) { | ||||||
|  |         _PyErr_SetString(tstate, PyExc_TypeError, "expected a name argument"); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     PyObject *msg = PyUnicode_FromFormat("%S module not found", name); | ||||||
|  |     if (msg == NULL) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     PyObject *exctype = PyExc_ModuleNotFoundError; | ||||||
|  |     PyObject *exc = new_importerror(tstate, exctype, msg, name, NULL, NULL); | ||||||
|  |     Py_DECREF(msg); | ||||||
|  |     if (exc == NULL) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     _PyErr_SetObject(tstate, exctype, exc); | ||||||
|  |     Py_DECREF(exc); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void | void | ||||||
| _PyErr_BadInternalCall(const char *filename, int lineno) | _PyErr_BadInternalCall(const char *filename, int lineno) | ||||||
| { | { | ||||||
|  | @ -1164,7 +1196,7 @@ PyErr_BadInternalCall(void) | ||||||
| #define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__) | #define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static PyObject * | PyObject * | ||||||
| _PyErr_FormatV(PyThreadState *tstate, PyObject *exception, | _PyErr_FormatV(PyThreadState *tstate, PyObject *exception, | ||||||
|                const char *format, va_list vargs) |                const char *format, va_list vargs) | ||||||
| { | { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Eric Snow
						Eric Snow