Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' into dpor

Conflicts:
	src/concuerror.erl
	src/concuerror_sched.erl
	testsuite/README
	testsuite/runtests.py
  • Loading branch information...
commit d587d2eb9f6610443b59d942e344d7992c41e505 2 parents f0a78d5 + a7b906f
@iliastsi iliastsi authored
View
3  Makefile
@@ -73,7 +73,8 @@ CORE_MODULES = \
concuerror_sched \
concuerror_state \
concuerror_ticket \
- concuerror_util
+ concuerror_util \
+ concuerror_io_server
LOG_MODULES = \
concuerror_log
View
29 src/concuerror.erl
@@ -175,6 +175,20 @@ parse([{Opt, Param} | Args], Options) ->
Options, {target, Target}),
parse(Args, NewOptions)
end;
+ %% Run Eunit tests for specific module
+ [Module] ->
+ AtomModule = 'eunit',
+ AtomFunc = 'test',
+ Pars = ["[{module, " ++ Module ++ "}]", "[verbose]"],
+ case validateTerms(Pars, []) of
+ {'error',_,_}=Error -> Error;
+ AtomParams ->
+ Target = {AtomModule, AtomFunc, AtomParams},
+ NewOptions = lists:keystore(target, 1,
+ Options, {target, Target}),
+ NewArgs = [{'D',["TEST"]} | Args],
+ parse(NewArgs, NewOptions)
+ end;
_Other -> wrongArgument('number', Opt)
end;
@@ -203,7 +217,7 @@ parse([{Opt, Param} | Args], Options) ->
parse(Args, NewOptions);
_Other -> wrongArgument('number', Opt)
end;
- [$I | Include] ->
+ "I" ++ Include ->
case Param of
[] -> parse([{'I', [Include]} | Args], Options);
_Other -> wrongArgument('number', Opt)
@@ -235,7 +249,7 @@ parse([{Opt, Param} | Args], Options) ->
end;
_Other -> wrongArgument('number', Opt)
end;
- [$D | Define] ->
+ "D" ++ Define ->
case Param of
[] -> parse([{'D', [Define]} | Args], Options);
_Other -> wrongArgument('number', Opt)
@@ -344,6 +358,7 @@ help() ->
"\n"
"usage: concuerror [<args>]\n"
"Arguments:\n"
+ " -t|--target module Run eunit tests for this module\n"
" -t|--target module function [args]\n"
" Specify the function to execute\n"
" -f|--files modules Specify the files (modules) to instrument\n"
@@ -433,7 +448,7 @@ exportAux({error, analysis, {_Target, RunCount}, Tickets}, IoDevice) ->
case file:write(IoDevice, Msg) of
ok ->
case lists:foldl(fun writeDetails/2, {1, IoDevice},
- concuerror_ticket:sort(Tickets)) of
+ concuerror_ticket:sort(Tickets)) of
{'error', _Reason}=Error -> Error;
_Ok -> ok
end;
@@ -445,10 +460,10 @@ writeDetails(_Ticket, {'error', _Reason}=Error) ->
Error;
writeDetails(Ticket, {Count, IoDevice}) ->
Error = concuerror_ticket:get_error(Ticket),
- Description =
- io_lib:format("~p\n~s\n", [Count, concuerror_error:long(Error)]),
- Details = lists:map(fun(M) -> " " ++ M ++ "\n" end,
- concuerror_ticket:details_to_strings(Ticket)),
+ Description = io_lib:format("~p\n~s\n",
+ [Count, concuerror_error:long(Error)]),
+ Details = [" " ++ M ++ "\n"
+ || M <- concuerror_ticket:details_to_strings(Ticket)],
Msg = lists:flatten([Description | Details]),
case file:write(IoDevice, Msg ++ "\n\n") of
ok -> {Count+1, IoDevice};
View
5 src/concuerror_gui.erl
@@ -859,9 +859,8 @@ loadPrefs(Options) ->
case lists:keyfind('files', 1, Options) of
false -> continue;
{'files', Files} ->
- AbsFiles = lists:map(fun filename:absname/1, Files),
- ErlFiles =
- lists:filter(fun concuerror_util:is_erl_source/1, AbsFiles),
+ AbsFiles = [filename:absname(F) || F <- Files],
+ ErlFiles = [F || F <- AbsFiles, concuerror_util:is_erl_source(F)],
addListItems(?MODULE_LIST, ErlFiles)
end,
%% Set include_dirs
View
4 src/concuerror_instr.erl
@@ -131,8 +131,8 @@ instrument_and_compile_one(File, Includes, Defines) ->
%% Compilation of original file without emitting code, just to show
%% warnings or stop if an error is found, before instrumenting it.
concuerror_log:log("Validating file ~p...~n", [File]),
- OptIncludes = lists:map(fun(I) -> {i, I} end, Includes),
- OptDefines = lists:map(fun({M,V}) -> {d,M,V} end, Defines),
+ OptIncludes = [{i, I} || I <- Includes],
+ OptDefines = [{d, M, V} || {M, V} <- Defines],
PreOptions = [strong_validation,verbose,return | OptIncludes++OptDefines],
case compile:file(File, PreOptions) of
{ok, Module, Warnings} ->
View
115 src/concuerror_io_server.erl
@@ -0,0 +1,115 @@
+%%%----------------------------------------------------------------------
+%%% Copyright (c) 2012, Alkis Gotovos <el3ctrologos@hotmail.com>,
+%%% Maria Christakis <mchrista@softlab.ntua.gr>
+%%% and Kostis Sagonas <kostis@cs.ntua.gr>.
+%%% All rights reserved.
+%%%
+%%% This file is distributed under the Simplified BSD License.
+%%% Details can be found in the LICENSE file.
+%%%----------------------------------------------------------------------
+%%% Authors : Ilias Tsitsimpis <iliastsi@hotmail.com>
+%%% Description : An I/O server
+%%%----------------------------------------------------------------------
+
+-module(concuerror_io_server).
+
+-export([new_group_leader/1, group_leader_sync/1]).
+
+
+%% @spec: new_group_leader(pid()) -> pid()
+%% @doc: Create a new process to act as group leader.
+-spec new_group_leader(pid()) -> pid().
+new_group_leader(Runner) ->
+ process_flag(trap_exit, true),
+ spawn_link(fun() -> group_leader_process(Runner) end).
+
+group_leader_process(Runner) ->
+ group_leader_loop(Runner, infinity, []).
+
+group_leader_loop(Runner, Wait, Buf) ->
+ receive
+ {io_request, From, ReplyAs, Req} ->
+ P = process_flag(priority, normal),
+ %% run this part under normal priority always
+ Buf1 = io_request(From, ReplyAs, Req, Buf),
+ process_flag(priority, P),
+ group_leader_loop(Runner, Wait, Buf1);
+ stop ->
+ %% quitting time: make a minimal pause, go low on priority,
+ %% set receive-timeout to zero and schedule out again
+ receive after 2 -> ok end,
+ process_flag(priority, low),
+ group_leader_loop(Runner, 0, Buf);
+ _ ->
+ %% discard any other messages
+ group_leader_loop(Runner, Wait, Buf)
+ after Wait ->
+ %% no more messages and nothing to wait for; we ought to
+ %% have collected all immediately pending output now
+ process_flag(priority, normal),
+ Runner ! {self(), buffer_to_binary(Buf)}
+ end.
+
+buffer_to_binary([B]) when is_binary(B) -> B; % avoid unnecessary copying
+buffer_to_binary(Buf) -> list_to_binary(lists:reverse(Buf)).
+
+%% @spec: group_leader_sync(pid()) -> unicode:chardata()
+%% @doc: Stop the group leader and return it's buffer
+-spec group_leader_sync(pid()) -> unicode:chardata().
+group_leader_sync(G) ->
+ G ! stop,
+ receive {'EXIT', G, normal} -> ok end,
+ receive {G, Buf} -> Buf end.
+
+%% Implementation of buffering I/O for group leader processes. (Note that
+%% each batch of characters is just pushed on the buffer, so it needs to
+%% be reversed when it is flushed.)
+
+io_request(From, ReplyAs, Req, Buf) ->
+ {Reply, Buf1} = io_request(Req, Buf),
+ io_reply(From, ReplyAs, Reply),
+ Buf1.
+
+io_reply(From, ReplyAs, Reply) ->
+ From ! {io_reply, ReplyAs, Reply},
+ ok.
+
+io_request({put_chars, Chars}, Buf) ->
+ {ok, [Chars | Buf]};
+io_request({put_chars, M, F, As}, Buf) ->
+ try apply(M, F, As) of
+ Chars -> {ok, [Chars | Buf]}
+ catch
+ C:T -> {{error, {C,T,erlang:get_stacktrace()}}, Buf}
+ end;
+io_request({put_chars, _Enc, Chars}, Buf) ->
+ io_request({put_chars, Chars}, Buf);
+io_request({put_chars, _Enc, Mod, Func, Args}, Buf) ->
+ io_request({put_chars, Mod, Func, Args}, Buf);
+io_request({get_chars, _Enc, _Prompt, _N}, Buf) ->
+ {eof, Buf};
+io_request({get_chars, _Prompt, _N}, Buf) ->
+ {eof, Buf};
+io_request({get_line, _Prompt}, Buf) ->
+ {eof, Buf};
+io_request({get_line, _Enc, _Prompt}, Buf) ->
+ {eof, Buf};
+io_request({get_until, _Prompt, _M, _F, _As}, Buf) ->
+ {eof, Buf};
+io_request({setopts, _Opts}, Buf) ->
+ {ok, Buf};
+io_request(getopts, Buf) ->
+ {error, {error, enotsup}, Buf};
+io_request({get_geometry,columns}, Buf) ->
+ {error, {error, enotsup}, Buf};
+io_request({get_geometry,rows}, Buf) ->
+ {error, {error, enotsup}, Buf};
+io_request({requests, Reqs}, Buf) ->
+ io_requests(Reqs, {ok, Buf});
+io_request(_, Buf) ->
+ {{error, request}, Buf}.
+
+io_requests([R | Rs], {ok, Buf}) ->
+ io_requests(Rs, io_request(R, Buf));
+io_requests(_, Result) ->
+ Result.
View
28 src/concuerror_sched.erl
@@ -230,7 +230,8 @@ empty_clock_vector() -> dict:new().
must_replay = false :: boolean(),
proc_before = [] :: [pid()],
dpor_flavor = 'none' :: 'full' | 'flanagan' | 'none',
- preemption_bound = inf :: non_neg_integer() | 'inf'
+ preemption_bound = inf :: non_neg_integer() | 'inf',
+ group_leader :: pid()
}).
interleave_dpor(Target, PreBound, Dpor) ->
@@ -239,14 +240,15 @@ interleave_dpor(Target, PreBound, Dpor) ->
Procs = processes(),
%% To be able to clean up we need to be trapping exits...
process_flag(trap_exit, true),
- Trace = start_target(Target),
+ {Trace, GroupLeader} = start_target(Target),
?f_debug("Target started!\n"),
NewState = #dpor_state{trace = Trace, target = Target, proc_before = Procs,
- dpor_flavor = Dpor, preemption_bound = PreBound},
+ dpor_flavor = Dpor, preemption_bound = PreBound,
+ group_leader = GroupLeader},
explore(NewState).
start_target(Target) ->
- FirstLid = start_target_op(Target),
+ {FirstLid, GroupLeader} = start_target_op(Target),
Next = wait_next(FirstLid, init),
New = ordsets:new(),
MaybeEnabled = ordsets:add_element(FirstLid, New),
@@ -258,15 +260,19 @@ start_target(Target) ->
#trace_state{nexts = dict:store(FirstLid, Next, dict:new()),
enabled = Enabled, blocked = Blocked, backtrack = Enabled,
pollable = Pollable},
- [TraceTop].
+ {[TraceTop], GroupLeader}.
start_target_op(Target) ->
concuerror_lid:start(),
+ %% Initialize a new group leader
+ GroupLeader = concuerror_io_server:new_group_leader(self()),
{Mod, Fun, Args} = Target,
NewFun = fun() -> apply(Mod, Fun, Args) end,
SpawnFun = fun() -> concuerror_rep:spawn_fun_wrapper(NewFun) end,
FirstPid = spawn(SpawnFun),
- concuerror_lid:new(FirstPid, noparent).
+ %% Set our io_server as the group leader
+ group_leader(GroupLeader, FirstPid),
+ {concuerror_lid:new(FirstPid, noparent), GroupLeader}.
explore(MightNeedReplayState) ->
receive
@@ -321,15 +327,21 @@ select_from_backtrack(#dpor_state{trace = Trace} = MightNeedReplayState) ->
replay_trace(#dpor_state{proc_before = ProcBefore,
run_count = RunCnt,
+ group_leader = GroupLeader,
target = Target} = State) ->
?f_debug("\nReplay (~p) is required...\n", [RunCnt + 1]),
[#trace_state{lid_trace = LidTrace}|_] = State#dpor_state.trace,
concuerror_lid:stop(),
+ %% Get buffered output from group leader
+ %% TODO: For now just ignore it. Maybe we can print it
+ %% only when we have an error (after the backtrace?)
+ _Output = concuerror_io_server:group_leader_sync(GroupLeader),
proc_cleanup(processes() -- ProcBefore),
- start_target_op(Target),
+ {_FirstLid, NewGroupLeader} = start_target_op(Target),
replay_lid_trace(LidTrace),
?f_debug("Done replaying...\n\n"),
- State#dpor_state{run_count = RunCnt + 1, must_replay = false}.
+ State#dpor_state{run_count = RunCnt + 1, must_replay = false,
+ group_leader = NewGroupLeader}.
replay_lid_trace(Queue) ->
replay_lid_trace(0, Queue).
View
4 testsuite/README
@@ -4,9 +4,9 @@ To run the testsuite:
1) To run all the tests simple execute `./runtests.py'.
For every test results are saved in
- `results/<suite_name>/<test_name>-<function_name>-<preem_bound>.txt'
+ `results/<suite_name>/results/<test_name>-<function_name>-<preem_bound>.txt'
(in the case of using partial order reduction the results are saved in
- `results/<suite_name>/<test_name>-<function_name>-<preem_bound>-dpor.txt')
+ `results/<suite_name>/results/<test_name>-<function_name>-<preem_bound>-dpor.txt')
2) To run all the tests from specific suites (SUITE1, SUITE2)
execute `./runtests.py suites/SUITE1/src/* suites/SUITE2/src/*'.
Please sign in to comment.
Something went wrong with that request. Please try again.