[erlang-questions] async driver in multithread mode - segmentationfault
Niranjan Gunasekera
niranjan@REDACTED
Tue Jan 23 04:17:58 CET 2007
Yes I have the same problem. I have sent a mail to this community, but
haven't got a reply yet.
The driver_async works fine with R10B-10. I have the problem with R11-2 (I
haven't test it with R11-0)
Pls help.
Thanks
Niranjan Gunasekera
----- Original Message -----
From: "Dmitriy Kargapolov" <dmitry.kargapolov@REDACTED>
To: <erlang-bugs@REDACTED>
Cc: <erlang-questions@REDACTED>
Sent: Tuesday, January 23, 2007 3:48 AM
Subject: [erlang-questions] async driver in multithread mode -
segmentationfault
> Hi,
> I was trying to implement asynchronous driver which is invoked in a
> separate thread. It crashes with "segmentation fail" message when second
> call is issued, in driver_async().
>
> I'm attaching dummy short test which shows the problem. I intentionally
> removed from the code most of driver_free() calls to reduce potential
> problem source.
>
> following command makes it failed:
> erl +A4 -noshell -s drv t -s init stop
> but no-thread-pool one works fine:
> erl -noshell -s drv t -s init stop
>
> Tested in R11-0, R11-2, smp and non-smp Linux.
> Any idea / help is appreciated.
> Thanks.
>
----------------------------------------------------------------------------
----
>
> #include <erl_driver.h>
> #include <ei.h>
>
> /* Driver interface declarations */
>
> static int init(void);
> static ErlDrvData start(ErlDrvPort port, char *command);
> static void stop(ErlDrvData drv_data);
> static void finish(void);
> static void output(ErlDrvData drv_data, char *buf, int len);
> static void ready_async(ErlDrvData drv_data, ErlDrvThreadData async_data);
>
> static ErlDrvEntry test_driver_entry = {
> init, /* init */
> start, /* start */
> stop, /* stop */
> output, /* output */
> NULL, /* ready_input */
> NULL, /* ready_output */
> "drv", /* the name of the driver */
> finish, /* finish */
> NULL, /* handle */
> NULL, /* control */
> NULL, /* timeout */
> NULL, /* outputv */
> ready_async, /* ready_async */
> NULL, /* flush */
> NULL, /* call */
> NULL /* event */
> };
>
> /* INITIALIZATION AFTER LOADING */
>
> /*
> * This is the init function called after this driver has been loaded.
> * It must *not* be declared static. Must return the address to
> * the driver entry.
> */
>
> DRIVER_INIT(test_drv)
> {
> return &test_driver_entry;
> }
>
> // This is called directly after the driver has been loaded by
erl_ddll:load_driver/2
> //
> static int init(void)
> {
> fprintf(stderr, "init called from %0X\r\n", pthread_self());
> }
>
> typedef struct {
> ErlDrvPort port;
> } my_drv_data;
>
> static ErlDrvData start(ErlDrvPort port, char *command)
> {
> fprintf(stderr, "start(%0X, %s) called from\r\n", port, command,
pthread_self());
> if (port == NULL) {
> return ERL_DRV_ERROR_GENERAL;
> }
> my_drv_data *data = driver_alloc (sizeof(my_drv_data));
> if (data == NULL) {
> return ERL_DRV_ERROR_GENERAL;
> }
> data->port = port;
> return (ErlDrvData) data;
> }
>
> static void stop(ErlDrvData drv_data)
> {
> fprintf(stderr, "stop(%0X) called from thread %0X\r\n", drv_data,
pthread_self());
> if (drv_data == 0) return;
> fprintf(stderr, "port used by stop(): %0X\r\n", ((my_drv_data *)
drv_data)->port);
> // driver_free (drv_data);
> }
>
> static void finish()
> {
> fprintf(stderr, "finish() called from thread %0X\r\n",
pthread_self());
> }
>
> static void do_invoke(void *data)
> {
> fprintf(stderr, "do_invoke(%0X) called from thread %0X\r\n", data,
pthread_self());
> }
>
> static void do_free(void *data)
> {
> fprintf(stderr, "do_free(%0X) called from thread %0X\r\n", data,
pthread_self());
> }
>
> static void ready_async(ErlDrvData drv_data, ErlDrvThreadData async_data)
> {
> fprintf(stderr, "ready_async(%0X, %0X) called from thread %0X\r\n",
drv_data, async_data, pthread_self());
> if (drv_data == 0) return;
> ErlDrvPort port = ((my_drv_data *) drv_data)->port;
> fprintf(stderr, "port used by ready_async(): %0X\r\n", port);
> ei_x_buff *test = driver_alloc (sizeof (ei_x_buff));
> ei_x_new_with_version (test);
> ei_x_encode_atom (test, "aaa");
> driver_output(port, test->buff, test->index);
> }
>
> static void output(ErlDrvData drv_data, char *buf, int len)
> {
> fprintf(stderr, "output(%0X, %0X, %d) called from thread %0X\r\n",
drv_data, buf, len, pthread_self());
> if (len <= 0) return;
> if (drv_data == 0) return;
> ErlDrvPort port = ((my_drv_data *) drv_data)->port;
> fprintf(stderr, "port used by output(): %0X\r\n", port);
> driver_async (port, NULL, do_invoke, NULL, do_free);
> }
>
----------------------------------------------------------------------------
----
>
> -module(drv).
> -compile(export_all).
>
> % test api
>
> -define(SERVER, ?MODULE).
>
> start(Path) ->
> gen_server:start({local, ?SERVER}, ?MODULE, Path, []).
>
> test_call(Msg) ->
> gen_server:call(?SERVER, {test, self(), Msg}).
>
> % gen_server callbacks
>
> -record(state, {port}).
>
> init(Path) ->
> process_flag(trap_exit, true),
> OpenPort = fun() ->
> case catch open_port({spawn, drv}, [binary]) of
> Port when is_port(Port) ->
> {ok, #state{port = Port}};
> Error ->
> {stop, Error}
> end
> end,
> case erl_ddll:load_driver(Path, "drv") of
> ok ->
> OpenPort();
> {error, already_loaded} ->
> OpenPort();
> Other ->
> {stop, Other}
> end.
>
> handle_call(Msg, From, State = #state{port = Port}) when is_port(Port) ->
> port_command(Port, term_to_binary({From, Msg})),
> {noreply, State};
>
> handle_call(_Msg, _From, State) ->
> {reply, ok, State}.
>
> handle_cast(_Msg, State) ->
> {noreply, State}.
>
> handle_info({Port, {data, Bin}}, State) when is_port(Port),
is_binary(Bin) ->
> case binary_to_term(Bin) of
> {data, To, Msg} ->
> gen_server:reply(To, {data, Msg});
> Other ->
> io:format("test> unknown reply: ~p~n", [Other])
> end,
> {noreply, State};
>
> handle_info(Msg, State) ->
> io:format("test> other message: ~p~n", [Msg]),
> {noreply, State}.
>
> terminate(_Reason, #state{port = Port}) when is_port(Port) ->
> port_close(Port),
> ok;
>
> terminate(_Reason, _State) ->
> ok.
>
> code_change(_OldVsn, State, _Extra) ->
> {ok, State}.
>
> % end of gen_server callbacks
>
> t() ->
> start("."),
> Ret1 = (catch test_call("lalala")),
> io:format("~nret1: '~p'~n", [Ret1]),
> Ret2 = (catch test_call("pipipi")),
> io:format("~nret2: '~p'~n", [Ret2]).
>
----------------------------------------------------------------------------
----
>
> ERL_TOP = /opt/erlang/current/lib/erlang
>
> EI_ROOT = $(ERL_TOP)/lib/erl_interface-3.5.5.2
>
> EI_INCLUDE = -I$(ERL_TOP)/usr/include -I$(EI_ROOT)/include
>
> EI_LIB = -L$(EI_ROOT)/lib -lei
>
> OUR_C_FLAGS = -g -Wall -fpic $(EI_INCLUDE)
> CFLAGS += $(OUR_C_FLAGS)
> CXXFLAGS += $(OUR_C_FLAGS)
>
> EBIN_DIR = .
> ERLC = $(ERL_TOP)/bin/erlc
> ERLC_FLAGS = -W
>
> TARGETS = drv.beam drv.so
>
> all: $(TARGETS)
>
> clean:
> rm -f $(TARGETS) *.o
> rm -f core erl_crash.dump
> rm -f *~
>
> %.so: %.cc
> $(CXX) $(CXXFLAGS) $< -shared -o $@
>
> %.so: %.o
> $(CC) $(CFLAGS) -shared $< $(EI_LIB) -o $@
>
> %: %.cc
> $(CXX) $(CXXFLAGS) $< -o $@
>
> %.beam: %.erl
> $(ERLC) $(ERLC_FLAGS) -o $(EBIN_DIR) $<
>
----------------------------------------------------------------------------
----
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://www.erlang.org/mailman/listinfo/erlang-questions
>
More information about the erlang-questions
mailing list