24
24
-module(megaco_flex_scanner).
26
-export([start/0, stop/1, scan/2]).
26
-export([is_enabled/0, is_reentrant_enabled/0, is_scanner_port/2]).
27
-export([start/0, start/1, stop/1, scan/2]).
29
-define(NUM_SCHED(), erlang:system_info(schedulers)).
30
-define(SCHED_ID(), erlang:system_info(scheduler_id)).
31
-define(SMP_SUPPORT_DEFAULT(), erlang:system_info(smp_support)).
34
case ?ENABLE_MEGACO_FLEX_SCANNER of
41
is_reentrant_enabled() ->
42
case ?MEGACO_REENTRANT_FLEX_SCANNER of
49
is_scanner_port(Port, Port) when is_port(Port) ->
51
is_scanner_port(Port, Ports) when is_tuple(Ports) ->
52
is_own_port(Port, Ports);
53
is_scanner_port(_, _) ->
56
is_own_port(Port, Ports) ->
57
is_own_port(Port, size(Ports), Ports).
59
is_own_port(_Port, 0, _Ports) ->
61
is_own_port(Port, N, Ports) when (N > 0) ->
62
case element(N, Ports) of
66
is_own_port(Port, N-1, Ports)
70
%%----------------------------------------------------------------------
71
%% Start the flex scanner
72
%%----------------------------------------------------------------------
75
start(?SMP_SUPPORT_DEFAULT()).
77
start(SMP) when ((SMP =:= true) orelse (SMP =:= false)) ->
78
(catch do_start(is_reentrant_enabled() andalso SMP)).
36
Port = open_drv_port(),
84
PortOrPorts = open_drv_port(SMP),
41
89
case code:priv_dir(megaco) of
43
91
throw({error, {priv_dir, Reason}});
111
open_drv_port(true) ->
112
open_drv_ports(?NUM_SCHED(), []);
116
open_drv_ports(0, Acc) ->
118
open_drv_ports(N, Acc) when is_integer(N) andalso (N > 0) ->
119
Port = open_drv_port(),
120
open_drv_ports(N-1, [Port | Acc]).
63
122
open_drv_port() ->
64
123
case (catch erlang:open_port({spawn, drv_name()}, [binary])) of
65
Port when port(Port) ->
124
Port when is_port(Port) ->
67
126
{'EXIT', Reason} ->
68
127
erl_ddll:unload_driver(drv_name()),
77
136
"megaco_flex_scanner_drv"
140
%%----------------------------------------------------------------------
141
%% Stop the flex scanner
142
%%----------------------------------------------------------------------
144
stop(Port) when is_port(Port) ->
81
145
erlang:port_close(Port),
82
146
erl_ddll:unload_driver(drv_name()),
148
stop(Ports) when is_tuple(Ports) ->
149
stop(tuple_to_list(Ports));
150
stop(Ports) when is_list(Ports) ->
151
lists:foreach(fun(Port) -> erlang:port_close(Port) end, Ports),
152
erl_ddll:unload_driver(drv_name()),
156
%%----------------------------------------------------------------------
158
%%----------------------------------------------------------------------
160
scan(Binary, Port) when is_port(Port) ->
161
do_scan(Binary, Port);
162
scan(Binary, Ports) when is_tuple(Ports) ->
163
%% p("scan -> entry with"
164
%% "~n Ports: ~p", [Ports]),
165
do_scan(Binary, select_port(Ports)).
167
do_scan(Binary, Port) ->
168
%% p("do_scan -> entry with"
169
%% "~n Port: ~p", [Port]),
87
170
case erlang:port_control(Port, $s, Binary) of
90
173
{tokens, Tokens, LatestLine} ->
174
%% p("do_scan -> OK with:"
175
%% "~n length(Tokens): ~p"
176
%% "~n LatestLine: ~p", [length(Tokens), LatestLine]),
91
177
Vsn = version(Tokens),
92
178
{ok, Tokens, Vsn, LatestLine}
180
%% p("do_scan -> ERROR", []),
94
181
{error, "Driver term send failure", 1}
184
%% p("do_scan -> port control failed: "
185
%% "~n Reason: ~p", [Reason]),
97
186
{error, Reason, 1}
189
select_port(Ports) ->
190
SchedId = ?SCHED_ID(),
191
%% lists:nth(SchedId, Ports).
192
element(SchedId, Ports).
102
195
99; % Let the parser deal with this