|
8 | 8 | #define Py_BUILD_CORE |
9 | 9 | #include "pycore_function.h" // FUNC_MAX_WATCHERS |
10 | 10 | #include "pycore_code.h" // CODE_MAX_WATCHERS |
| 11 | +#include "pycore_context.h" // CONTEXT_MAX_WATCHERS |
11 | 12 |
|
12 | 13 | /*[clinic input] |
13 | 14 | module _testcapi |
@@ -622,6 +623,147 @@ allocate_too_many_func_watchers(PyObject *self, PyObject *args) |
622 | 623 | Py_RETURN_NONE; |
623 | 624 | } |
624 | 625 |
|
| 626 | +// Test contexct object watchers |
| 627 | +#define NUM_CONTEXT_WATCHERS 2 |
| 628 | +static int context_watcher_ids[NUM_CONTEXT_WATCHERS] = {-1, -1}; |
| 629 | +static int num_context_object_enter_events[NUM_CONTEXT_WATCHERS] = {0, 0}; |
| 630 | +static int num_context_object_exit_events[NUM_CONTEXT_WATCHERS] = {0, 0}; |
| 631 | + |
| 632 | +static int |
| 633 | +handle_context_watcher_event(int which_watcher, PyContextEvent event, PyContext *ctx) { |
| 634 | + if (event == Py_CONTEXT_EVENT_ENTER) { |
| 635 | + num_context_object_enter_events[which_watcher]++; |
| 636 | + } |
| 637 | + else if (event == Py_CONTEXT_EVENT_EXIT) { |
| 638 | + num_context_object_exit_events[which_watcher]++; |
| 639 | + } |
| 640 | + else { |
| 641 | + return -1; |
| 642 | + } |
| 643 | + return 0; |
| 644 | +} |
| 645 | + |
| 646 | +static int |
| 647 | +first_context_watcher_callback(PyContextEvent event, PyContext *ctx) { |
| 648 | + return handle_context_watcher_event(0, event, ctx); |
| 649 | +} |
| 650 | + |
| 651 | +static int |
| 652 | +second_context_watcher_callback(PyContextEvent event, PyContext *ctx) { |
| 653 | + return handle_context_watcher_event(1, event, ctx); |
| 654 | +} |
| 655 | + |
| 656 | +static int |
| 657 | +noop_context_event_handler(PyContextEvent event, PyContext *ctx) { |
| 658 | + return 0; |
| 659 | +} |
| 660 | + |
| 661 | +static int |
| 662 | +error_context_event_handler(PyContextEvent event, PyContext *ctx) { |
| 663 | + PyErr_SetString(PyExc_RuntimeError, "boom!"); |
| 664 | + return -1; |
| 665 | +} |
| 666 | + |
| 667 | +static PyObject * |
| 668 | +add_context_watcher(PyObject *self, PyObject *which_watcher) |
| 669 | +{ |
| 670 | + int watcher_id; |
| 671 | + assert(PyLong_Check(which_watcher)); |
| 672 | + long which_l = PyLong_AsLong(which_watcher); |
| 673 | + if (which_l == 0) { |
| 674 | + watcher_id = PyContext_AddWatcher(first_context_watcher_callback); |
| 675 | + context_watcher_ids[0] = watcher_id; |
| 676 | + num_context_object_enter_events[0] = 0; |
| 677 | + num_context_object_exit_events[0] = 0; |
| 678 | + } |
| 679 | + else if (which_l == 1) { |
| 680 | + watcher_id = PyContext_AddWatcher(second_context_watcher_callback); |
| 681 | + context_watcher_ids[1] = watcher_id; |
| 682 | + num_context_object_enter_events[1] = 0; |
| 683 | + num_context_object_exit_events[1] = 0; |
| 684 | + } |
| 685 | + else if (which_l == 2) { |
| 686 | + watcher_id = PyContext_AddWatcher(error_context_event_handler); |
| 687 | + } |
| 688 | + else { |
| 689 | + PyErr_Format(PyExc_ValueError, "invalid watcher %d", which_l); |
| 690 | + return NULL; |
| 691 | + } |
| 692 | + if (watcher_id < 0) { |
| 693 | + return NULL; |
| 694 | + } |
| 695 | + return PyLong_FromLong(watcher_id); |
| 696 | +} |
| 697 | + |
| 698 | +static PyObject * |
| 699 | +clear_context_watcher(PyObject *self, PyObject *watcher_id) |
| 700 | +{ |
| 701 | + assert(PyLong_Check(watcher_id)); |
| 702 | + long watcher_id_l = PyLong_AsLong(watcher_id); |
| 703 | + if (PyContext_ClearWatcher(watcher_id_l) < 0) { |
| 704 | + return NULL; |
| 705 | + } |
| 706 | + // reset static events counters |
| 707 | + if (watcher_id_l >= 0) { |
| 708 | + for (int i = 0; i < NUM_CONTEXT_WATCHERS; i++) { |
| 709 | + if (watcher_id_l == context_watcher_ids[i]) { |
| 710 | + context_watcher_ids[i] = -1; |
| 711 | + num_context_object_enter_events[i] = 0; |
| 712 | + num_context_object_exit_events[i] = 0; |
| 713 | + } |
| 714 | + } |
| 715 | + } |
| 716 | + Py_RETURN_NONE; |
| 717 | +} |
| 718 | + |
| 719 | +static PyObject * |
| 720 | +get_context_watcher_num_enter_events(PyObject *self, PyObject *watcher_id) |
| 721 | +{ |
| 722 | + assert(PyLong_Check(watcher_id)); |
| 723 | + long watcher_id_l = PyLong_AsLong(watcher_id); |
| 724 | + assert(watcher_id_l >= 0 && watcher_id_l < NUM_CONTEXT_WATCHERS); |
| 725 | + return PyLong_FromLong(num_context_object_enter_events[watcher_id_l]); |
| 726 | +} |
| 727 | + |
| 728 | +static PyObject * |
| 729 | +get_context_watcher_num_exit_events(PyObject *self, PyObject *watcher_id) |
| 730 | +{ |
| 731 | + assert(PyLong_Check(watcher_id)); |
| 732 | + long watcher_id_l = PyLong_AsLong(watcher_id); |
| 733 | + assert(watcher_id_l >= 0 && watcher_id_l < NUM_CONTEXT_WATCHERS); |
| 734 | + return PyLong_FromLong(num_context_object_exit_events[watcher_id_l]); |
| 735 | +} |
| 736 | + |
| 737 | +static PyObject * |
| 738 | +allocate_too_many_context_watchers(PyObject *self, PyObject *args) |
| 739 | +{ |
| 740 | + int watcher_ids[CONTEXT_MAX_WATCHERS + 1]; |
| 741 | + int num_watchers = 0; |
| 742 | + for (unsigned long i = 0; i < sizeof(watcher_ids) / sizeof(int); i++) { |
| 743 | + int watcher_id = PyContext_AddWatcher(noop_context_event_handler); |
| 744 | + if (watcher_id == -1) { |
| 745 | + break; |
| 746 | + } |
| 747 | + watcher_ids[i] = watcher_id; |
| 748 | + num_watchers++; |
| 749 | + } |
| 750 | + PyObject *exc = PyErr_GetRaisedException(); |
| 751 | + for (int i = 0; i < num_watchers; i++) { |
| 752 | + if (PyContext_ClearWatcher(watcher_ids[i]) < 0) { |
| 753 | + PyErr_WriteUnraisable(Py_None); |
| 754 | + break; |
| 755 | + } |
| 756 | + } |
| 757 | + if (exc) { |
| 758 | + PyErr_SetRaisedException(exc); |
| 759 | + return NULL; |
| 760 | + } |
| 761 | + else if (PyErr_Occurred()) { |
| 762 | + return NULL; |
| 763 | + } |
| 764 | + Py_RETURN_NONE; |
| 765 | +} |
| 766 | + |
625 | 767 | /*[clinic input] |
626 | 768 | _testcapi.set_func_defaults_via_capi |
627 | 769 | func: object |
@@ -689,6 +831,16 @@ static PyMethodDef test_methods[] = { |
689 | 831 | _TESTCAPI_SET_FUNC_KWDEFAULTS_VIA_CAPI_METHODDEF |
690 | 832 | {"allocate_too_many_func_watchers", allocate_too_many_func_watchers, |
691 | 833 | METH_NOARGS, NULL}, |
| 834 | + |
| 835 | + // Code object watchers. |
| 836 | + {"add_context_watcher", add_context_watcher, METH_O, NULL}, |
| 837 | + {"clear_context_watcher", clear_context_watcher, METH_O, NULL}, |
| 838 | + {"get_context_watcher_num_enter_events", |
| 839 | + get_context_watcher_num_enter_events, METH_O, NULL}, |
| 840 | + {"get_context_watcher_num_exit_events", |
| 841 | + get_context_watcher_num_exit_events, METH_O, NULL}, |
| 842 | + {"allocate_too_many_context_watchers", |
| 843 | + (PyCFunction) allocate_too_many_context_watchers, METH_NOARGS, NULL}, |
692 | 844 | {NULL}, |
693 | 845 | }; |
694 | 846 |
|
|
0 commit comments