3636
3737#include "py_nif.h"
3838#include "py_event_loop.h"
39+ #include "py_reactor_buffer.h"
3940
4041/* ============================================================================
4142 * Global State
@@ -3065,7 +3066,8 @@ ERL_NIF_TERM nif_get_fd_from_resource(ErlNifEnv *env, int argc,
30653066/**
30663067 * reactor_on_read_ready(ContextRef, Fd) -> {ok, Action} | {error, Reason}
30673068 *
3068- * Call Python's erlang_reactor.on_read_ready(fd) and return the action.
3069+ * Read data from fd and call Python's erlang_reactor.on_read_ready(fd, data).
3070+ * Uses zero-copy ReactorBuffer for efficient data transfer.
30693071 * Action is one of: <<"continue">>, <<"write_pending">>, <<"close">>
30703072 *
30713073 * This is a dirty NIF since it acquires the GIL and calls Python.
@@ -3084,24 +3086,54 @@ ERL_NIF_TERM nif_reactor_on_read_ready(ErlNifEnv *env, int argc,
30843086 return make_error (env , "invalid_fd" );
30853087 }
30863088
3089+ /* Read data from fd into buffer resource (before acquiring GIL) */
3090+ reactor_buffer_resource_t * buffer = NULL ;
3091+ size_t bytes_read = 0 ;
3092+ int read_result = reactor_buffer_read_fd (fd , REACTOR_MAX_READ_SIZE ,
3093+ & buffer , & bytes_read );
3094+
3095+ if (read_result < 0 ) {
3096+ return make_error (env , "read_failed" );
3097+ }
3098+
3099+ if (read_result == 1 || (read_result == 0 && buffer == NULL )) {
3100+ /* EOF or would block with no data */
3101+ return enif_make_tuple2 (env , ATOM_OK ,
3102+ enif_make_atom (env , read_result == 1 ? "close" : "continue" ));
3103+ }
3104+
30873105 /* Acquire context (handles both worker mode and subinterpreter mode) */
30883106 py_context_guard_t guard = py_context_acquire (ctx );
30893107 if (!guard .acquired ) {
3108+ enif_release_resource (buffer );
30903109 return make_error (env , "acquire_failed" );
30913110 }
30923111
3112+ /* Create ReactorBuffer Python object wrapping the resource */
3113+ PyObject * py_buffer = ReactorBuffer_from_resource (buffer , buffer );
3114+ /* Release our reference - Python now owns the only reference */
3115+ enif_release_resource (buffer );
3116+
3117+ if (py_buffer == NULL ) {
3118+ PyErr_Clear ();
3119+ py_context_release (& guard );
3120+ return make_error (env , "buffer_creation_failed" );
3121+ }
3122+
30933123 /* Import erlang.reactor module */
30943124 PyObject * reactor_module = PyImport_ImportModule ("erlang.reactor" );
30953125 if (reactor_module == NULL ) {
30963126 PyErr_Clear ();
3127+ Py_DECREF (py_buffer );
30973128 py_context_release (& guard );
30983129 return make_error (env , "import_erlang_reactor_failed" );
30993130 }
31003131
3101- /* Call on_read_ready(fd) */
3132+ /* Call on_read_ready(fd, data) with the buffer */
31023133 PyObject * result = PyObject_CallMethod (reactor_module , "on_read_ready" ,
3103- "i " , fd );
3134+ "iO " , fd , py_buffer );
31043135 Py_DECREF (reactor_module );
3136+ Py_DECREF (py_buffer );
31053137
31063138 if (result == NULL ) {
31073139 PyErr_Clear ();
0 commit comments