[erlang-questions] async driver in multithread mode - segmentationfault

Niranjan Gunasekera <>
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" <>
To: <>
Cc: <>
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
> 
> http://www.erlang.org/mailman/listinfo/erlang-questions
>





More information about the erlang-questions mailing list