Created
August 11, 2019 02:26
-
-
Save RoadrunnerWMC/fb434e7ebaa12f533a2ce1df8d094579 to your computer and use it in GitHub Desktop.
Test case for cffi ffi.gc() callback-upon-deletion subinterpreter issue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from cffi import FFI | |
ffibuilder = FFI() | |
ffibuilder.cdef( | |
""" | |
typedef struct c_class c_class; | |
typedef void destroy_callback_function(); | |
extern c_class* c_class_create(destroy_callback_function *callback); | |
extern void c_class_destroy(c_class *obj); | |
extern "Python" void _py_destroy_callback_function_impl(); | |
""") | |
ffibuilder.set_source('_c_code', # name of the output C extension | |
""" | |
#include "c_code.h" | |
""", | |
sources=['c_code.c']) | |
if __name__ == '__main__': | |
ffibuilder.compile(verbose=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include "c_code.h" | |
struct c_class { | |
destroy_callback_function *destroy_callback; | |
}; | |
extern void c_class_destroy(c_class *obj) | |
{ | |
if (obj->destroy_callback) { | |
obj->destroy_callback(); | |
} | |
free(obj); | |
} | |
extern c_class* c_class_create(destroy_callback_function *callback) | |
{ | |
c_class *obj = malloc(sizeof (c_class)); | |
*obj = (c_class) { | |
.destroy_callback = callback | |
}; | |
return obj; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef C_CODE_H | |
#define C_CODE_H | |
typedef struct c_class c_class; | |
typedef void destroy_callback_function(); | |
extern c_class* c_class_create(destroy_callback_function *callback); | |
extern void c_class_destroy(c_class *obj); | |
#endif // C_CODE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import wrapper | |
# Removing this function causes the callback to execute successfully, for some reason? | |
def unused_function(): | |
print('(Nothing calls or references this function, so this print call will never execute)') | |
obj = wrapper.make_class() | |
print('End of test.py') | |
# (obj goes out of scope here) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from _c_code import lib, ffi | |
@ffi.def_extern() | |
def _py_destroy_callback_function_impl(): | |
print('Destroy callback') | |
def make_class(): | |
return ffi.gc( | |
lib.c_class_create(lib._py_destroy_callback_function_impl), | |
lib.c_class_destroy, | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment