diff options
Diffstat (limited to 'lib')
144 files changed, 3530 insertions, 2281 deletions
diff --git a/lib/cosEvent/doc/src/notes.xml b/lib/cosEvent/doc/src/notes.xml index b6c4531901..1a5c8afa17 100644 --- a/lib/cosEvent/doc/src/notes.xml +++ b/lib/cosEvent/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1999</year><year>2010</year> + <year>1999</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,42 +33,48 @@ </header> <section> - <title>cosEvent 2.1.9</title> + <title>cosEvent 2.1.10</title> <section> <title>Improvements and New Features</title> <list type="bulleted"> <item> <p> - Test suites published.</p> + Eliminated Dialyzer warnings when using exit or throw.</p> <p> - Own Id: OTP-8543 Aux Id:</p> + Own Id: OTP-9050 Aux Id:</p> </item> </list> </section> </section> <section> - <title>cosEvent 2.1.8</title> + <title>cosEvent 2.1.9</title> <section> <title>Improvements and New Features</title> <list type="bulleted"> <item> <p> - Removed the usage of the codeinclude tag in the documentation.</p> + Test suites published.</p> <p> - Own Id: OTP-8409 Aux Id:</p> + Own Id: OTP-8543 Aux Id:</p> </item> </list> </section> + </section> + + <section> + <title>cosEvent 2.1.8</title> <section> - <title>Fixed Bugs and Malfunctions</title> + <title>Improvements and New Features</title> <list type="bulleted"> <item> - <p>The documentation EIX file was not generated.</p> - <p>Own id: OTP-8355 Aux Id:</p> + <p> + Removed the usage of the codeinclude tag in the documentation.</p> + <p> + Own Id: OTP-8409 Aux Id:</p> </item> </list> </section> diff --git a/lib/cosEvent/src/cosEventApp.erl b/lib/cosEvent/src/cosEventApp.erl index 084490f845..143c241448 100644 --- a/lib/cosEvent/src/cosEventApp.erl +++ b/lib/cosEvent/src/cosEventApp.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -66,26 +66,31 @@ %% Effect : Install necessary data in the IFR DB %%------------------------------------------------------------ install() -> - install_loop(?IDL_MODULES, []). + case install_loop(?IDL_MODULES, []) of + ok -> + ok; + {error, Reason} -> + exit(Reason) + end. install_loop([], _) -> ok; install_loop([H|T], Accum) -> case catch H:'oe_register'() of {'EXIT',{unregistered,App}} -> - ?write_ErrorMsg("Unable to register '~p'; application ~p not registered. -Trying to unregister ~p~n", [H,App,Accum]), + ?write_ErrorMsg("Unable to register '~p'; application ~p not registered.\n" + "Trying to unregister ~p~n", [H,App,Accum]), uninstall_loop(Accum, {exit, register}); {'EXCEPTION',_} -> - ?write_ErrorMsg("Unable to register '~p'; propably already registered. -You are adviced to confirm this. -Trying to unregister ~p~n", [H,Accum]), + ?write_ErrorMsg("Unable to register '~p'; propably already registered.\n" + "You are adviced to confirm this.\n" + "Trying to unregister ~p~n", [H,Accum]), uninstall_loop(Accum, {exit, register}); ok -> install_loop(T, [H|Accum]); _ -> - ?write_ErrorMsg("Unable to register '~p'; reason unknown. -Trying to unregister ~p~n", [H,Accum]), + ?write_ErrorMsg("Unable to register '~p'; reason unknown.\n" + "Trying to unregister ~p~n", [H,Accum]), uninstall_loop(Accum, {exit, register}) end. @@ -96,27 +101,32 @@ Trying to unregister ~p~n", [H,Accum]), %% Effect : Remove data related to cosEvent from the IFR DB %%------------------------------------------------------------ uninstall() -> - uninstall_loop(lists:reverse(?IDL_MODULES), ok). + case uninstall_loop(lists:reverse(?IDL_MODULES), ok) of + ok -> + ok; + {error, Reason} -> + exit(Reason) + end. uninstall_loop([],ok) -> ok; uninstall_loop([],{exit, register}) -> - exit({?MODULE, "oe_register failed"}); + {error, {?MODULE, "oe_register failed"}}; uninstall_loop([],{exit, unregister}) -> - exit({?MODULE, "oe_unregister failed"}); + {error, {?MODULE, "oe_unregister failed"}}; uninstall_loop([],{exit, both}) -> - exit({?MODULE, "oe_register and, for some of those already registered, oe_unregister failed"}); + {error, {?MODULE, "oe_register and, for some of those already registered, oe_unregister failed"}}; uninstall_loop([H|T], Status) -> case catch H:'oe_unregister'() of ok -> uninstall_loop(T, Status); _ when Status == ok -> - ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered. -You are adviced to confirm this.~n",[H]), + ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered.\n" + "You are adviced to confirm this.\n",[H]), uninstall_loop(T, {exit, unregister}); _ -> - ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered. -You are adviced to confirm this.~n",[H]), + ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered.\n" + "You are adviced to confirm this.\n",[H]), uninstall_loop(T, {exit, both}) end. diff --git a/lib/cosEvent/vsn.mk b/lib/cosEvent/vsn.mk index 9c00a17100..38999db5fa 100644 --- a/lib/cosEvent/vsn.mk +++ b/lib/cosEvent/vsn.mk @@ -1 +1,3 @@ -COSEVENT_VSN = 2.1.9 + +COSEVENT_VSN = 2.1.10 + diff --git a/lib/cosEventDomain/doc/src/notes.xml b/lib/cosEventDomain/doc/src/notes.xml index deb1985c86..522dcea829 100644 --- a/lib/cosEventDomain/doc/src/notes.xml +++ b/lib/cosEventDomain/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2001</year><year>2010</year> + <year>2001</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,7 +32,24 @@ </header> <section> + <title>cosEventDomain 1.1.10</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + Eliminated Dialyzer warnings when using exit or throw.</p> + <p> + Own Id: OTP-9050 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> <title>cosEventDomain 1.1.9</title> + <section> <title>Improvements and New Features</title> <list type="bulleted"> @@ -44,7 +61,6 @@ </item> </list> </section> - </section> <section> diff --git a/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl b/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl index 0b73100540..f5dd6d5c14 100644 --- a/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl +++ b/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -778,12 +778,17 @@ get_qos(_OE_This, #state{cyclic = Cyclic, diamonds = Diamonds} = State) -> %%---------------------------------------------------------------------- set_qos(_OE_This, State, NewQoS) -> QoS = cosEventDomainApp:get_qos(NewQoS), - set_qos_helper(QoS, State, []). + case set_qos_helper(QoS, State, []) of + {ok, NewState} -> + {reply, ok, NewState}; + {error, Errors} -> + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Errors}) + end. set_qos_helper([], State, []) -> - {reply, ok, State}; + {ok, State}; %{reply, ok, State}; set_qos_helper([], _, Errors) -> - corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Errors}); + {error, Errors}; set_qos_helper([{?DiamondDetection, Diamonds}|T], #state{diamonds = Diamonds} = State, Errors) -> set_qos_helper(T, State, Errors); @@ -828,12 +833,17 @@ set_qos_helper([{?CycleDetection, _}|T], #state{cyclic = Cyclic} = State, Errors %%---------------------------------------------------------------------- validate_qos(_OE_This, State, WantedQoS) -> QoS = cosEventDomainApp:get_qos(WantedQoS), - {reply, {ok, validate_qos_helper(QoS, State, [], [])}, State}. + case validate_qos_helper(QoS, State, [], []) of + {ok, Properties} -> + {reply, {ok, Properties}, State}; + {error, Errors} -> + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Errors}) + end. validate_qos_helper([], _, Properties, []) -> - Properties; + {ok, Properties}; validate_qos_helper([], _, _, Errors) -> - corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Errors}); + {error, Errors}; validate_qos_helper([{?DiamondDetection, ?ForbidDiamonds}|T], State, Properties, Errors) -> case get_diamonds_helper(State, false) of diff --git a/lib/cosEventDomain/src/cosEventDomainApp.erl b/lib/cosEventDomain/src/cosEventDomainApp.erl index d57f51443c..734e4deccb 100644 --- a/lib/cosEventDomain/src/cosEventDomainApp.erl +++ b/lib/cosEventDomain/src/cosEventDomainApp.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -270,12 +270,17 @@ create_id() -> get_qos([]) -> []; get_qos(Properties) -> - get_qos(Properties, [], []). + case get_qos(Properties, [], []) of + {ok, Supported} -> + Supported; + {error, Unsupported} -> + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupported}) + end. get_qos([], Supported, []) -> - Supported; + {ok, Supported}; get_qos([], _, Unsupported) -> - corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupported}); + {error, Unsupported}; get_qos([#'CosNotification_Property'{name = ?CycleDetection, value= #any{value = ?AuthorizeCycles}}|T], Supported, Unsupported) -> diff --git a/lib/cosEventDomain/vsn.mk b/lib/cosEventDomain/vsn.mk index bd21133fe5..f4a77ab7a8 100644 --- a/lib/cosEventDomain/vsn.mk +++ b/lib/cosEventDomain/vsn.mk @@ -1 +1,3 @@ -COSEVENTDOMAIN_VSN = 1.1.9 + +COSEVENTDOMAIN_VSN = 1.1.10 + diff --git a/lib/cosNotification/doc/src/notes.xml b/lib/cosNotification/doc/src/notes.xml index 04c0c2accd..125e25e67e 100644 --- a/lib/cosNotification/doc/src/notes.xml +++ b/lib/cosNotification/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2000</year><year>2010</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -31,6 +31,20 @@ <file>notes.xml</file> </header> + <section><title>cosNotification 1.1.16</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Eliminated Dialyzer warnings when using exit or throw.</p> + <p> + Own Id: OTP-9050</p> + </item> + </list> + </section> +</section> + <section><title>cosNotification 1.1.15</title> <section><title>Improvements and New Features</title> diff --git a/lib/cosNotification/src/CosNotification_Common.erl b/lib/cosNotification/src/CosNotification_Common.erl index 0e0f1da0d5..af9b2d4368 100644 --- a/lib/cosNotification/src/CosNotification_Common.erl +++ b/lib/cosNotification/src/CosNotification_Common.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -28,7 +28,6 @@ %%--------------- INCLUDES ----------------------------------- -include_lib("orber/include/corba.hrl"). --include_lib("orber/include/ifr_types.hrl"). %% Application files -include("CosNotification.hrl"). -include("CosNotifyChannelAdmin.hrl"). @@ -945,14 +944,19 @@ check_limits(LQS, NPR) -> %% supported. %%------------------------------------------------------------ validate_event_qos(Wanted, Curr) -> - v_e_q_helper(Wanted, Curr, []), - []. + case v_e_q_helper(Wanted, Curr, []) of + ok -> + []; + {error, Unsupp} -> + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupp}) + end. + v_e_q_helper([], _Curr, []) -> - %% Parsed all and foynd no conflicts. + %% Parsed all and found no conflicts. ok; v_e_q_helper([], _Curr, Unsupp) -> %% Not possible to use these requested QoS. - corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupp}); + {error, Unsupp}; %%--- EventReliability ---%% v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability, @@ -1071,30 +1075,38 @@ v_e_q_helper(What, _, _) -> %% LQS - local representation of QoS. %% Returns : {NewOMGStyleQoS, NewLocalQoS} | #'CosNotification_UnsupportedQoS'{} %%------------------------------------------------------------ -set_properties([], Curr, channelAdm, _, [], NewQoS,_,_,LAS) -> +set_properties(Wanted, Current, Type, Supported, Unsupp, NewQoS, Parent, Childs, LQS) -> + case do_set_properties(Wanted, Current, Type, Supported, Unsupp, NewQoS, Parent, Childs, LQS) of + {error, Exc} -> + corba:raise(Exc); + Result -> + Result + end. + +do_set_properties([], Curr, channelAdm, _, [], NewQoS,_,_,LAS) -> merge_properties(NewQoS, Curr, LAS); -set_properties([], Curr, _, _, [], NewQoS,_,_,LQS) -> +do_set_properties([], Curr, _, _, [], NewQoS,_,_,LQS) -> %% set_local_qos and merge_properties are help functions found at the end of QoS %% functions. NewLQS = set_local_qos(NewQoS, LQS), merge_properties(NewQoS, Curr, NewLQS); -set_properties([], _, channelAdm, _, Unsupp, _,_,_,_) -> - corba:raise(#'CosNotification_UnsupportedAdmin'{admin_err = Unsupp}); -set_properties([], _, _, _, Unsupp, _,_,_,_) -> - corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupp}); +do_set_properties([], _, channelAdm, _, Unsupp, _,_,_,_) -> + {error, #'CosNotification_UnsupportedAdmin'{admin_err = Unsupp}}; +do_set_properties([], _, _, _, Unsupp, _,_,_,_) -> + {error, #'CosNotification_UnsupportedQoS'{qos_err = Unsupp}}; -set_properties([Req|Tail], Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS) -> +do_set_properties([Req|Tail], Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS) -> %% set_values and is_supported are help functions found at the end of QoS %% functions. case set_values(is_supported(Supported, Req), Req, Type, Curr, Parent, Childs,LQS) of {unsupported, U} -> - set_properties(Tail, Curr, Type, Supported, [U|Unsupp], NewQoS, Parent, Childs,LQS); + do_set_properties(Tail, Curr, Type, Supported, [U|Unsupp], NewQoS, Parent, Childs,LQS); {ok, S, NewLQS} -> - set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,NewLQS); + do_set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,NewLQS); {ok, S} -> - set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,LQS); + do_set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,LQS); ok -> - set_properties(Tail, Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS) + do_set_properties(Tail, Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS) end. diff --git a/lib/cosNotification/vsn.mk b/lib/cosNotification/vsn.mk index cfd5948dfc..6613385579 100644 --- a/lib/cosNotification/vsn.mk +++ b/lib/cosNotification/vsn.mk @@ -1 +1,2 @@ -COSNOTIFICATION_VSN = 1.1.15 +COSNOTIFICATION_VSN = 1.1.16 + diff --git a/lib/cosProperty/doc/src/notes.xml b/lib/cosProperty/doc/src/notes.xml index 11e6205ee9..d7d52514ce 100644 --- a/lib/cosProperty/doc/src/notes.xml +++ b/lib/cosProperty/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2000</year><year>2010</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -54,6 +54,34 @@ <title>Fixed Bugs and Malfunctions</title> <list type="bulleted"> <item> + <p>Eliminated Dialyzer warnings when using exit or throw.</p> + <p>Own id: OTP-9050 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosProperty 1.1.12</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Test suites published.</p> + <p>Own id: OTP-8543 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> + <title>cosProperty 1.1.11</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> <p>The documentation EIX file was not generated.</p> <p>Own id: OTP-8355 Aux Id:</p> </item> diff --git a/lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl index b099026b88..202df42b61 100644 --- a/lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl +++ b/lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% Copyright Ericsson AB 2000-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -152,12 +152,18 @@ create_initial_propertysetdef(_OE_This, State, PropDefs) -> %% Internal functions %%====================================================================== evaluate_propertysetdef(SetDefs) -> - evaluate_propertysetdef(SetDefs, [], []). + case evaluate_propertysetdef(SetDefs, [], []) of + {ok, NewProperties} -> + NewProperties; + {error, Exc} -> + corba:raise(#'CosPropertyService_MultipleExceptions'{exceptions = Exc}) + end. + evaluate_propertysetdef([], NewProperties, []) -> %% No exceptions found. - NewProperties; + {ok, NewProperties}; evaluate_propertysetdef([], _, Exc) -> - corba:raise(#'CosPropertyService_MultipleExceptions'{exceptions = Exc}); + {error, Exc}; evaluate_propertysetdef([#'CosPropertyService_PropertyDef' {property_name = Name, property_value = Value, diff --git a/lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl index ad3cdb62d4..4bc29b99ac 100644 --- a/lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl +++ b/lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% Copyright Ericsson AB 2000-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -153,12 +153,18 @@ create_initial_propertyset(_OE_This, State, Properties) -> %% Internal functions %%====================================================================== evaluate_propertyset(Sets) -> - evaluate_propertyset(Sets, [], []). + case evaluate_propertyset(Sets, [], []) of + {ok, NewProperties} -> + NewProperties; + {error, Exc} -> + corba:raise(#'CosPropertyService_MultipleExceptions'{exceptions = Exc}) + end. + evaluate_propertyset([], NewProperties, []) -> %% No exceptions found. - NewProperties; + {ok, NewProperties}; evaluate_propertyset([], _, Exc) -> - corba:raise(#'CosPropertyService_MultipleExceptions'{exceptions = Exc}); + {error, Exc}; evaluate_propertyset([#'CosPropertyService_Property' {property_name = Name, property_value = Value}|T], X, Exc) -> diff --git a/lib/cosProperty/vsn.mk b/lib/cosProperty/vsn.mk index ca9a7ca77e..deb1eb0450 100644 --- a/lib/cosProperty/vsn.mk +++ b/lib/cosProperty/vsn.mk @@ -1 +1,2 @@ -COSPROPERTY_VSN = 1.1.12 +COSPROPERTY_VSN = 1.1.13 + diff --git a/lib/cosTime/doc/src/notes.xml b/lib/cosTime/doc/src/notes.xml index 40ebf42753..718ca23bc5 100644 --- a/lib/cosTime/doc/src/notes.xml +++ b/lib/cosTime/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2000</year><year>2010</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,6 +33,22 @@ </header> <section> + <title>cosTime 1.1.10</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + Eliminated Dialyzer warnings when using exit or throw.</p> + <p> + Own Id: OTP-9050 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> <title>cosTime 1.1.9</title> <section> diff --git a/lib/cosTime/src/cosTime.erl b/lib/cosTime/src/cosTime.erl index f4e67570ad..f7d03650af 100644 --- a/lib/cosTime/src/cosTime.erl +++ b/lib/cosTime/src/cosTime.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% Copyright Ericsson AB 2000-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -71,29 +71,39 @@ %%------------------------------------------------------------ install_time() -> - install_loop(?IDL_TIME_MODULES,[]). + case install_loop(?IDL_TIME_MODULES,[]) of + ok -> + ok; + {error, Reason} -> + exit(Reason) + end. install_timerevent() -> - install_loop(?IDL_TIMEREVENT_MODULES,[]). + case install_loop(?IDL_TIMEREVENT_MODULES,[]) of + ok -> + ok; + {error, Reason} -> + exit(Reason) + end. install_loop([], _) -> ok; install_loop([H|T], Accum) -> case catch H:'oe_register'() of {'EXIT',{unregistered,App}} -> - ?write_ErrorMsg("Unable to register '~p'; application ~p not registered. -Trying to unregister ~p~n", [H,App,Accum]), + ?write_ErrorMsg("Unable to register '~p'; application ~p not registered.\n" + "Trying to unregister ~p\n", [H,App,Accum]), uninstall_loop(Accum, {exit, register}); {'EXCEPTION',_} -> - ?write_ErrorMsg("Unable to register '~p'; propably already registered. -You are adviced to confirm this. -Trying to unregister ~p~n", [H,Accum]), + ?write_ErrorMsg("Unable to register '~p'; propably already registered.\n" + "You are adviced to confirm this.\n" + "Trying to unregister ~p\n", [H,Accum]), uninstall_loop(Accum, {exit, register}); ok -> install_loop(T, [H|Accum]); _ -> - ?write_ErrorMsg("Unable to register '~p'; reason unknown. -Trying to unregister ~p~n", [H,Accum]), + ?write_ErrorMsg("Unable to register '~p'; reason unknown.\n" + "Trying to unregister ~p\n", [H,Accum]), uninstall_loop(Accum, {exit, register}) end. @@ -105,33 +115,43 @@ Trying to unregister ~p~n", [H,Accum]), %%------------------------------------------------------------ uninstall_time() -> - uninstall_loop(lists:reverse(?IDL_TIME_MODULES),ok). + case uninstall_loop(lists:reverse(?IDL_TIME_MODULES),ok) of + ok -> + ok; + {error, Reason} -> + exit(Reason) + end. uninstall_timerevent() -> - uninstall_loop(lists:reverse(?IDL_TIMEREVENT_MODULES),ok). + case uninstall_loop(lists:reverse(?IDL_TIMEREVENT_MODULES),ok) of + ok -> + ok; + {error, Reason} -> + exit(Reason) + end. uninstall_loop([],ok) -> ok; uninstall_loop([],{exit, register}) -> - exit({?MODULE, "oe_register failed"}); + {error, {?MODULE, "oe_register failed"}}; uninstall_loop([],{exit, unregister}) -> - exit({?MODULE, "oe_unregister failed"}); + {error, {?MODULE, "oe_unregister failed"}}; uninstall_loop([],{exit, both}) -> - exit({?MODULE, "oe_register and, for some of those already registered, oe_unregister failed"}); + {error, {?MODULE, "oe_register and, for some of those already registered, oe_unregister failed"}}; uninstall_loop([H|T], Status) -> case catch H:'oe_unregister'() of ok -> uninstall_loop(T, Status); _ when Status == ok -> - ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered. -You are adviced to confirm this.~n",[H]), + ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered.\n" + "You are adviced to confirm this.~n",[H]), uninstall_loop(T, {exit, unregister}); _ -> - ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered. -You are adviced to confirm this.~n",[H]), + ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered.\n" + "You are adviced to confirm this.~n",[H]), uninstall_loop(T, {exit, both}) end. - + %%------------------------------------------------------------ %% function : start/stop %% Arguments: diff --git a/lib/cosTime/vsn.mk b/lib/cosTime/vsn.mk index 429613fb61..ebc5aff1cc 100644 --- a/lib/cosTime/vsn.mk +++ b/lib/cosTime/vsn.mk @@ -1 +1,2 @@ -COSTIME_VSN = 1.1.9 +COSTIME_VSN = 1.1.10 + diff --git a/lib/debugger/src/dbg_ui_view.erl b/lib/debugger/src/dbg_ui_view.erl index 7350a830a8..be998f22ff 100644 --- a/lib/debugger/src/dbg_ui_view.erl +++ b/lib/debugger/src/dbg_ui_view.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -42,6 +42,9 @@ start(GS, Mod) -> false -> spawn(fun () -> init(GS, Mod, Title) end) end. +-spec stop() -> no_return(). +stop() -> + exit(stop). %%==================================================================== %% Main loop and message handling @@ -90,7 +93,7 @@ loop(State) -> dbg_ui_winman:update_windows_menu(Data), loop(State); {dbg_ui_winman, destroy} -> - exit(stop); + stop(); %% Help window termination -- ignore {'EXIT', _Pid, _Reason} -> @@ -104,7 +107,7 @@ gui_cmd(ignore, State) -> gui_cmd({win, Win}, State) -> State#state{win=Win}; gui_cmd(stopped, _State) -> - exit(stop); + stop(); gui_cmd({coords, Coords}, State) -> State#state{coords=Coords}; @@ -115,8 +118,8 @@ gui_cmd({shortcut, Key}, State) -> end; %% File menu -gui_cmd('Close', State) -> - gui_cmd(stopped, State); +gui_cmd('Close', _State) -> + stop(); %% Edit menu gui_cmd('Go To Line...', State) -> diff --git a/lib/debugger/src/dbg_wx_view.erl b/lib/debugger/src/dbg_wx_view.erl index 8ff89a4847..6242b9d0e0 100644 --- a/lib/debugger/src/dbg_wx_view.erl +++ b/lib/debugger/src/dbg_wx_view.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -46,6 +46,9 @@ start(GS, Mod) -> spawn_link(fun () -> init(GS, Env, Mod, Title) end) end. +-spec stop() -> no_return(). +stop() -> + exit(normal). %%==================================================================== %% Main loop and message handling @@ -113,13 +116,13 @@ loop(State) -> end. %%--Commands from the GUI--------------------------------------------- - + gui_cmd(ignore, State) -> State; gui_cmd({win, Win}, State) -> State#state{win=Win}; gui_cmd(stopped, _State) -> - exit(normal); + stop(); gui_cmd({coords, Coords}, State) -> State#state{coords=Coords}; @@ -132,7 +135,7 @@ gui_cmd({shortcut, Key}, State) -> %% File menu gui_cmd('Close', State) -> dbg_wx_trace_win:stop(State#state.win), - gui_cmd(stopped, State); + stop(); %% Edit menu gui_cmd('Go To Line', State) -> diff --git a/lib/dialyzer/doc/manual.txt b/lib/dialyzer/doc/manual.txt index cc6f9130c7..1d7a1a6222 100644 --- a/lib/dialyzer/doc/manual.txt +++ b/lib/dialyzer/doc/manual.txt @@ -129,7 +129,7 @@ Usage: dialyzer [--help] [--version] [--shell] [--quiet] [--verbose] [--apps applications] [-o outfile] [--build_plt] [--add_to_plt] [--remove_from_plt] [--check_plt] [--no_check_plt] [--plt_info] [--get_warnings] - [--no_native] + [--no_native] [--fullpath] Options: files_or_dirs (for backwards compatibility also as: -c files_or_dirs) @@ -231,6 +231,8 @@ Options: Bypass the native code compilation of some key files that Dialyzer heuristically performs when dialyzing many files; this avoids the compilation time but it may result in (much) longer analysis time. + --fullpath + Display the full path names of files for which warnings are emitted. --gui Use the gs-based GUI. --wx diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml index 01a7e478bc..8813d51f1f 100644 --- a/lib/dialyzer/doc/src/dialyzer.xml +++ b/lib/dialyzer/doc/src/dialyzer.xml @@ -71,7 +71,7 @@ [--apps applications] [-o outfile] [--build_plt] [--add_to_plt] [--remove_from_plt] [--check_plt] [--no_check_plt] [--plt_info] [--get_warnings] - [--no_native] + [--no_native] [--fullpath] ]]></code> <p>Options:</p> <taglist> @@ -198,10 +198,12 @@ heuristically performs when dialyzing many files; this avoids the compilation time but it may result in (much) longer analysis time.</item> + <tag><c><![CDATA[--fullpath]]></c></tag> + <item>Display the full path names of files for which warnings are emitted.</item> <tag><c><![CDATA[--gui]]></c></tag> <item>Use the gs-based GUI.</item> <tag><c><![CDATA[--wx]]></c></tag> - <item>Use the wx-based GUI..</item> + <item>Use the wx-based GUI.</item> </taglist> <note> <p>* denotes that multiple occurrences of these options are possible.</p> diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl index 471f9fccd2..dde0c17c39 100644 --- a/lib/dialyzer/src/dialyzer.erl +++ b/lib/dialyzer/src/dialyzer.erl @@ -2,7 +2,7 @@ %%----------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -38,7 +38,8 @@ gui/0, gui/1, plt_info/1, - format_warning/1]). + format_warning/1, + format_warning/2]). -include("dialyzer.hrl"). @@ -48,6 +49,8 @@ %% - run/1: Erlang interface for a command line-like analysis %% - gui/0/1: Erlang interface for the gui. %% - format_warning/1: Get the string representation of a warning. +%% - format_warning/1: Likewise, but with an option whether +%% to display full path names or not %% - plt_info/1: Get information of the specified plt. %%-------------------------------------------------------------------- @@ -281,11 +284,19 @@ cl_check_log(Output) -> -spec format_warning(dial_warning()) -> string(). -format_warning({_Tag, {File, Line}, Msg}) when is_list(File), - is_integer(Line) -> - BaseName = filename:basename(File), +format_warning(W) -> + format_warning(W, basename). + +-spec format_warning(dial_warning(), fopt()) -> string(). + +format_warning({_Tag, {File, Line}, Msg}, FOpt) when is_list(File), + is_integer(Line) -> + F = case FOpt of + fullpath -> File; + basename -> filename:basename(File) + end, String = lists:flatten(message_to_string(Msg)), - lists:flatten(io_lib:format("~s:~w: ~s", [BaseName, Line, String])). + lists:flatten(io_lib:format("~s:~w: ~s", [F, Line, String])). %%----------------------------------------------------------------------------- @@ -325,6 +336,8 @@ message_to_string({guard_fail, [Arg1, Infix, Arg2]}) -> io_lib:format("Guard test ~s ~s ~s can never succeed\n", [Arg1, Infix, Arg2]); message_to_string({guard_fail, [Guard, Args]}) -> io_lib:format("Guard test ~w~s can never succeed\n", [Guard, Args]); +message_to_string({neg_guard_fail, [Guard, Args]}) -> + io_lib:format("Guard test not(~w~s) can never succeed\n", [Guard, Args]); message_to_string({guard_fail_pat, [Pat, Type]}) -> io_lib:format("Clause guard cannot succeed. The ~s was matched" " against the type ~s\n", [Pat, Type]); diff --git a/lib/dialyzer/src/dialyzer.hrl b/lib/dialyzer/src/dialyzer.hrl index 1d98574585..aa3f703af2 100644 --- a/lib/dialyzer/src/dialyzer.hrl +++ b/lib/dialyzer/src/dialyzer.hrl @@ -2,7 +2,7 @@ %%% %%% %CopyrightBegin% %%% -%%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %%% %%% The contents of this file are subject to the Erlang Public License, %%% Version 1.1, (the "License"); you may not use this file except in @@ -31,7 +31,7 @@ -define(RET_DISCREPANCIES, 2). -type dial_ret() :: ?RET_NOTHING_SUSPICIOUS - | ?RET_INTERNAL_ERROR + | ?RET_INTERNAL_ERROR | ?RET_DISCREPANCIES. %%-------------------------------------------------------------------- @@ -87,7 +87,7 @@ %%-------------------------------------------------------------------- %% THIS TYPE SHOULD ONE DAY DISAPPEAR -- IT DOES NOT BELONG HERE %%-------------------------------------------------------------------- - + -type ordset(T) :: [T] . %% XXX: temporarily %%-------------------------------------------------------------------- @@ -102,6 +102,8 @@ -type dial_define() :: {atom(), term()}. -type dial_option() :: {atom(), term()}. -type dial_options() :: [dial_option()]. +-type fopt() :: 'basename' | 'fullpath'. +-type format() :: 'formatted' | 'raw'. -type label() :: non_neg_integer(). -type rep_mode() :: 'quiet' | 'normal' | 'verbose'. -type start_from() :: 'byte_code' | 'src_code'. @@ -137,10 +139,10 @@ erlang_mode = false :: boolean(), use_contracts = true :: boolean(), output_file = none :: 'none' | file:filename(), - output_format = formatted :: 'raw' | 'formatted', + output_format = formatted :: format(), + filename_opt = basename :: fopt(), callgraph_file = "" :: file:filename(), - check_plt = true :: boolean() - }). + check_plt = true :: boolean()}). -record(contract, {contracts = [] :: [contract_pair()], args = [] :: [erl_types:erl_type()], diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl index 1987c1732c..86f1ba4696 100644 --- a/lib/dialyzer/src/dialyzer_cl.erl +++ b/lib/dialyzer/src/dialyzer_cl.erl @@ -2,7 +2,7 @@ %%------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -46,7 +46,8 @@ legal_warnings = ordsets:new() :: [dial_warn_tag()], mod_deps = dict:new() :: dict(), output = standard_io :: io:device(), - output_format = formatted :: 'raw' | 'formatted', + output_format = formatted :: format(), + filename_opt = basename :: fopt(), output_plt = none :: 'none' | file:filename(), plt_info = none :: 'none' | dialyzer_plt:plt_info(), report_mode = normal :: rep_mode(), @@ -532,8 +533,10 @@ hc(Mod) -> new_state() -> #cl_state{}. -init_output(State0, #options{output_file = OutFile, output_format = OutFormat}) -> - State = State0#cl_state{output_format = OutFormat}, +init_output(State0, #options{output_file = OutFile, + output_format = OutFormat, + filename_opt = FOpt}) -> + State = State0#cl_state{output_format = OutFormat, filename_opt = FOpt}, case OutFile =:= none of true -> State; @@ -766,6 +769,7 @@ print_warnings(#cl_state{stored_warnings = []}) -> ok; print_warnings(#cl_state{output = Output, output_format = Format, + filename_opt = FOpt, stored_warnings = Warnings}) -> PrWarnings = process_warnings(Warnings), case PrWarnings of @@ -773,7 +777,7 @@ print_warnings(#cl_state{output = Output, [_|_] -> S = case Format of formatted -> - [dialyzer:format_warning(W) || W <- PrWarnings]; + [dialyzer:format_warning(W, FOpt) || W <- PrWarnings]; raw -> [io_lib:format("~p. \n", [W]) || W <- PrWarnings] end, diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl index 5ca7599b35..f9baf36822 100644 --- a/lib/dialyzer/src/dialyzer_cl_parse.erl +++ b/lib/dialyzer/src/dialyzer_cl_parse.erl @@ -2,7 +2,7 @@ %%----------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -133,6 +133,9 @@ cl(["-o"++Output|T]) -> cl(["--raw"|T]) -> put(dialyzer_output_format, raw), cl(T); +cl(["--fullpath"|T]) -> + put(dialyzer_filename_opt, fullpath), + cl(T); cl(["-pa", Path|T]) -> case code:add_patha(Path) of true -> cl(T); @@ -243,6 +246,7 @@ init() -> put(dialyzer_options_defines, DefaultOpts#options.defines), put(dialyzer_options_files, DefaultOpts#options.files), put(dialyzer_output_format, formatted), + put(dialyzer_filename_opt, basename), put(dialyzer_options_check_plt, DefaultOpts#options.check_plt), ok. @@ -281,6 +285,7 @@ cl_options() -> {files_rec, get(dialyzer_options_files_rec)}, {output_file, get(dialyzer_output)}, {output_format, get(dialyzer_output_format)}, + {filename_opt, get(dialyzer_filename_opt)}, {analysis_type, get(dialyzer_options_analysis_type)}, {get_warnings, get(dialyzer_options_get_warnings)}, {callgraph_file, get(dialyzer_callgraph_file)} @@ -335,7 +340,7 @@ help_message() -> [--apps applications] [-o outfile] [--build_plt] [--add_to_plt] [--remove_from_plt] [--check_plt] [--no_check_plt] [--plt_info] [--get_warnings] - [--no_native] + [--no_native] [--fullpath] Options: files_or_dirs (for backwards compatibility also as: -c files_or_dirs) Use Dialyzer from the command line to detect defects in the @@ -437,6 +442,8 @@ Options: Bypass the native code compilation of some key files that Dialyzer heuristically performs when dialyzing many files; this avoids the compilation time but it may result in (much) longer analysis time. + --fullpath + Display the full path names of files for which warnings are emitted. --gui Use the gs-based GUI. --wx diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index b80c7efc1a..2ffbcd3e82 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -1457,6 +1457,7 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, false -> WarnType = case Msg of {guard_fail, _} -> ?WARN_MATCHING; + {neg_guard_fail, _} -> ?WARN_MATCHING; {opaque_guard, _} -> ?WARN_OPAQUE end, state__add_warning(State1, WarnType, FailGuard, Msg); @@ -1748,7 +1749,7 @@ bind_opaque_pats(GenType, Type, Pat, Map, State, Rev) -> bind_guard(Guard, Map, State) -> try bind_guard(Guard, Map, dict:new(), pos, State) of - {Map1, _Type} -> Map1 + {Map1, _Type} -> Map1 catch throw:{fail, Warning} -> {error, Warning}; throw:{fatal_fail, Warning} -> {error, Warning} @@ -1869,8 +1870,8 @@ handle_guard_gen_fun({M, F, A}, Guard, Map, Env, Eval, State) -> true -> %% Is this an error-bif? case t_is_none(erl_bif_types:type(M, F, A)) of - true -> signal_guard_fail(Guard, As, State); - false -> signal_guard_fatal_fail(Guard, As, State) + true -> signal_guard_fail(Eval, Guard, As, State); + false -> signal_guard_fatal_fail(Eval, Guard, As, State) end; false -> BifArgs = case erl_bif_types:arg_types(M, F, A) of @@ -1887,7 +1888,7 @@ handle_guard_gen_fun({M, F, A}, Guard, Map, Env, Eval, State) -> case t_is_none(Ret) of true -> case Eval =:= pos of - true -> signal_guard_fail(Guard, As, State); + true -> signal_guard_fail(Eval, Guard, As, State); false -> throw({fail, none}) end; false -> {Map2, Ret} @@ -1900,7 +1901,7 @@ handle_guard_type_test(Guard, F, Map, Env, Eval, State) -> case bind_type_test(Eval, F, ArgType, State) of error -> ?debug("Type test: ~w failed\n", [F]), - signal_guard_fail(Guard, [ArgType], State); + signal_guard_fail(Eval, Guard, [ArgType], State); {ok, NewArgType, Ret} -> ?debug("Type test: ~w succeeded, NewType: ~s, Ret: ~s\n", [F, t_to_string(NewArgType), t_to_string(Ret)]), @@ -1963,18 +1964,19 @@ handle_guard_comp(Guard, Comp, Map, Env, Eval, State) -> true when Eval =:= pos -> {Map, t_atom(true)}; true when Eval =:= dont_know -> {Map, t_atom(true)}; true when Eval =:= neg -> {Map, t_atom(true)}; - false when Eval =:= pos -> signal_guard_fail(Guard, ArgTypes, State); + false when Eval =:= pos -> + signal_guard_fail(Eval, Guard, ArgTypes, State); false when Eval =:= dont_know -> {Map, t_atom(false)}; false when Eval =:= neg -> {Map, t_atom(false)} end; {literal, var} when IsInt1 andalso IsInt2 andalso (Eval =:= pos) -> case bind_comp_literal_var(Arg1, Arg2, Type2, Comp, Map1) of - error -> signal_guard_fail(Guard, ArgTypes, State); + error -> signal_guard_fail(Eval, Guard, ArgTypes, State); {ok, NewMap} -> {NewMap, t_atom(true)} end; {var, literal} when IsInt1 andalso IsInt2 andalso (Eval =:= pos) -> case bind_comp_literal_var(Arg2, Arg1, Type1, invert_comp(Comp), Map1) of - error -> signal_guard_fail(Guard, ArgTypes, State); + error -> signal_guard_fail(Eval, Guard, ArgTypes, State); {ok, NewMap} -> {NewMap, t_atom(true)} end; {_, _} -> @@ -2014,7 +2016,7 @@ handle_guard_is_function(Guard, Map, Env, Eval, State) -> [FunType0, ArityType0] = ArgTypes0, ArityType = t_inf(ArityType0, t_integer()), case t_is_none(ArityType) of - true -> signal_guard_fail(Guard, ArgTypes0, State); + true -> signal_guard_fail(Eval, Guard, ArgTypes0, State); false -> FunTypeConstr = case t_number_vals(ArityType) of @@ -2026,7 +2028,7 @@ handle_guard_is_function(Guard, Map, Env, Eval, State) -> case t_is_none(FunType) of true -> case Eval of - pos -> signal_guard_fail(Guard, ArgTypes0, State); + pos -> signal_guard_fail(Eval, Guard, ArgTypes0, State); neg -> {Map1, t_atom(false)}; dont_know -> {Map1, t_atom(false)} end; @@ -2062,7 +2064,7 @@ handle_guard_is_record(Guard, Map, Env, Eval, State) -> case t_is_none(Type) of true -> case Eval of - pos -> signal_guard_fail(Guard, + pos -> signal_guard_fail(Eval, Guard, [RecType, t_from_term(Tag), t_from_term(Arity)], State); @@ -2095,7 +2097,7 @@ handle_guard_eq(Guard, Map, Env, Eval, State) -> Eval =:= pos -> ArgTypes = [t_from_term(cerl:concrete(Arg1)), t_from_term(cerl:concrete(Arg2))], - signal_guard_fail(Guard, ArgTypes, State) + signal_guard_fail(Eval, Guard, ArgTypes, State) end end; {literal, _} when Eval =:= pos -> @@ -2150,7 +2152,7 @@ handle_guard_eqeq(Guard, Map, Env, Eval, State) -> Eval =:= pos -> ArgTypes = [t_from_term(cerl:concrete(Arg1)), t_from_term(cerl:concrete(Arg2))], - signal_guard_fail(Guard, ArgTypes, State) + signal_guard_fail(Eval, Guard, ArgTypes, State) end end; {literal, _} when Eval =:= pos -> @@ -2172,7 +2174,7 @@ bind_eqeq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State) -> case Eval of neg -> {Map2, t_atom(false)}; dont_know -> {Map2, t_atom(false)}; - pos -> signal_guard_fail(Guard, [Type1, Type2], State) + pos -> signal_guard_fail(Eval, Guard, [Type1, Type2], State) end; false -> case Eval of @@ -2199,29 +2201,29 @@ bind_eqeq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State) -> end. bind_eqeq_guard_lit_other(Guard, Arg1, Arg2, Map, Env, State) -> - %% Assumes positive evaluation + Eval = dont_know, case cerl:concrete(Arg1) of true -> {_, Type} = MT = bind_guard(Arg2, Map, Env, pos, State), case t_is_atom(true, Type) of true -> MT; false -> - {_, Type0} = bind_guard(Arg2, Map, Env, dont_know, State), - signal_guard_fail(Guard, [Type0, t_atom(true)], State) + {_, Type0} = bind_guard(Arg2, Map, Env, Eval, State), + signal_guard_fail(Eval, Guard, [Type0, t_atom(true)], State) end; false -> {Map1, Type} = bind_guard(Arg2, Map, Env, neg, State), case t_is_atom(false, Type) of true -> {Map1, t_atom(true)}; false -> - {_, Type0} = bind_guard(Arg2, Map, Env, dont_know, State), - signal_guard_fail(Guard, [Type0, t_atom(true)], State) + {_, Type0} = bind_guard(Arg2, Map, Env, Eval, State), + signal_guard_fail(Eval, Guard, [Type0, t_atom(true)], State) end; Term -> LitType = t_from_term(Term), - {Map1, Type} = bind_guard(Arg2, Map, Env, dont_know, State), + {Map1, Type} = bind_guard(Arg2, Map, Env, Eval, State), case t_is_subtype(LitType, Type) of - false -> signal_guard_fail(Guard, [Type, LitType], State); + false -> signal_guard_fail(Eval, Guard, [Type, LitType], State); true -> case cerl:is_c_var(Arg2) of true -> {enter_type(Arg2, LitType, Map1), t_atom(true)}; @@ -2250,31 +2252,37 @@ handle_guard_and(Guard, Map, Env, Eval, State) -> catch throw:{fail, _} -> bind_guard(Arg2, Map, Env, pos, State) end, {Map2, Type2} = - try bind_guard(Arg1, Map, Env, neg, State) - catch throw:{fail, _} -> bind_guard(Arg2, Map, Env, pos, State) + try bind_guard(Arg2, Map, Env, neg, State) + catch throw:{fail, _} -> bind_guard(Arg1, Map, Env, pos, State) end, case t_is_atom(false, Type1) orelse t_is_atom(false, Type2) of true -> {join_maps([Map1, Map2], Map), t_atom(false)}; false -> throw({fail, none}) end; dont_know -> - True = t_atom(true), {Map1, Type1} = bind_guard(Arg1, Map, Env, dont_know, State), - case t_is_none(t_inf(Type1, t_boolean())) of - true -> throw({fail, none}); + {Map2, Type2} = bind_guard(Arg2, Map, Env, dont_know, State), + Bool1 = t_inf(Type1, t_boolean()), + Bool2 = t_inf(Type2, t_boolean()), + case t_is_none(Bool1) orelse t_is_none(Bool2) of + true -> throw({fatal_fail, none}); false -> - {Map2, Type2} = bind_guard(Arg2, Map1, Env, Eval, State), - case t_is_none(t_inf(Type2, t_boolean())) of - true -> throw({fail, none}); - false -> {Map2, True} - end + NewMap = join_maps([Map1, Map2], Map), + NewType = + case {t_atom_vals(Bool1), t_atom_vals(Bool2)} of + {['true'] , ['true'] } -> t_atom(true); + {['false'], _ } -> t_atom(false); + {_ , ['false']} -> t_atom(false); + {_ , _ } -> t_boolean() + end, + {NewMap, NewType} end end. handle_guard_or(Guard, Map, Env, Eval, State) -> [Arg1, Arg2] = cerl:call_args(Guard), case Eval of - pos -> + pos -> {Map1, Bool1} = try bind_guard(Arg1, Map, Env, pos, State) catch @@ -2303,11 +2311,22 @@ handle_guard_or(Guard, Map, Env, Eval, State) -> end end; dont_know -> - {Map1, Bool1} = bind_guard(Arg1, Map, Env, dont_know, State), - {Map2, Bool2} = bind_guard(Arg2, Map, Env, dont_know, State), - case t_is_boolean(Bool1) andalso t_is_boolean(Bool2) of - true -> {join_maps([Map1, Map2], Map), t_sup(Bool1, Bool2)}; - false -> throw({fail, none}) + {Map1, Type1} = bind_guard(Arg1, Map, Env, dont_know, State), + {Map2, Type2} = bind_guard(Arg2, Map, Env, dont_know, State), + Bool1 = t_inf(Type1, t_boolean()), + Bool2 = t_inf(Type2, t_boolean()), + case t_is_none(Bool1) orelse t_is_none(Bool2) of + true -> throw({fatal_fail, none}); + false -> + NewMap = join_maps([Map1, Map2], Map), + NewType = + case {t_atom_vals(Bool1), t_atom_vals(Bool2)} of + {['false'], ['false']} -> t_atom(false); + {['true'] , _ } -> t_atom(true); + {_ , ['true'] } -> t_atom(true); + {_ , _ } -> t_boolean() + end, + {NewMap, NewType} end end. @@ -2349,10 +2368,12 @@ bind_guard_list([G|Gs], Map, Env, Eval, State, Acc) -> bind_guard_list([], Map, _Env, _Eval, _State, Acc) -> {Map, lists:reverse(Acc)}. --spec signal_guard_fail(cerl:c_call(), [erl_types:erl_type()], state()) -> - no_return(). +-type eval() :: 'pos' | 'neg' | 'dont_know'. + +-spec signal_guard_fail(eval(), cerl:c_call(), [erl_types:erl_type()], + state()) -> no_return(). -signal_guard_fail(Guard, ArgTypes, State) -> +signal_guard_fail(Eval, Guard, ArgTypes, State) -> Args = cerl:call_args(Guard), F = cerl:atom_val(cerl:call_name(Guard)), MFA = {cerl:atom_val(cerl:call_module(Guard)), F, length(Args)}, @@ -2365,7 +2386,7 @@ signal_guard_fail(Guard, ArgTypes, State) -> atom_to_list(F), format_args_1([Arg2], [ArgType2], State)]}; false -> - mk_guard_msg(F, Args, ArgTypes, State) + mk_guard_msg(Eval, F, Args, ArgTypes, State) end, throw({fail, {Guard, Msg}}). @@ -2380,20 +2401,25 @@ is_infix_op({erlang, '>=', 2}) -> true; is_infix_op({M, F, A}) when is_atom(M), is_atom(F), is_integer(A), 0 =< A, A =< 255 -> false. --spec signal_guard_fatal_fail(cerl:c_call(), [erl_types:erl_type()], state()) -> - no_return(). +-spec signal_guard_fatal_fail(eval(), cerl:c_call(), [erl_types:erl_type()], + state()) -> no_return(). -signal_guard_fatal_fail(Guard, ArgTypes, State) -> +signal_guard_fatal_fail(Eval, Guard, ArgTypes, State) -> Args = cerl:call_args(Guard), F = cerl:atom_val(cerl:call_name(Guard)), - Msg = mk_guard_msg(F, Args, ArgTypes, State), + Msg = mk_guard_msg(Eval, F, Args, ArgTypes, State), throw({fatal_fail, {Guard, Msg}}). -mk_guard_msg(F, Args, ArgTypes, State) -> +mk_guard_msg(Eval, F, Args, ArgTypes, State) -> FArgs = [F, format_args(Args, ArgTypes, State)], case any_has_opaque_subtype(ArgTypes) of true -> {opaque_guard, FArgs}; - false -> {guard_fail, FArgs} + false -> + case Eval of + neg -> {neg_guard_fail, FArgs}; + pos -> {guard_fail, FArgs}; + dont_know -> {guard_fail, FArgs} + end end. bind_guard_case_clauses(Arg, Clauses, Map, Env, Eval, State) -> diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl index 2c0afa6e2b..b5cefd16ca 100644 --- a/lib/dialyzer/src/dialyzer_options.erl +++ b/lib/dialyzer/src/dialyzer_options.erl @@ -2,7 +2,7 @@ %%----------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -169,6 +169,9 @@ build_options([{OptionName, Value} = Term|Rest], Options) -> output_format -> assert_output_format(Value), build_options(Rest, Options#options{output_format = Value}); + filename_opt -> + assert_filename_opt(Value), + build_options(Rest, Options#options{filename_opt = Value}); output_plt -> assert_filename(Value), build_options(Rest, Options#options{output_plt = Value}); @@ -218,6 +221,13 @@ assert_output_format(formatted) -> assert_output_format(Term) -> bad_option("Illegal value for output_format", Term). +assert_filename_opt(basename) -> + ok; +assert_filename_opt(fullpath) -> + ok; +assert_filename_opt(Term) -> + bad_option("Illegal value for filename_opt", Term). + assert_plt_op(#options{analysis_type = OldVal}, #options{analysis_type = NewVal}) -> case is_plt_mode(OldVal) andalso is_plt_mode(NewVal) of diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl index c1f95a7a67..6705ccd356 100644 --- a/lib/edoc/src/edoc_lib.erl +++ b/lib/edoc/src/edoc_lib.erl @@ -16,7 +16,6 @@ %% %% $Id$ %% -%% @private %% @copyright 2001-2003 Richard Carlsson %% @author Richard Carlsson <richardc@it.uu.se> %% @see edoc @@ -49,14 +48,17 @@ %% --------------------------------------------------------------------- %% List and string utilities +%% @private timestr({H,M,Sec}) -> lists:flatten(io_lib:fwrite("~2.2.0w:~2.2.0w:~2.2.0w",[H,M,Sec])). +%% @private datestr({Y,M,D}) -> Ms = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], lists:flatten(io_lib:fwrite("~s ~w ~w",[lists:nth(M, Ms),D,Y])). +%% @private count(X, Xs) -> count(X, Xs, 0). @@ -67,6 +69,7 @@ count(X, [_ | Xs], N) -> count(_X, [], N) -> N. +%% @private lines(Cs) -> lines(Cs, [], []). @@ -77,6 +80,7 @@ lines([C | Cs], As, Ls) -> lines([], As, Ls) -> lists:reverse([lists:reverse(As) | Ls]). +%% @private split_at(Cs, K) -> split_at(Cs, K, []). @@ -87,6 +91,7 @@ split_at([C | Cs], K, As) -> split_at([], _K, As) -> {lists:reverse(As), []}. +%% @private split_at_stop(Cs) -> split_at_stop(Cs, []). @@ -103,6 +108,7 @@ split_at_stop([C | Cs], As) -> split_at_stop([], As) -> {lists:reverse(As), []}. +%% @private split_at_space(Cs) -> split_at_space(Cs, []). @@ -117,17 +123,20 @@ split_at_space([C | Cs], As) -> split_at_space([], As) -> {lists:reverse(As), []}. +%% @private is_space([$\s | Cs]) -> is_space(Cs); is_space([$\t | Cs]) -> is_space(Cs); is_space([$\n | Cs]) -> is_space(Cs); is_space([_C | _Cs]) -> false; is_space([]) -> true. +%% @private strip_space([$\s | Cs]) -> strip_space(Cs); strip_space([$\t | Cs]) -> strip_space(Cs); strip_space([$\n | Cs]) -> strip_space(Cs); strip_space(Cs) -> Cs. +%% @private segment(Es, N) -> segment(Es, [], [], 0, N). @@ -140,6 +149,7 @@ segment([], [], Cs, _N, _M) -> segment([], As, Cs, _N, _M) -> lists:reverse([lists:reverse(As) | Cs]). +%% @private transpose([]) -> []; transpose([[] | Xss]) -> transpose(Xss); transpose([[X | Xs] | Xss]) -> @@ -151,6 +161,7 @@ transpose([[X | Xs] | Xss]) -> %% end of the summary sentence only if it is also the last segment in %% the list, or is followed by a 'p' or 'br' ("whitespace") element. +%% @private get_first_sentence([#xmlElement{name = p, content = Es} | _]) -> %% Descend into initial paragraph. get_first_sentence_1(Es); @@ -230,6 +241,7 @@ end_of_sentence_1(_, false, _) -> %% Names must begin with a lowercase letter and contain only %% alphanumerics and underscores. +%% @private is_name([C | Cs]) when C >= $a, C =< $z -> is_name_1(Cs); is_name([C | Cs]) when C >= $\337, C =< $\377, C =/= $\367 -> @@ -252,6 +264,7 @@ is_name_1(_) -> false. to_atom(A) when is_atom(A) -> A; to_atom(S) when is_list(S) -> list_to_atom(S). +%% @private unique([X | Xs]) -> [X | unique(Xs, X)]; unique([]) -> []. @@ -267,6 +280,7 @@ unique([], _) -> []. %% content of <a href="overview-summary.html#ftag-equiv">`@equiv'</a> %% tags, and strings denoting file names, e.g. in @headerfile. Also used %% by {@link edoc_run}. +%% @private parse_expr(S, L) -> case erl_scan:string(S ++ ".", L) of @@ -287,10 +301,11 @@ parse_expr(S, L) -> %% @doc EDoc "contact information" parsing. This is the type of the %% content in e.g. %% <a href="overview-summary.html#mtag-author">`@author'</a> tags. +%% @private -%% @type info() = #info{name = string(), -%% email = string(), -%% uri = string()} +%% % @type info() = #info{name = string(), +%% % email = string(), +%% % uri = string()} -record(info, {name = "" :: string(), email = "" :: string(), @@ -367,6 +382,7 @@ strip_and_reverse(As) -> %% %% TODO: general utf-8 encoding for all of Unicode (0-16#10ffff) +%% @private escape_uri([C | Cs]) when C >= $a, C =< $z -> [C | escape_uri(Cs)]; escape_uri([C | Cs]) when C >= $A, C =< $Z -> @@ -409,6 +425,7 @@ hex_octet(N) -> %% Please note that URI are *not* file names. Don't use the stdlib %% 'filename' module for operations on (any parts of) URI. +%% @private join_uri(Base, "") -> Base; join_uri("", Path) -> @@ -418,6 +435,7 @@ join_uri(Base, Path) -> %% Check for relative URI; "network paths" ("//...") not included! +%% @private is_relative_uri([$: | _]) -> false; is_relative_uri([$/, $/ | _]) -> @@ -433,6 +451,7 @@ is_relative_uri([_ | Cs]) -> is_relative_uri([]) -> true. +%% @private uri_get("file:///" ++ Path) -> uri_get_file(Path); uri_get("file://localhost/" ++ Path) -> @@ -532,6 +551,7 @@ uri_get_ftp(URI) -> Msg = io_lib:format("cannot access ftp scheme yet: '~s'.", [URI]), {error, Msg}. +%% @private to_label([$\s | Cs]) -> to_label(Cs); to_label([$\t | Cs]) -> @@ -564,6 +584,7 @@ to_label_2(Cs) -> %% --------------------------------------------------------------------- %% Files +%% @private filename([C | T]) when is_integer(C), C > 0 -> [C | filename(T)]; filename([H|T]) -> @@ -576,6 +597,7 @@ filename(N) -> report("bad filename: `~P'.", [N, 25]), exit(error). +%% @private copy_file(From, To) -> case file:copy(From, To) of {ok, _} -> ok; @@ -600,6 +622,7 @@ list_dir(Dir, Error) -> F("could not read directory '~s': ~s.", [filename(Dir), R1]) end. +%% @private simplify_path(P) -> case filename:basename(P) of "." -> @@ -636,6 +659,7 @@ simplify_path(P) -> %% exit(error) %% end. +%% @private try_subdir(Dir, Subdir) -> D = filename:join(Dir, Subdir), case filelib:is_dir(D) of @@ -648,6 +672,7 @@ try_subdir(Dir, Subdir) -> %% %% @doc Write the given `Text' to the file named by `Name' in directory %% `Dir'. If the target directory does not exist, it will be created. +%% @private write_file(Text, Dir, Name) -> write_file(Text, Dir, Name, ''). @@ -657,6 +682,7 @@ write_file(Text, Dir, Name) -> %% Name::edoc:filename(), Package::atom()|string()) -> ok %% @doc Like {@link write_file/3}, but adds path components to the target %% directory corresponding to the specified package. +%% @private write_file(Text, Dir, Name, Package) -> Dir1 = filename:join([Dir | packages:split(Package)]), @@ -672,6 +698,7 @@ write_file(Text, Dir, Name, Package) -> exit(error) end. +%% @private write_info_file(App, Packages, Modules, Dir) -> Ts = [{packages, Packages}, {modules, Modules}], @@ -703,6 +730,7 @@ info_file_data(Ts) -> %% Local file access - don't complain if file does not exist. +%% @private read_info_file(Dir) -> File = filename:join(Dir, ?INFO_FILE), case filelib:is_file(File) of @@ -769,11 +797,13 @@ parse_terms_1([], _As, _Vs) -> %% --------------------------------------------------------------------- %% Source files and packages +%% @private find_sources(Path, Opts) -> find_sources(Path, "", Opts). %% @doc See {@link edoc:run/3} for a description of the options %% `subpackages', `source_suffix' and `exclude_packages'. +%% @private %% NEW-OPTIONS: subpackages, source_suffix, exclude_packages %% DEFER-OPTIONS: edoc:run/3 @@ -827,6 +857,7 @@ is_package_dir(Name, Dir) -> is_name(filename:rootname(filename:basename(Name))) andalso filelib:is_dir(filename:join(Dir, Name)). +%% @private find_file([P | Ps], Pkg, Name) -> Dir = filename:join(P, filename:join(packages:split(Pkg))), File = filename:join(Dir, Name), @@ -839,6 +870,7 @@ find_file([P | Ps], Pkg, Name) -> find_file([], _Pkg, _Name) -> "". +%% @private find_doc_dirs() -> find_doc_dirs(code:get_path()). @@ -904,6 +936,7 @@ add_new(K, V, D) -> %% @spec (Options::proplist()) -> edoc_env() %% @equiv get_doc_env([], [], [], Opts) +%% @private get_doc_env(Opts) -> get_doc_env([], [], [], Opts). @@ -952,6 +985,7 @@ get_doc_env(App, Packages, Modules, Opts) -> %% NEW-OPTIONS: doclet %% DEFER-OPTIONS: edoc:run/3 +%% @private run_doclet(Fun, Opts) -> run_plugin(doclet, ?DEFAULT_DOCLET, Fun, Opts). @@ -961,6 +995,7 @@ run_doclet(Fun, Opts) -> %% NEW-OPTIONS: layout %% DEFER-OPTIONS: edoc:layout/2 +%% @private run_layout(Fun, Opts) -> run_plugin(layout, ?DEFAULT_LAYOUT, Fun, Opts). diff --git a/lib/edoc/src/edoc_wiki.erl b/lib/edoc/src/edoc_wiki.erl index e4a3d74734..b36aaae6ce 100644 --- a/lib/edoc/src/edoc_wiki.erl +++ b/lib/edoc/src/edoc_wiki.erl @@ -82,7 +82,8 @@ parse_xml(Data, Line) -> parse_xml_1(Text, Line) -> Text1 = "<doc>" ++ Text ++ "</doc>", - case catch {ok, xmerl_scan:string(Text1, [{line, Line}])} of + Options = [{line, Line}, {encoding, "iso-8859-1"}], + case catch {ok, xmerl_scan:string(Text1, Options)} of {ok, {E, _}} -> E#xmlElement.content; {'EXIT', {fatal, {Reason, L, _C}}} -> diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml index c7a7926c40..7c8a2c8208 100644 --- a/lib/erl_docgen/doc/src/notes.xml +++ b/lib/erl_docgen/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2009</year> + <year>2004</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -29,7 +29,22 @@ <file>notes.xml</file> </header> <p>This document describes the changes made to the erl_docgen application.</p> - <section><title>Erl_Docgen 0.2.3</title> + + <section><title>erl_docgen 0.2.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Subsections below level 2 where not handled correct when generating html and pdf.</p> + <p> + Own Id: OTP-90730</p> + </item> + </list> + </section> + + </section> + + <section><title>erl_docgen 0.2.3</title> <section><title>Fixed Bugs and Malfunctions</title> <list> @@ -56,9 +71,9 @@ </list> </section> -</section> + </section> -<section><title>Erl_Docgen 0.2.2</title> + <section><title>erl_docgen 0.2.2</title> <section><title>Fixed Bugs and Malfunctions</title> <list> @@ -71,9 +86,9 @@ </list> </section> -</section> + </section> -<section><title>erl_docgen 0.2.1</title> + <section><title>erl_docgen 0.2.1</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl index 732560e303..c6375ea621 100644 --- a/lib/erl_docgen/priv/xsl/db_html.xsl +++ b/lib/erl_docgen/priv/xsl/db_html.xsl @@ -3,7 +3,7 @@ # # %CopyrightBegin% # - # Copyright Ericsson AB 2009-2010. All Rights Reserved. + # Copyright Ericsson AB 2009-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -556,8 +556,8 @@ </xsl:apply-templates> </xsl:template> - <!-- Chapter/Subsection --> - <xsl:template match="chapter/section/section"> + <!-- Subsections lvl 3 and ... --> + <xsl:template match="section/section"> <xsl:param name="chapnum"/> <xsl:param name="sectnum"/> <h4> @@ -569,8 +569,6 @@ </xsl:apply-templates> </xsl:template> - - <!-- *ref/Section --> <xsl:template match="erlref/section|cref/section|comref/section|fileref/section|appref/section"> <xsl:param name="chapnum"/> diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl index 1e80c360b8..f500cd3fee 100644 --- a/lib/erl_docgen/priv/xsl/db_pdf.xsl +++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl @@ -3,7 +3,7 @@ # # %CopyrightBegin% # - # Copyright Ericsson AB 2009-2010. All Rights Reserved. + # Copyright Ericsson AB 2009-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -827,7 +827,7 @@ </xsl:template> - <!-- Chapter/Subsection --> + <!-- Chapter/Subsection --> <xsl:template match="chapter/section/section"> <xsl:param name="partnum"/> <xsl:param name="chapnum"/> @@ -844,6 +844,22 @@ </xsl:template> + <!-- Subsection below level 2 --> + <xsl:template match="section/section/section"> + <xsl:param name="partnum"/> + <xsl:param name="chapnum"/> + <xsl:param name="sectnum"/> + <fo:block xsl:use-attribute-sets="h5" id="{generate-id(title)}"> + <!-- xsl:value-of select="$partnum"/>.<xsl:value-of select="$chapnum"/>.<xsl:value-of select="$sectnum"/>.<xsl:number/ --> + <xsl:value-of select="title"/> + </fo:block> + <xsl:apply-templates> + <xsl:with-param name="partnum" select="$partnum"/> + <xsl:with-param name="chapnum" select="$chapnum"/> + <xsl:with-param name="sectnum" select="$sectnum"/> + </xsl:apply-templates> + </xsl:template> + <!-- *ref/Section --> <xsl:template match="erlref/section|comref/section|cref/section|fileref/section|appref/section"> diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk index fb0f5ca0cd..29585d8520 100644 --- a/lib/erl_docgen/vsn.mk +++ b/lib/erl_docgen/vsn.mk @@ -1 +1,2 @@ -ERL_DOCGEN_VSN = 0.2.3 +ERL_DOCGEN_VSN = 0.2.4 + diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 309c118107..30b911c41b 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -191,127 +191,19 @@ type(binary, referenced_byte_size, 1, Xs) -> strict(arg_types(binary, referenced_byte_size, 1), Xs, fun(_) -> t_non_neg_integer() end); %%-- code --------------------------------------------------------------------- -type(code, add_path, 1, Xs) -> - strict(arg_types(code, add_path, 1), Xs, - fun (_) -> - t_sup(t_atom('true'), - t_tuple([t_atom('error'), t_atom('bad_directory')])) - end); -type(code, add_patha, 1, Xs) -> - type(code, add_path, 1, Xs); -type(code, add_paths, 1, Xs) -> - strict(arg_types(code, add_paths, 1), Xs, fun(_) -> t_atom('ok') end); -type(code, add_pathsa, 1, Xs) -> - type(code, add_paths, 1, Xs); -type(code, add_pathsz, 1, Xs) -> - type(code, add_paths, 1, Xs); -type(code, add_pathz, 1, Xs) -> - type(code, add_path, 1, Xs); -type(code, all_loaded, 0, _) -> - t_list(t_tuple([t_atom(), t_code_loaded_fname_or_status()])); -type(code, compiler_dir, 0, _) -> - t_string(); -type(code, del_path, 1, Xs) -> - strict(arg_types(code, del_path, 1), Xs, - fun (_) -> - t_sup(t_boolean(), - t_tuple([t_atom('error'), t_atom('bad_name')])) - end); -type(code, delete, 1, Xs) -> - strict(arg_types(code, delete, 1), Xs, fun (_) -> t_boolean() end); -type(code, ensure_loaded, 1, Xs) -> - type(code, load_file, 1, Xs); type(code, get_chunk, 2, Xs) -> strict(arg_types(code, get_chunk, 2), Xs, fun (_) -> t_sup(t_binary(), t_atom('undefined')) end); -type(code, get_object_code, 1, Xs) -> - strict(arg_types(code, get_object_code, 1), Xs, - fun (_) -> - t_sup(t_tuple([t_atom(), t_binary(), t_string()]), - t_atom('error')) - end); -type(code, get_path, 0, _) -> - t_list(t_string()); -type(code, is_loaded, 1, Xs) -> - strict(arg_types(code, is_loaded, 1), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('file'), t_code_loaded_fname_or_status()]), - t_atom('false')]) - end); -type(code, is_sticky, 1, Xs) -> - strict(arg_types(code, is_sticky, 1), Xs, fun (_) -> t_boolean() end); type(code, is_module_native, 1, Xs) -> strict(arg_types(code, is_module_native, 1), Xs, fun (_) -> t_sup(t_boolean(), t_atom('undefined')) end); -type(code, lib_dir, 0, _) -> - t_string(); -type(code, lib_dir, 1, Xs) -> - strict(arg_types(code, lib_dir, 1), Xs, - fun (_) -> - t_sup(t_string(), - t_tuple([t_atom('error'), t_atom('bad_name')])) - end); -type(code, load_abs, 1, Xs) -> - strict(arg_types(code, load_abs, 1), Xs, - fun ([_File]) -> t_code_load_return(t_atom()) end); % XXX: cheating -type(code, load_abs, 2, Xs) -> - strict(arg_types(code, load_abs, 2), Xs, - fun ([_File,Mod]) -> t_code_load_return(Mod) end); -type(code, load_binary, 3, Xs) -> - strict(arg_types(code, load_binary, 3), Xs, - fun ([Mod,_File,_Bin]) -> t_code_load_return(Mod) end); -type(code, load_file, 1, Xs) -> - strict(arg_types(code, load_file, 1), Xs, - fun ([Mod]) -> t_code_load_return(Mod) end); -type(code, load_native_partial, 2, Xs) -> - strict(arg_types(code, load_native_partial, 2), Xs, - fun ([Mod,_Bin]) -> t_code_load_return(Mod) end); -type(code, load_native_sticky, 3, Xs) -> - strict(arg_types(code, load_native_sticky, 3), Xs, - fun ([Mod,_Bin,_]) -> t_code_load_return(Mod) end); type(code, module_md5, 1, Xs) -> strict(arg_types(code, module_md5, 1), Xs, fun (_) -> t_sup(t_binary(), t_atom('undefined')) end); type(code, make_stub_module, 3, Xs) -> strict(arg_types(code, make_stub_module, 3), Xs, fun ([Mod,_,_]) -> Mod end); -type(code, priv_dir, 1, Xs) -> - strict(arg_types(code, priv_dir, 1), Xs, - fun (_) -> - t_sup(t_string(), t_tuple([t_atom('error'), t_atom('bad_name')])) - end); -type(code, purge, 1, Xs) -> - type(code, delete, 1, Xs); -type(code, rehash, 0, _) -> t_atom('ok'); -type(code, replace_path, 2, Xs) -> - strict(arg_types(code, replace_path, 2), Xs, - fun (_) -> - t_sup([t_atom('true'), - t_tuple([t_atom('error'), t_atom('bad_name')]), - t_tuple([t_atom('error'), t_atom('bad_directory')]), - t_tuple([t_atom('error'), - t_tuple([t_atom('badarg'), t_any()])])]) - end); -type(code, root_dir, 0, _) -> - t_string(); -type(code, set_path, 1, Xs) -> - strict(arg_types(code, set_path, 1), Xs, - fun (_) -> - t_sup([t_atom('true'), - t_tuple([t_atom('error'), t_atom('bad_path')]), - t_tuple([t_atom('error'), t_atom('bad_directory')])]) - end); -type(code, soft_purge, 1, Xs) -> - type(code, delete, 1, Xs); -type(code, stick_mod, 1, Xs) -> - strict(arg_types(code, stick_mod, 1), Xs, fun (_) -> t_atom('true') end); -type(code, unstick_mod, 1, Xs) -> - type(code, stick_mod, 1, Xs); -type(code, which, 1, Xs) -> - strict(arg_types(code, which, 1), Xs, - fun (_) -> - t_sup([t_code_loaded_fname_or_status(), - t_atom('non_existing')]) - end); +type(code, rehash, 0, _) -> + t_atom('ok'); %%-- erl_ddll ----------------------------------------------------------------- type(erl_ddll, demonitor, 1, Xs) -> type(erlang, demonitor, 1, Xs); @@ -3334,80 +3226,16 @@ arg_types(binary, part, 3) -> arg_types(binary, referenced_byte_size, 1) -> [t_binary()]; %%------- code ---------------------------------------------------------------- -arg_types(code, add_path, 1) -> - [t_string()]; -arg_types(code, add_patha, 1) -> - arg_types(code, add_path, 1); -arg_types(code, add_paths, 1) -> - [t_list(t_string())]; -arg_types(code, add_pathsa, 1) -> - arg_types(code, add_paths, 1); -arg_types(code, add_pathsz, 1) -> - arg_types(code, add_paths, 1); -arg_types(code, add_pathz, 1) -> - arg_types(code, add_path, 1); -arg_types(code, all_loaded, 0) -> - []; -arg_types(code, compiler_dir, 0) -> - []; -arg_types(code, del_path, 1) -> - [t_sup(t_string(), t_atom())]; % OBS: differs from add_path/1 -arg_types(code, delete, 1) -> - [t_atom()]; -arg_types(code, ensure_loaded, 1) -> - arg_types(code, load_file, 1); arg_types(code, get_chunk, 2) -> [t_binary(), t_string()]; -arg_types(code, get_object_code, 1) -> - [t_atom()]; -arg_types(code, get_path, 0) -> - []; -arg_types(code, is_loaded, 1) -> - [t_atom()]; -arg_types(code, is_sticky, 1) -> - [t_atom()]; arg_types(code, is_module_native, 1) -> [t_atom()]; -arg_types(code, lib_dir, 0) -> - []; -arg_types(code, lib_dir, 1) -> - [t_atom()]; -arg_types(code, load_abs, 1) -> - [t_string()]; -arg_types(code, load_abs, 2) -> - [t_code_loaded_fname_or_status(), t_atom()]; -arg_types(code, load_binary, 3) -> - [t_atom(), t_code_loaded_fname_or_status(), t_binary()]; -arg_types(code, load_file, 1) -> - [t_atom()]; -arg_types(code, load_native_partial, 2) -> - [t_atom(), t_binary()]; -arg_types(code, load_native_sticky, 3) -> - [t_atom(), t_binary(), t_sup(t_binary(), t_atom('false'))]; arg_types(code, module_md5, 1) -> [t_binary()]; arg_types(code, make_stub_module, 3) -> [t_atom(), t_binary(), t_tuple([t_list(), t_list()])]; -arg_types(code, priv_dir, 1) -> - [t_atom()]; -arg_types(code, purge, 1) -> - arg_types(code, delete, 1); arg_types(code, rehash, 0) -> []; -arg_types(code, replace_path, 2) -> - [t_atom(), t_string()]; -arg_types(code, root_dir, 0) -> - []; -arg_types(code, set_path, 1) -> - [t_list(t_string())]; -arg_types(code, soft_purge, 1) -> - arg_types(code, delete, 1); -arg_types(code, stick_mod, 1) -> - [t_atom()]; -arg_types(code, unstick_mod, 1) -> - arg_types(code, stick_mod, 1); -arg_types(code, which, 1) -> - [t_atom()]; %%------- erl_ddll ------------------------------------------------------------ arg_types(erl_ddll, demonitor, 1) -> arg_types(erlang, demonitor, 1); @@ -3536,9 +3364,9 @@ arg_types(erlang, atom_to_binary, 2) -> arg_types(erlang, atom_to_list, 1) -> [t_atom()]; arg_types(erlang, binary_part, 2) -> - [t_binary(), t_tuple([t_integer(),t_integer()])]; + [t_binary(), t_tuple([t_non_neg_integer(), t_integer()])]; arg_types(erlang, binary_part, 3) -> - [t_binary(), t_integer(), t_integer()]; + [t_binary(), t_non_neg_integer(), t_integer()]; arg_types(erlang, binary_to_atom, 2) -> [t_binary(), t_encoding_a2b()]; arg_types(erlang, binary_to_existing_atom, 2) -> @@ -3801,9 +3629,10 @@ arg_types(erlang, nodes, 1) -> arg_types(erlang, now, 0) -> []; arg_types(erlang, open_port, 2) -> + ArgT = t_sup(t_unicode_string(), t_binary()), [t_sup(t_atom(), t_sup([t_tuple([t_atom('spawn'), t_string()]), t_tuple([t_atom('spawn_driver'), t_string()]), - t_tuple([t_atom('spawn_executable'), t_sup(t_unicode_string(),t_binary())]), + t_tuple([t_atom('spawn_executable'), ArgT]), t_tuple([t_atom('fd'), t_integer(), t_integer()])])), t_list(t_sup(t_sup([t_atom('stream'), t_atom('exit_status'), @@ -3819,8 +3648,8 @@ arg_types(erlang, open_port, 2) -> t_tuple([t_atom('line'), t_integer()]), t_tuple([t_atom('cd'), t_string()]), t_tuple([t_atom('env'), t_list(t_tuple(2))]), % XXX: More - t_tuple([t_atom('args'), t_list(t_sup(t_unicode_string(),t_binary()))]), - t_tuple([t_atom('arg0'),t_sup(t_unicode_string(),t_binary())])])))]; + t_tuple([t_atom('args'), t_list(ArgT)]), + t_tuple([t_atom('arg0'), ArgT])])))]; arg_types(erlang, phash, 2) -> [t_any(), t_pos_integer()]; arg_types(erlang, phash2, 1) -> @@ -4643,10 +4472,10 @@ t_endian() -> %% ===================================================================== t_binary_part() -> - t_tuple([t_non_neg_integer(),t_integer()]). + t_tuple([t_non_neg_integer(), t_integer()]). t_binary_canonical_part() -> - t_tuple([t_non_neg_integer(),t_non_neg_integer()]). + t_tuple([t_non_neg_integer(), t_non_neg_integer()]). t_binary_pattern() -> t_sup([t_binary(), @@ -4654,10 +4483,10 @@ t_binary_pattern() -> t_binary_compiled_pattern()]). t_binary_compiled_pattern() -> - t_tuple([t_atom('cp'),t_binary()]). + t_tuple([t_atom('cp'), t_binary()]). t_binary_options() -> - t_list(t_tuple([t_atom('scope'),t_binary_part()])). + t_list(t_tuple([t_atom('scope'), t_binary_part()])). %% ===================================================================== %% HTTP types documented in R12B-4 @@ -4807,7 +4636,8 @@ t_process_priority_level() -> t_sup([t_atom('max'), t_atom('high'), t_atom('normal'), t_atom('low')]). t_process_status() -> - t_sup([t_atom('runnable'), t_atom('running'), + t_sup([t_atom('exiting'), t_atom('garbage_collecting'), + t_atom('runnable'), t_atom('running'), t_atom('suspended'), t_atom('waiting')]). t_raise_errorclass() -> diff --git a/lib/hipe/icode/hipe_icode_range.erl b/lib/hipe/icode/hipe_icode_range.erl index c7e6a451af..c222e8a5d5 100644 --- a/lib/hipe/icode/hipe_icode_range.erl +++ b/lib/hipe/icode/hipe_icode_range.erl @@ -1,20 +1,20 @@ %% -*- erlang-indent-level: 2 -*- %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %%%------------------------------------------------------------------- @@ -59,15 +59,17 @@ -record(range, {range :: range_rep(), other :: boolean()}). +-type range() :: #range{}. --record(ann, {range :: #range{}, +-record(ann, {range :: range(), type :: erl_types:erl_type(), count :: integer()}). +-type ann() :: #ann{}. --type range_anno() :: {range_anno, #ann{}, fun((#ann{}) -> string())}. --type args_fun() :: fun((mfa(),cfg()) -> [#range{}]). --type call_fun() :: fun((mfa(),[#range{}]) -> #range{}). --type final_fun() :: fun((mfa(),[#range{}]) -> ok). +-type range_anno() :: {'range_anno', ann(), fun((ann()) -> string())}. +-type args_fun() :: fun((mfa(), cfg()) -> [range()]). +-type call_fun() :: fun((mfa(), [range()]) -> range()). +-type final_fun() :: fun((mfa(), [range()]) -> 'ok'). -type data() :: {mfa(), args_fun(), call_fun(), final_fun()}. -type label() :: non_neg_integer(). -type info() :: gb_tree(). @@ -75,15 +77,15 @@ -type variable() :: #icode_variable{}. -type annotated_variable() :: #icode_variable{}. -type argument() :: #icode_const{} | variable(). --type three_range_fun() :: fun((#range{},#range{},#range{}) -> #range{}). +-type three_range_fun() :: fun((range(),range(),range()) -> range()). -type instr_split_info() :: {icode_instr(), [{label(),info()}]}. --type last_instr_return() :: {instr_split_info(), #range{}}. +-type last_instr_return() :: {instr_split_info(), range()}. -record(state, {info_map = gb_trees:empty() :: info(), counter = dict:new() :: dict(), cfg :: cfg(), liveness = gb_trees:empty() :: gb_tree(), - ret_type :: #range{}, + ret_type :: range(), lookup_fun :: call_fun(), result_action :: final_fun()}). @@ -108,8 +110,8 @@ cfg(Cfg, MFA, Options, Servers) -> -spec concurrent_cfg(cfg(), mfa(), pid()) -> cfg(). concurrent_cfg(Cfg, MFA, CompServer) -> - CompServer ! {ready, {MFA,self()}}, - {ArgsFun,CallFun,FinalFun} = do_analysis(Cfg, MFA), + CompServer ! {ready, {MFA, self()}}, + {ArgsFun, CallFun, FinalFun} = do_analysis(Cfg, MFA), Ans = do_rewrite(Cfg, MFA, ArgsFun, CallFun, FinalFun), CompServer ! {done_rewrite, MFA}, Ans. @@ -227,7 +229,7 @@ analyse_block(Label, Info, State, Rewrite) -> state__update_info(State2, InfoList, Rewrite). -spec analyse_BB([icode_instr()], info(), [icode_instr()], boolean(), call_fun()) -> - {[icode_instr()], [{label(),info()}], #range{}}. + {[icode_instr()], [{label(),info()}], range()}. analyse_BB([Last], Info, Code, Rewrite, LookupFun) -> {{NewI, LabelInfoList}, RetType} = @@ -266,9 +268,9 @@ handle_args(I, Info, WidenFun) -> %% io:format("Uses: ~p~nRanges: ~p~n", [Uses, PresentRanges]), JoinFun = fun(Var, Range) -> update_info(Var, Range, WidenFun) end, NewUses = lists:zipwith(JoinFun, Uses, PresentRanges), - hipe_icode:subst_uses(lists:zip(Uses, NewUses),I). + hipe_icode:subst_uses(lists:zip(Uses, NewUses), I). --spec join_info(#ann{}, #range{}, three_range_fun()) -> #ann{}. +-spec join_info(ann(), range(), three_range_fun()) -> ann(). join_info(Ann = #ann{range = R1, type = Type, count = ?WIDEN}, R2, Fun) -> Ann#ann{range = Fun(R1, R2, range_from_simple_type(Type))}; @@ -278,17 +280,17 @@ join_info(Ann = #ann{range = R1, type = Type, count = C}, R2, _Fun) when C < ?WI NewR -> Ann#ann{range = NewR, count = C+1} end. --spec join_three(#range{}, #range{}, #range{}) -> #range{}. +-spec join_three(range(), range(), range()) -> range(). join_three(R1, R2, R3) -> inf(sup(R1, R2), R3). --spec update_info(variable(), #range{}) -> annotated_variable(). +-spec update_info(variable(), range()) -> annotated_variable(). update_info(Var, Range) -> update_info(Var, Range, fun update_three/3). --spec update_info(variable(), #range{}, three_range_fun()) -> annotated_variable(). +-spec update_info(variable(), range(), three_range_fun()) -> annotated_variable(). update_info(Arg, R, Fun) -> case hipe_icode:is_annotated_variable(Arg) of @@ -299,7 +301,7 @@ update_info(Arg, R, Fun) -> Arg end. --spec update_info1(any(), #range{}, three_range_fun()) -> range_anno(). +-spec update_info1(any(), range(), three_range_fun()) -> range_anno(). update_info1({range_anno, Ann, _}, R2, Fun) -> make_range_anno(update_ann(Ann,R2,Fun)); @@ -314,71 +316,71 @@ update_ann(Ann = #ann{range = R1, type = Type, count = C}, R2, _Fun) -> NewR -> Ann#ann{range = NewR, count = C+1} end. --spec type_to_ann(erl_types:erl_type()) -> #ann{}. +-spec type_to_ann(erl_types:erl_type()) -> ann(). type_to_ann(Type) -> - #ann{range = range_from_simple_type(Type), type = t_limit(Type,1), count=1}. + #ann{range = range_from_simple_type(Type), type = t_limit(Type,1), count = 1}. --spec make_range_anno(#ann{}) -> range_anno(). +-spec make_range_anno(ann()) -> range_anno(). make_range_anno(Ann) -> {range_anno, Ann, fun pp_ann/1}. --spec update_three(#range{}, #range{}, #range{}) -> #range{}. +-spec update_three(range(), range(), range()) -> range(). update_three(_R1, R2, R3) -> inf(R2, R3). --spec safe_widen(#range{}, #range{}, #range{}) -> #range{}. +-spec safe_widen(range(), range(), range()) -> range(). safe_widen(#range{range=Old}, #range{range=New}, T = #range{range=Wide}) -> ResRange = - case {Old,New,Wide} of - {{Min,Max1},{Min,Max2},{_,Max}} -> - case inf_geq(OMax = next_up_limit(inf_max([Max1,Max2])),Max) of + case {Old, New, Wide} of + {{Min,Max1}, {Min,Max2}, {_,Max}} -> + case inf_geq(OMax = next_up_limit(inf_max([Max1, Max2])), Max) of true -> {Min,Max}; false -> {Min,OMax} end; - {{Min1,Max},{Min2,Max},{Min,_}} -> - case inf_geq(Min, OMin = next_down_limit(inf_min([Min1,Min2]))) of + {{Min1,Max}, {Min2,Max}, {Min,_}} -> + case inf_geq(Min, OMin = next_down_limit(inf_min([Min1, Min2]))) of true -> {Min,Max}; false -> {OMin,Max} end; - {{Min1,Max1},{Min2,Max2},{Min,Max}} -> + {{Min1,Max1}, {Min2,Max2}, {Min,Max}} -> RealMax = - case inf_geq(OMax = next_up_limit(inf_max([Max1,Max2])),Max) of + case inf_geq(OMax = next_up_limit(inf_max([Max1, Max2])), Max) of true -> Max; false -> OMax end, RealMin = - case inf_geq(Min, OMin = next_down_limit(inf_min([Min1,Min2]))) of + case inf_geq(Min, OMin = next_down_limit(inf_min([Min1, Min2]))) of true -> Min; false -> OMin end, - {RealMin,RealMax}; + {RealMin, RealMax}; _ -> Wide end, - T#range{range=ResRange}. + T#range{range = ResRange}. --spec widen(#range{}, #range{}, #range{}) -> #range{}. +-spec widen(range(), range(), range()) -> range(). widen(#range{range=Old}, #range{range=New}, T = #range{range=Wide}) -> ResRange = - case {Old,New,Wide} of - {{Min,_},{Min,Max2},{_,Max}} -> - case inf_geq(OMax = next_up_limit(Max2),Max) of + case {Old, New, Wide} of + {{Min,_}, {Min,Max2}, {_,Max}} -> + case inf_geq(OMax = next_up_limit(Max2), Max) of true -> {Min,Max}; false -> {Min,OMax} end; - {{_,Max},{Min2,Max},{Min,_}} -> + {{_,Max}, {Min2,Max}, {Min,_}} -> case inf_geq(Min, OMin = next_down_limit(Min2)) of true -> {Min,Max}; false -> {OMin,Max} end; - {_,{Min2,Max2},{Min,Max}} -> + {_, {Min2,Max2}, {Min,Max}} -> RealMax = - case inf_geq(OMax = next_up_limit(Max2),Max) of + case inf_geq(OMax = next_up_limit(Max2), Max) of true -> Max; false -> OMax end, @@ -387,11 +389,11 @@ widen(#range{range=Old}, #range{range=New}, T = #range{range=Wide}) -> true -> Min; false -> OMin end, - {RealMin,RealMax}; + {RealMin, RealMax}; _ -> Wide end, - T#range{range=ResRange}. + T#range{range = ResRange}. -spec analyse_call(#icode_call{}, call_fun()) -> #icode_call{}. @@ -421,7 +423,7 @@ analyse_move(Move) -> analyse_begin_handler(Handler) -> SubstList = - [{Dst,update_info(Dst,any_type())} || + [{Dst, update_info(Dst, any_type())} || Dst <- hipe_icode:begin_handler_dstlist(Handler)], hipe_icode:subst_defines(SubstList, Handler). @@ -494,14 +496,14 @@ analyse_switch_val(Switch, Info, Rewrite) -> end end. --spec update_infos(argument(), info(), [{#range{},label()}]) -> [{label(),info()}]. +-spec update_infos(argument(), info(), [{range(),label()}]) -> [{label(),info()}]. update_infos(Arg, Info, [{Range, Label}|Rest]) -> - [{Label,enter_define({Arg,Range},Info)} | update_infos(Arg,Info,Rest)]; + [{Label,enter_define({Arg,Range},Info)} | update_infos(Arg, Info, Rest)]; update_infos(_, _, []) -> []. --spec get_range_label_list([{argument(),label()}], #range{}, [{#range{},label()}]) -> - {#range{},[{#range{},label()}]}. +-spec get_range_label_list([{argument(),label()}], range(), [{range(),label()}]) -> + {range(),[{range(),label()}]}. get_range_label_list([{Val,Label}|Cases], SRange, Acc) -> VRange = get_range_from_arg(Val), @@ -516,7 +518,7 @@ get_range_label_list([], SRange, Acc) -> {PointTypes, _} = lists:unzip(Acc), {remove_point_types(SRange, PointTypes), Acc}. --spec update_switch(#icode_switch_val{}, [{#range{},label()}], boolean()) -> +-spec update_switch(#icode_switch_val{}, [{range(),label()}], boolean()) -> #icode_switch_val{}. update_switch(Switch, LabelRangeList, KeepFail) -> @@ -524,14 +526,14 @@ update_switch(Switch, LabelRangeList, KeepFail) -> case label_range_list_to_cases(LabelRangeList, []) of no_update -> Switch; - Cases -> + Cases -> hipe_icode:switch_val_cases_update(Switch, Cases) end, if KeepFail -> S2; true -> S2 end. --spec label_range_list_to_cases([{#range{},label()}], [{#icode_const{},label()}]) -> +-spec label_range_list_to_cases([{range(),label()}], [{#icode_const{},label()}]) -> 'no_update' | [{#icode_const{},label()}]. label_range_list_to_cases([{#range{range={C,C},other=false},Label}|Rest], @@ -586,9 +588,9 @@ analyse_last_call(Call, Info, LookupFun) -> NewInfo = enter_vals(NewI, Info), case hipe_icode:call_fail_label(Call) of [] -> - {NewI, [{Continuation,NewInfo}]}; + {NewI, [{Continuation, NewInfo}]}; Fail -> - {NewI, [{Continuation,NewInfo}, {Fail,Info}]} + {NewI, [{Continuation, NewInfo}, {Fail, Info}]} end. -spec analyse_if(#icode_if{}, info(), boolean()) -> @@ -596,16 +598,16 @@ analyse_last_call(Call, Info, LookupFun) -> analyse_if(If, Info, Rewrite) -> case hipe_icode:if_args(If) of - Args = [_,_] -> + [_, _] = Args -> analyse_sane_if(If, Info, Args, get_range_from_args(Args), Rewrite); _ -> TrueLabel = hipe_icode:if_true_label(If), FalseLabel = hipe_icode:if_false_label(If), - {If, [{TrueLabel,Info},{FalseLabel,Info}]} + {If, [{TrueLabel, Info}, {FalseLabel, Info}]} end. -spec analyse_sane_if(#icode_if{}, info(), [argument(),...], - [#range{},...], boolean()) -> + [range(),...], boolean()) -> {#icode_goto{} | #icode_if{}, [{label(), info()}]}. analyse_sane_if(If, Info, [Arg1, Arg2], [Range1, Range2], Rewrite) -> @@ -613,59 +615,61 @@ analyse_sane_if(If, Info, [Arg1, Arg2], [Range1, Range2], Rewrite) -> '>' -> {TrueRange2, TrueRange1, FalseRange2, FalseRange1} = range_inequality_propagation(Range2, Range1); - '==' -> - {TempTrueRange1, TempTrueRange2, FalseRange1, FalseRange2}= - range_equality_propagation(Range1, Range2), - TrueRange1 = set_other(TempTrueRange1,other(Range1)), - TrueRange2 = set_other(TempTrueRange2,other(Range2)); '<' -> - {TrueRange1, TrueRange2, FalseRange1, FalseRange2} = + {TrueRange1, TrueRange2, FalseRange1, FalseRange2} = range_inequality_propagation(Range1, Range2); '>=' -> {FalseRange1, FalseRange2, TrueRange1, TrueRange2} = range_inequality_propagation(Range1, Range2); '=<' -> - {FalseRange2, FalseRange1, TrueRange2, TrueRange1} = + {FalseRange2, FalseRange1, TrueRange2, TrueRange1} = range_inequality_propagation(Range2, Range1); '=:=' -> - {TrueRange1, TrueRange2, FalseRange1, FalseRange2}= + {TrueRange1, TrueRange2, FalseRange1, FalseRange2} = range_equality_propagation(Range1, Range2); '=/=' -> {FalseRange1, FalseRange2, TrueRange1, TrueRange2} = range_equality_propagation(Range1, Range2); + '==' -> + {TempTrueRange1, TempTrueRange2, FalseRange1, FalseRange2} = + range_equality_propagation(Range1, Range2), + TrueRange1 = set_other(TempTrueRange1, other(Range1)), + TrueRange2 = set_other(TempTrueRange2, other(Range2)); '/=' -> - {TempFalseRange1, TempFalseRange2, TrueRange1, TrueRange2}= + {TempFalseRange1, TempFalseRange2, TrueRange1, TrueRange2} = range_equality_propagation(Range1, Range2), - FalseRange1 = set_other(TempFalseRange1,other(Range1)), - FalseRange2 = set_other(TempFalseRange2,other(Range2)) + FalseRange1 = set_other(TempFalseRange1, other(Range1)), + FalseRange2 = set_other(TempFalseRange2, other(Range2)) end, - TrueLabel = hipe_icode:if_true_label(If), - FalseLabel = hipe_icode:if_false_label(If), - TrueInfo = - enter_defines([{Arg1,TrueRange1}, {Arg2,TrueRange2}],Info), - FalseInfo = - enter_defines([{Arg1,FalseRange1}, {Arg2,FalseRange2}],Info), - True = - case lists:any(fun range__is_none/1,[TrueRange1,TrueRange2]) of + %% io:format("TR1 = ~w\nTR2 = ~w\n", [TrueRange1, TrueRange2]), + True = + case lists:all(fun range__is_none/1, [TrueRange1, TrueRange2]) of true -> []; - false -> [{TrueLabel,TrueInfo}] + false -> + TrueLabel = hipe_icode:if_true_label(If), + TrueArgRanges = [{Arg1, TrueRange1}, {Arg2, TrueRange2}], + TrueInfo = enter_defines(TrueArgRanges, Info), + [{TrueLabel, TrueInfo}] end, - False = - case lists:any(fun range__is_none/1, [FalseRange1,FalseRange2]) of + %% io:format("FR1 = ~w\nFR2 = ~w\n", [FalseRange1, FalseRange2]), + False = + case lists:all(fun range__is_none/1, [FalseRange1, FalseRange2]) of true -> []; - false -> [{FalseLabel,FalseInfo}] + false -> + FalseLabel = hipe_icode:if_false_label(If), + FalseArgRanges = [{Arg1, FalseRange1}, {Arg2, FalseRange2}], + FalseInfo = enter_defines(FalseArgRanges, Info), + [{FalseLabel, FalseInfo}] end, - UpdateInfo = True++False, + UpdateInfo = True ++ False, NewIF = if Rewrite -> - %%io:format("~w~n~w~n", [{Arg1,FalseRange1},{Arg2,FalseRange2}]), - %%io:format("Any none: ~w~n", [lists:any(fun range__is_none/1,[FalseRange1,FalseRange2])]), case UpdateInfo of - [] -> %%This is weird + [] -> %% This is weird If; - [{Label,_Info}] -> + [{Label, _Info}] -> hipe_icode:mk_goto(Label); - [_,_] -> + [_, _] -> If end; true -> @@ -686,13 +690,13 @@ normalize_name(Name) -> Name -> Name end. --spec range_equality_propagation(#range{}, #range{}) -> - {#range{}, #range{}, #range{}, #range{}}. +-spec range_equality_propagation(range(), range()) -> + {range(), range(), range(), range()}. range_equality_propagation(Range_1, Range_2) -> True_range = inf(Range_1, Range_2), case {range(Range_1), range(Range_2)} of - {{N,N},{ N,N}} -> + {{N,N}, {N,N}} -> False_range_1 = none_range(), False_range_2 = none_range(); {{N1,N1}, {N2,N2}} -> @@ -710,8 +714,8 @@ range_equality_propagation(Range_1, Range_2) -> end, {True_range, True_range, False_range_1, False_range_2}. --spec range_inequality_propagation(#range{}, #range{}) -> - {#range{}, #range{}, #range{}, #range{}}. +-spec range_inequality_propagation(range(), range()) -> + {range(), range(), range(), range()}. %% Range1 < Range2 range_inequality_propagation(Range1, Range2) -> @@ -781,26 +785,24 @@ analyse_type(Type, Info, Rewrite) -> TrueRange = inf(any_range(), OldVarRange), FalseRange = inf(none_range(), OldVarRange); _ -> - TrueRange = inf(none_range(),OldVarRange), + TrueRange = inf(none_range(), OldVarRange), FalseRange = OldVarRange end, TrueLabel = hipe_icode:type_true_label(Type), FalseLabel = hipe_icode:type_false_label(Type), - TrueInfo = - enter_define({Arg,TrueRange},Info), - FalseInfo = - enter_define({Arg,FalseRange},Info), - True = + TrueInfo = enter_define({Arg, TrueRange}, Info), + FalseInfo = enter_define({Arg, FalseRange}, Info), + True = case range__is_none(TrueRange) of true -> []; - false -> [{TrueLabel,TrueInfo}] + false -> [{TrueLabel, TrueInfo}] end, - False = + False = case range__is_none(FalseRange) of true -> []; - false -> [{FalseLabel,FalseInfo}] + false -> [{FalseLabel, FalseInfo}] end, - UpdateInfo = True++False, + UpdateInfo = True ++ False, NewType = if Rewrite -> case UpdateInfo of @@ -808,15 +810,15 @@ analyse_type(Type, Info, Rewrite) -> Type; [{Label,_Info}] -> hipe_icode:mk_goto(Label); - [_,_] -> + [_, _] -> Type end; true -> Type end, - {NewType,True ++ False}. + {NewType, True ++ False}. --spec compare_with_integer(integer(), #range{}) -> {#range{}, #range{}}. +-spec compare_with_integer(integer(), range()) -> {range(), range()}. compare_with_integer(N, OldVarRange) -> TestRange = range_init({N, N}, false), @@ -843,13 +845,13 @@ compare_with_integer(N, OldVarRange) -> %%== Ranges ================================================================== --spec pp_ann(#ann{} | erl_types:erl_type()) -> string(). +-spec pp_ann(ann() | erl_types:erl_type()) -> string(). -pp_ann(#ann{range=#range{range=R, other=false}}) -> +pp_ann(#ann{range = #range{range = R, other = false}}) -> pp_range(R); -pp_ann(#ann{range=#range{range=empty, other=true}, type=Type}) -> +pp_ann(#ann{range = #range{range = empty, other = true}, type = Type}) -> t_to_string(Type); -pp_ann(#ann{range=#range{range=R, other=true}, type=Type}) -> +pp_ann(#ann{range = #range{range = R, other = true}, type = Type}) -> pp_range(R) ++ " | " ++ t_to_string(Type); pp_ann(Type) -> t_to_string(Type). @@ -867,12 +869,12 @@ val_to_string(pos_inf) -> "inf"; val_to_string(neg_inf) -> "-inf"; val_to_string(X) when is_integer(X) -> integer_to_list(X). --spec range_from_type(erl_types:erl_type()) -> [#range{}]. +-spec range_from_type(erl_types:erl_type()) -> [range()]. range_from_type(Type) -> [range_from_simple_type(T) || T <- t_to_tlist(Type)]. --spec range_from_simple_type(erl_types:erl_type()) -> #range{}. +-spec range_from_simple_type(erl_types:erl_type()) -> range(). range_from_simple_type(Type) -> None = t_none(), @@ -887,7 +889,7 @@ range_from_simple_type(Type) -> #range{range = Range, other = true} end. --spec range_init(range_rep(), boolean()) -> #range{}. +-spec range_init(range_rep(), boolean()) -> range(). range_init({Min, Max} = Range, Other) -> case inf_geq(Max, Min) of @@ -899,39 +901,39 @@ range_init({Min, Max} = Range, Other) -> range_init(empty, Other) -> #range{range = empty, other = Other}. --spec range(#range{}) -> range_rep(). +-spec range(range()) -> range_rep(). range(#range{range = R}) -> R. --spec other(#range{}) -> boolean(). +-spec other(range()) -> boolean(). other(#range{other = O}) -> O. --spec set_other(#range{}, boolean()) -> #range{}. +-spec set_other(range(), boolean()) -> range(). set_other(R, O) -> R#range{other = O}. --spec range__min(#range{}) -> 'empty' | 'neg_inf' | integer(). +-spec range__min(range()) -> 'empty' | 'neg_inf' | integer(). -range__min(#range{range=empty}) -> empty; -range__min(#range{range={Min,_}}) -> Min. +range__min(#range{range = empty}) -> empty; +range__min(#range{range = {Min,_}}) -> Min. --spec range__max(#range{}) -> 'empty' | 'pos_inf' | integer(). +-spec range__max(range()) -> 'empty' | 'pos_inf' | integer(). -range__max(#range{range=empty}) -> empty; -range__max(#range{range={_,Max}}) -> Max. +range__max(#range{range = empty}) -> empty; +range__max(#range{range = {_,Max}}) -> Max. --spec range__is_none(#range{}) -> boolean(). +-spec range__is_none(range()) -> boolean(). -range__is_none(#range{range=empty, other=false}) -> true; +range__is_none(#range{range = empty, other = false}) -> true; range__is_none(#range{}) -> false. --spec range__is_empty(#range{}) -> boolean(). +-spec range__is_empty(range()) -> boolean(). -range__is_empty(#range{range=empty}) -> true; -range__is_empty(#range{range={_,_}}) -> false. +range__is_empty(#range{range = empty}) -> true; +range__is_empty(#range{range = {_,_}}) -> false. --spec remove_point_types(#range{}, [#range{}]) -> #range{}. +-spec remove_point_types(range(), [range()]) -> range(). remove_point_types(Range, Ranges) -> Sorted = lists:sort(Ranges), @@ -939,35 +941,35 @@ remove_point_types(Range, Ranges) -> Range1 = lists:foldl(FoldFun, Range, Sorted), lists:foldl(FoldFun, Range1, lists:reverse(Sorted)). --spec range__remove_constant(#range{}, #range{}) -> #range{}. +-spec range__remove_constant(range(), range()) -> range(). -range__remove_constant(R = #range{range={C,C}}, #range{range={C,C}}) -> - R#range{range=empty}; -range__remove_constant(R = #range{range={C,H}}, #range{range={C,C}}) -> - R#range{range={C+1,H}}; -range__remove_constant(R = #range{range={L,C}}, #range{range={C,C}}) -> - R#range{range={L,C-1}}; -range__remove_constant(R = #range{}, #range{range={C,C}}) -> +range__remove_constant(#range{range = {C, C}} = R, #range{range = {C, C}}) -> + R#range{range = empty}; +range__remove_constant(#range{range = {C, H}} = R, #range{range = {C, C}}) -> + R#range{range = {C+1, H}}; +range__remove_constant(#range{range = {L, C}} = R, #range{range = {C, C}}) -> + R#range{range = {L, C-1}}; +range__remove_constant(#range{} = R, #range{range = {C,C}}) -> R; -range__remove_constant(R = #range{}, _) -> +range__remove_constant(#range{} = R, _) -> R. --spec any_type() -> #range{}. +-spec any_type() -> range(). any_type() -> - #range{range=any_r(), other=true}. + #range{range = any_r(), other = true}. --spec any_range() -> #range{}. +-spec any_range() -> range(). any_range() -> - #range{range=any_r(), other=false}. + #range{range = any_r(), other = false}. --spec none_range() -> #range{}. +-spec none_range() -> range(). none_range() -> - #range{range=empty, other=true}. + #range{range = empty, other = true}. --spec none_type() -> #range{}. +-spec none_type() -> range(). none_type() -> #range{range = empty, other = false}. @@ -976,12 +978,12 @@ none_type() -> any_r() -> {neg_inf, pos_inf}. --spec get_range_from_args([argument()]) -> [#range{}]. +-spec get_range_from_args([argument()]) -> [range()]. get_range_from_args(Args) -> [get_range_from_arg(Arg) || Arg <- Args]. --spec get_range_from_arg(argument()) -> #range{}. +-spec get_range_from_arg(argument()) -> range(). get_range_from_arg(Arg) -> case hipe_icode:is_const(Arg) of @@ -989,15 +991,15 @@ get_range_from_arg(Arg) -> Value = hipe_icode:const_value(Arg), case is_integer(Value) of true -> - #range{range={Value,Value}, other=false}; + #range{range = {Value, Value}, other = false}; false -> - #range{range=empty, other=true} + #range{range = empty, other = true} end; false -> case hipe_icode:is_annotated_variable(Arg) of true -> case hipe_icode:variable_annotation(Arg) of - {range_anno, #ann{range=Range}, _} -> + {range_anno, #ann{range = Range}, _} -> Range; {type_anno, Type, _} -> range_from_simple_type(Type) @@ -1012,7 +1014,7 @@ get_range_from_arg(Arg) -> %% inf([R1,R2|Rest]) -> %% inf([inf(R1,R2)|Rest]). --spec inf(#range{}, #range{}) -> #range{}. +-spec inf(range(), range()) -> range(). inf(#range{range=R1, other=O1}, #range{range=R2, other=O2}) -> #range{range=range_inf(R1,R2), other=other_inf(O1,O2)}. @@ -1022,8 +1024,8 @@ inf(#range{range=R1, other=O1}, #range{range=R2, other=O2}) -> range_inf(empty, _) -> empty; range_inf(_, empty) -> empty; range_inf({Min1,Max1}, {Min2,Max2}) -> - NewMin = inf_max([Min1,Min2]), - NewMax = inf_min([Max1,Max2]), + NewMin = inf_max([Min1, Min2]), + NewMax = inf_min([Max1, Max2]), case inf_geq(NewMax, NewMin) of true -> {NewMin, NewMax}; @@ -1035,14 +1037,14 @@ range_inf({Min1,Max1}, {Min2,Max2}) -> other_inf(O1, O2) -> O1 and O2. --spec sup([#range{},...]) -> #range{}. +-spec sup([range(),...]) -> range(). sup([R]) -> R; sup([R1,R2|Rest]) -> sup([sup(R1, R2)|Rest]). --spec sup(#range{}, #range{}) -> #range{}. +-spec sup(range(), range()) -> range(). sup(#range{range=R1,other=O1}, #range{range=R2,other=O2}) -> #range{range=range_sup(R1,R2), other=other_sup(O1,O2)}. @@ -1063,7 +1065,7 @@ other_sup(O1, O2) -> O1 or O2. %%== Call Support ============================================================= -spec analyse_call_or_enter_fun(fun_name(), [argument()], - icode_call_type(), call_fun()) -> [#range{}]. + icode_call_type(), call_fun()) -> [range()]. analyse_call_or_enter_fun(Fun, Args, CallType, LookupFun) -> %%io:format("Fun: ~p~n Args: ~p~n CT: ~p~n LF: ~p~n", [Fun, Args, CallType, LookupFun]), @@ -1105,19 +1107,19 @@ analyse_call_or_enter_fun(Fun, Args, CallType, LookupFun) -> [any_type()]; {hipe_bs_primop, {bs_get_integer, Size, Flags}} -> {Min, Max} = analyse_bs_get_integer(Size, Flags, length(Args) =:= 1), - [#range{range={Min, Max}, other=false}, any_type()]; + [#range{range = {Min, Max}, other = false}, any_type()]; {hipe_bs_primop, _} = Primop -> Type = hipe_icode_primops:type(Primop), range_from_type(Type) end. --type bin_operation() :: fun((#range{},#range{}) -> #range{}). --type unary_operation() :: fun((#range{}) -> #range{}). +-type bin_operation() :: fun((range(), range()) -> range()). +-type unary_operation() :: fun((range()) -> range()). -spec basic_type(fun_name()) -> 'not_int' | 'not_analysed' - | {bin, bin_operation()} - | {unary, unary_operation()} - | {fcall, mfa()} | {hipe_bs_primop, _}. + | {'bin', bin_operation()} + | {'unary', unary_operation()} + | {'fcall', mfa()} | {'hipe_bs_primop', _}. %% Arithmetic operations basic_type('+') -> {bin, fun(R1, R2) -> range_add(R1, R2) end}; @@ -1214,7 +1216,7 @@ analyse_bs_get_integer(Size, Flags, false) when is_integer(Size), %% Arithmetic --spec range_add(#range{}, #range{}) -> #range{}. +-spec range_add(range(), range()) -> range(). range_add(Range1, Range2) -> NewMin = inf_add(range__min(Range1), range__min(Range2)), @@ -1222,7 +1224,7 @@ range_add(Range1, Range2) -> Other = other(Range1) orelse other(Range2), range_init({NewMin, NewMax}, Other). --spec range_sub(#range{}, #range{}) -> #range{}. +-spec range_sub(range(), range()) -> range(). range_sub(Range1, Range2) -> Min_sub = inf_min([inf_inv(range__max(Range2)), @@ -1234,7 +1236,7 @@ range_sub(Range1, Range2) -> Other = other(Range1) orelse other(Range2), range_init({NewMin, NewMax}, Other). --spec range_mult(#range{}, #range{}) -> #range{}. +-spec range_mult(range(), range()) -> range(). range_mult(#range{range=empty, other=true}, _Range2) -> range_init(empty, true); @@ -1274,7 +1276,7 @@ range_mult(Range1, Range2) -> Other = other(Range1) orelse other(Range2), range_init(Range, Other). --spec extreme_divisors(#range{}) -> range_tuple(). +-spec extreme_divisors(range()) -> range_tuple(). extreme_divisors(#range{range={0,0}}) -> {0,0}; extreme_divisors(#range{range={0,Max}}) -> {1,Max}; @@ -1289,7 +1291,7 @@ extreme_divisors(#range{range={Min,Max}}) -> end end. --spec range_div(#range{}, #range{}) -> #range{}. +-spec range_div(range(), range()) -> range(). %% this is div, not /. range_div(_, #range{range={0,0}}) -> @@ -1306,7 +1308,7 @@ range_div(Range1, Den) -> inf_div(Max1, Min2), inf_div(Max1, Max2)], range_init({inf_min(Min_max_list), inf_max(Min_max_list)}, false). --spec range_rem(#range{}, #range{}) -> #range{}. +-spec range_rem(range(), range()) -> range(). range_rem(Range1, Range2) -> %% Range1 desides the sign of the answer. @@ -1332,7 +1334,7 @@ range_rem(Range1, Range2) -> %%--- Bit operations ---------------------------- --spec range_bsr(#range{}, #range{}) -> #range{}. +-spec range_bsr(range(), range()) -> range(). range_bsr(Range1, Range2=#range{range={Min, Max}}) -> New_Range2 = range_init({inf_inv(Max), inf_inv(Min)}, other(Range2)), @@ -1340,7 +1342,7 @@ range_bsr(Range1, Range2=#range{range={Min, Max}}) -> %% io:format("bsr res:~w~nInput:= ~w~n", [Ans, {Range1,Range2}]), Ans. --spec range_bsl(#range{}, #range{}) -> #range{}. +-spec range_bsl(range(), range()) -> range(). range_bsl(Range1, Range2) -> Min1 = range__min(Range1), @@ -1359,7 +1361,7 @@ range_bsl(Range1, Range2) -> end, range_init(MinMax, false). --spec range_bnot(#range{}) -> #range{}. +-spec range_bnot(range()) -> range(). range_bnot(Range) -> Minus_one = range_init({-1,-1}, false), @@ -1389,7 +1391,7 @@ negwidth(X, N) -> false -> negwidth(X, N+1) end. --spec range_band(#range{}, #range{}) -> #range{}. +-spec range_band(range(), range()) -> range(). range_band(R1, R2) -> {_Min1, Max1} = MM1 = range(R1), @@ -1423,7 +1425,7 @@ range_band(R1, R2) -> end, range_init(Range, false). --spec range_bor(#range{}, #range{}) -> #range{}. +-spec range_bor(range(), range()) -> range(). range_bor(R1, R2) -> {Min1, _Max1} = MM1 = range(R1), @@ -1457,7 +1459,7 @@ range_bor(R1, R2) -> end, range_init(Range, false). --spec classify_range(#range{}) -> 'minus_minus' | 'minus_plus' | 'plus_plus'. +-spec classify_range(range()) -> 'minus_minus' | 'minus_plus' | 'plus_plus'. classify_range(Range) -> case range(Range) of @@ -1480,7 +1482,7 @@ classify_int_range(_Number1, Number2) when Number2 < 0 -> classify_int_range(_Number1, _Number2) -> minus_plus. --spec range_bxor(#range{}, #range{}) -> #range{}. +-spec range_bxor(range(), range()) -> range(). range_bxor(R1, R2) -> {Min1, Max1} = MM1 = range(R1), @@ -1895,7 +1897,7 @@ convert_ann_to_types(#ann{range=#range{other=true}, type=Type}) -> %% Icode Coordinator Callbacks %%===================================================================== --spec replace_nones([#range{}]) -> [#range{}]. +-spec replace_nones([range()]) -> [range()]. replace_nones(Args) -> [replace_none(Arg) || Arg <- Args]. @@ -1905,7 +1907,7 @@ replace_none(Arg) -> false -> Arg end. --spec update__info([#range{}], [#range{}]) -> {boolean(), [#ann{}]}. +-spec update__info([range()], [range()]) -> {boolean(), [ann()]}. update__info(NewRanges, OldRanges) -> SupFun = fun (Ann, Range) -> join_info(Ann, Range, fun safe_widen/3) @@ -1915,19 +1917,19 @@ update__info(NewRanges, OldRanges) -> Change = lists:zipwith(EqFun, ResRanges, OldRanges), {lists:all(fun (X) -> X end, Change), ResRanges}. --spec new__info/1 :: ([#range{}]) -> [#ann{}]. +-spec new__info([range()]) -> [ann()]. new__info(NewRanges) -> [#ann{range=Range,count=1,type=t_any()} || Range <- NewRanges]. --spec return__info/1 :: ([#ann{}]) -> [#range{}]. +-spec return__info([ann()]) -> [range()]. return__info(Ranges) -> [Range || #ann{range=Range} <- Ranges]. --spec return_none/0 :: () -> [#range{},...]. +-spec return_none() -> [range(),...]. return_none() -> [none_type()]. --spec return_none_args/2 :: (#cfg{}, mfa()) -> [#range{}]. +-spec return_none_args(cfg(), mfa()) -> [range()]. return_none_args(Cfg, {_M,_F,A}) -> NoArgs = case hipe_icode_cfg:is_closure(Cfg) of @@ -1936,7 +1938,7 @@ return_none_args(Cfg, {_M,_F,A}) -> end, lists:duplicate(NoArgs, none_type()). --spec return_any_args/2 :: (#cfg{}, mfa()) -> [#range{}]. +-spec return_any_args(cfg(), mfa()) -> [range()]. return_any_args(Cfg, {_M,_F,A}) -> NoArgs = case hipe_icode_cfg:is_closure(Cfg) of diff --git a/lib/inets/doc/src/http_client.xml b/lib/inets/doc/src/http_client.xml index 672ea3fa98..4542211d71 100644 --- a/lib/inets/doc/src/http_client.xml +++ b/lib/inets/doc/src/http_client.xml @@ -42,10 +42,10 @@ dynamically in runtime. Each client profile will spawn a new process to handle each request unless there is a possibility to use a persistent connection with or without pipelining. - The client will add a host header and an empty - te header if there are no such headers present in the request.</p> + The client will add a <c>host</c> header and an empty + <c>te</c> header if there are no such headers present in the request.</p> - <p>The clients supports ipv6 as long as the underlying mechanisms also do + <p>The client supports ipv6 as long as the underlying mechanisms also do so.</p> </section> @@ -87,7 +87,7 @@ httpc:request("http://www.erlang.org"). </code> <p>An ordinary asynchronous request. The result will be sent - to the calling process on the form {http, {ReqestId, Result}}</p> + to the calling process in the form <c>{http, {ReqestId, Result}}</c></p> <code type="erl"> 5 > {ok, RequestId} = httpc:request(get, {"http://www.erlang.org", []}, [], [{sync, false}]). diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml index c20358178b..bcdd2913e0 100644 --- a/lib/inets/doc/src/httpc.xml +++ b/lib/inets/doc/src/httpc.xml @@ -36,7 +36,7 @@ <note> <p>When starting the Inets application a manager process for the default profile will be started. The functions in this API - that does not explicitly use a profile will accesses the + that do not explicitly use a profile will access the default profile. A profile keeps track of proxy options, cookies and other options that can be applied to more than one request. </p> @@ -117,7 +117,7 @@ ssl_options() = {verify, code()} | application or started dynamically in runtime by calling the inets application API <c>inets:start(httpc, ServiceConfig)</c>, or <c>inets:start(httpc, ServiceConfig, How)</c> - see <seealso marker="inets">inets(3)</seealso> Below follows a + see <seealso marker="inets">inets(3)</seealso>. Below follows a description of the available configuration options.</p> <taglist> <tag>{profile, profile()}</tag> @@ -129,8 +129,8 @@ ssl_options() = {verify, code()} | as session cookies.</item> </taglist> - <p>The client can be stopped using inets:stop(httpc, Pid) or - inets:stop(httpc, Profile).</p> + <p>The client can be stopped using <c>inets:stop(httpc, Pid)</c> or + <c>inets:stop(httpc, Profile)</c>.</p> <marker id="request1"></marker> </section> @@ -148,7 +148,7 @@ ssl_options() = {verify, code()} | <v>Reason = term() </v> </type> <desc> - <p>Equivalent to httpc:request(get, {Url, []}, [], []).</p> + <p>Equivalent to <c>httpc:request(get, {Url, []}, [], [])</c>.</p> <marker id="request2"></marker> </desc> @@ -201,7 +201,7 @@ ssl_options() = {verify, code()} | <desc> <p>Sends a HTTP-request. The function can be both synchronous and asynchronous. In the later case the function will return - {ok, RequestId} and later on the information will be delivered + <c>{ok, RequestId}</c> and later on the information will be delivered to the <c>receiver</c> depending on that value. </p> <p>Http option (<c>http_option()</c>) details: </p> @@ -209,7 +209,7 @@ ssl_options() = {verify, code()} | <tag><c><![CDATA[timeout]]></c></tag> <item> <p>Timeout time for the request. </p> - <p>The clock start ticking as soon as the request has been + <p>The clock starts ticking as soon as the request has been sent. </p> <p>Time is in milliseconds. </p> <p>Defaults to <c>infinity</c>. </p> @@ -246,11 +246,11 @@ ssl_options() = {verify, code()} | <tag><c><![CDATA[autoredirect]]></c></tag> <item> - <p>Should the client automatically retreive the information + <p>Should the client automatically retrieve the information from the new URI and return that as the result instead of a 30X-result code. </p> <p>Note that for some 30X-result codes automatic redirect - is not allowed in these cases the 30X-result will always + is not allowed. In these cases the 30X-result will always be returned. </p> <p>Defaults to <c>true</c>. </p> </item> @@ -267,12 +267,12 @@ ssl_options() = {verify, code()} | <c>HTTP/0.9</c> client. By default this is an <c>HTTP/1.1</c> client. When using <c>HTTP/1.0</c> persistent connections will not be used. </p> - <p>Defaults to the trsing <c>"HTTP/1.1"</c>. </p> + <p>Defaults to the string <c>"HTTP/1.1"</c>. </p> </item> <tag><c><![CDATA[relaxed]]></c></tag> <item> - <p>If set to true workarounds for known server deviations from + <p>If set to <c>true</c> workarounds for known server deviations from the HTTP-standard are enabled. </p> <p>Defaults to <c>false</c>. </p> </item> @@ -296,21 +296,21 @@ ssl_options() = {verify, code()} | <item> <p>Streams the body of a 200 or 206 response to the calling process or to a file. When streaming to the calling process - using the option <c>self</c> the the following stream messages - will be sent to that process: {http, {RequestId, + using the option <c>self</c> the following stream messages + will be sent to that process: <c>{http, {RequestId, stream_start, Headers}, {http, {RequestId, stream, - BinBodyPart}, {http, {RequestId, stream_end, Headers}. When + BinBodyPart}, {http, {RequestId, stream_end, Headers}</c>. When streaming to to the calling processes using the option <c>{self, once}</c> the first message will have an additional - element e.i. {http, {RequestId, stream_start, Headers, Pid}, + element e.i. <c>{http, {RequestId, stream_start, Headers, Pid}</c>, this is the process id that should be used as an argument to - http:stream_next/1 to trigger the next message to be sent to + <c>http:stream_next/1</c> to trigger the next message to be sent to the calling process. </p> <p>Note that it is possible that chunked encoding will add - headers so that there are more headers in the stream_end - message than in the stream_start. + headers so that there are more headers in the <c>stream_end</c> + message than in the <c>stream_start</c>. When streaming to a file and the request is asynchronous the - message {http, {RequestId, saved_to_file}} will be sent. </p> + message <c>{http, {RequestId, saved_to_file}}</c> will be sent. </p> <p>Defaults to <c>none</c>. </p> </item> @@ -338,7 +338,7 @@ ssl_options() = {verify, code()} | case insenstive. This feature should only be used if there is no other way to communicate with the server or for testing purpose. Also note that when this option is used no headers - will be automatically added, all necessary headers has to be + will be automatically added, all necessary headers have to be provided by the user. </p> <p>Defaults to <c>false</c>. </p> </item> @@ -354,16 +354,16 @@ ssl_options() = {verify, code()} | checked in any way. </p> <p>Note that this may change the socket behaviour (see <seealso marker="kernel:inet#setopts">inet:setopts/2</seealso>) - for an already existing, and therefor already connected + for an already existing one, and therefore an already connected request handler. </p> - <p>By defaults the socket options set by the + <p>By default the socket options set by the <seealso marker="#set_options">set_options/1,2</seealso> - function is used when establishing connection. </p> + function are used when establishing a connection. </p> </item> <tag><c><![CDATA[receiver]]></c></tag> <item> - <p>Defines how the client will deliver the result for a + <p>Defines how the client will deliver the result of an asynchroneous request (<c>sync</c> has the value <c>false</c>). </p> @@ -395,7 +395,7 @@ apply(Module, Function, [ReplyInfo | Args]) </item> </taglist> - <p>In all cases above, <c>ReplyInfo</c> has the following + <p>In all of the above cases, <c>ReplyInfo</c> has the following structure: </p> <pre> @@ -470,46 +470,46 @@ apply(Module, Function, [ReplyInfo | Args]) <v>IpDesc = string()</v> <d>ex: "134.138" or "[FEDC:BA98" (all IP-addresses starting with 134.138 or FEDC:BA98), "66.35.250.150" or "[2010:836B:4179::836B:4179]" (a complete IP-address).</d> <v>MaxSessions = integer() </v> - <d>Default is <em>2</em>. + <d>Default is <c>2</c>. Maximum number of persistent connections to a host.</d> <v>MaxKeepAlive = integer() </v> - <d>Default is <em>5</em>. + <d>Default is <c>5</c>. Maximum number of outstanding requests on the same connection to a host.</d> <v>KeepAliveTimeout = integer() </v> - <d>Default is <em>120000</em> (= 2 min). + <d>Default is <c>120000</c> (= 2 min). If a persistent connection is idle longer than the - keep_alive_timeout the client will close the connection. - The server may also have a such a time out but you should + <c>keep_alive_timeout</c> the client will close the connection. + The server may also have such a time out but you should not count on it!</d> <v>MaxPipeline = integer() </v> - <d>Default is <em>2</em>. + <d>Default is <c>2</c>. Maximum number of outstanding requests on a pipelined connection to a host.</d> <v>PipelineTimeout = integer() </v> - <d>Default is <em>0</em>, + <d>Default is <c>0</c>, which will result in pipelining not being used. If a persistent connection is idle longer than the - pipeline_timeout the client will close the connection. </d> + <c>pipeline_timeout</c> the client will close the connection. </d> <v>CookieMode = enabled | disabled | verify </v> - <d>Default is <em>disabled</em>. + <d>Default is <c>disabled</c>. If Cookies are enabled all valid cookies will automatically be saved in the client manager's cookie database. - If the option verify is used the function http:verify_cookie/2 - has to be called for the cookie to be saved.</d> + If the option <c>verify</c> is used the function <c>store_cookies/2</c> + has to be called for the cookies to be saved.</d> <v>IpFamily = inet | inet6 | inet6fb4 </v> - <d>By default <em>inet</em>. + <d>By default <c>inet</c>. When it is set to <c>inet6fb4</c> you can use both ipv4 and ipv6. It first tries <c>inet6</c> and if that does not works falls back to <c>inet</c>. The option is here to provide a workaround for buggy ipv6 stacks to ensure that ipv4 will always work.</d> <v>IpAddress = ip_address() </v> <d>If the host has several network interfaces, this option specifies which one to use. - See gen_tcp:connect/3,4 for more info. </d> + See <seealso marker="kernel:gen_tcp#connect">gen_tcp:connect/3,4</seealso> for more info. </d> <v>Port = integer() </v> <d>Specify which local port number to use. - See gen_tcp:connect/3,4 for more info. </d> + See <seealso marker="kernel:gen_tcp#connect">gen_tcp:connect/3,4</seealso> for more info. </d> <v>VerboseMode = false | verbose | debug | trace </v> - <d>Default is <em>false</em>. + <d>Default is <c>false</c>. This option is used to switch on (or off) different levels of erlang trace on the client. It is a debug feature.</d> @@ -523,14 +523,14 @@ apply(Module, Function, [ReplyInfo | Args]) alive and use persistent connections with or without pipeline depending on configuration and current circumstances. The HTTP/1.1 specification does not - provide a guideline for how many requests that would be + provide a guideline for how many requests would be ideal to be sent on a persistent connection, this very much depends on the application. Note that a very long queue of requests may cause a - user perceived delays as earlier request may take a long time + user perceived delay as earlier requests may take a long time to complete. The HTTP/1.1 specification does suggest a limit of 2 persistent connections per server, which is the - default value of the max_sessions option. </p> + default value of the <c>max_sessions</c> option. </p> </note> <marker id="stream_next"></marker> @@ -549,14 +549,14 @@ apply(Module, Function, [ReplyInfo | Args]) <p>Triggers the next message to be streamed, e.i. same behavior as active once for sockets.</p> - <marker id="verify_cookie"></marker> - <marker id="store_cookie"></marker> + <marker id="verify_cookies"></marker> + <marker id="store_cookies"></marker> </desc> </func> <func> - <name>store_cookie(SetCookieHeaders, Url) -> </name> - <name>store_cookie(SetCookieHeaders, Url, Profile) -> ok | {error, Reason}</name> + <name>store_cookies(SetCookieHeaders, Url) -> </name> + <name>store_cookies(SetCookieHeaders, Url, Profile) -> ok | {error, Reason}</name> <fsummary>Saves the cookies defined in SetCookieHeaders in the client profile's cookie database.</fsummary> <type> <v>SetCookieHeaders = headers() - where field = "set-cookie"</v> @@ -566,7 +566,7 @@ apply(Module, Function, [ReplyInfo | Args]) <desc> <p>Saves the cookies defined in SetCookieHeaders in the client profile's cookie database. You need to - call this function if you set the option cookies to <c>verify</c>. + call this function if you have set the option <c>cookies</c> to <c>verify</c>. If no profile is specified the default profile will be used. </p> @@ -576,16 +576,16 @@ apply(Module, Function, [ReplyInfo | Args]) <func> <name>cookie_header(Url) -> </name> - <name>cookie_header(Url, Profile) -> header() | {error, Rason}</name> + <name>cookie_header(Url, Profile) -> header() | {error, Reason}</name> <fsummary>Returns the cookie header that would be sent when - making a request to Url using the profile Profile.</fsummary> + making a request to Url using the profile <c>Profile</c>.</fsummary> <type> <v>Url = url()</v> <v>Profile = profile()</v> </type> <desc> <p>Returns the cookie header that would be sent - when making a request to Url using the profile Profile. + when making a request to <c>Url</c> using the profile <c>Profile</c>. If no profile is specified the default profile will be used. </p> @@ -602,7 +602,7 @@ apply(Module, Function, [ReplyInfo | Args]) <v>Profile = profile()</v> </type> <desc> - <p>Resets (clears) the cookie database for the specified Profile. + <p>Resets (clears) the cookie database for the specified <c>Profile</c>. If no profile is specified the default profile will be used. </p> </desc> diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 11b0af4310..5da9d98002 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> <header> <copyright> - <year>2002</year><year>2010</year> + <year>2002</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,50 +32,78 @@ <file>notes.xml</file> </header> - <section><title>Inets 5.5.1</title> + <section><title>Inets 5.5.2</title> - <section><title>Fixed Bugs and Malfunctions</title> + <section><title>Improvements and New Features</title> + <p>-</p> + +<!-- <list> <item> - <p> Fix format_man_pages so it handles all man sections - and remove warnings/errors in various man pages. </p> <p> - Own Id: OTP-8600</p> + Miscellaneous inet6 related problems.</p> + <p>Own Id: OTP-8927</p> </item> + </list> +--> + + </section> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> <item> - <p> - [httpc] Pipelined and queued requests not processed when - connection closed remotelly.</p> - <p> - Own Id: OTP-8906</p> + <p>[httpd] httpd_response:send_chunk handles empty list and + empty binary - i.e. no chunk is sent, but it does + not handle a list with an empty binary [<<>>]. + This will be sent as an empty chunk - which in turn + will be encoded by http_chunk to the same as a final + chunk, which will make the http client believe that + the end of the page is reached.</p> + <p>Own Id: OTP-8906</p> </item> </list> </section> + </section> <!-- 5.5.2 --> + + + <section><title>Inets 5.5.1</title> <section><title>Improvements and New Features</title> <list> <item> - <p> - Miscellaneous inet6 related problems.</p> - <p> - Own Id: OTP-8927</p> + <p>Miscellaneous inet6 related problems.</p> + <p>Own Id: OTP-8927</p> </item> <item> - <p> - Updated http-server to make sure URLs in error-messages - are URL-encoded. Added support in http-client to use - URL-encoding. Also added the missing include directory - for the inets application.</p> - <p> - Own Id: OTP-8940 Aux Id: seq11735 </p> + <p>Updated http-server to make sure URLs in error-messages + are URL-encoded. Added support in http-client to use + URL-encoding. Also added the missing include directory + for the inets application.</p> + <p>Own Id: OTP-8940 Aux Id: seq11735 </p> </item> </list> </section> -</section> + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Fix format_man_pages so it handles all man sections + and remove warnings/errors in various man pages. </p> + <p>Own Id: OTP-8600</p> + </item> + <item> + <p>[httpc] Pipelined and queued requests not processed when + connection closed remotelly.</p> + <p>Own Id: OTP-8906</p> + </item> + </list> + </section> -<section><title>Inets 5.5</title> + </section> <!-- 5.5.1 --> + + + <section><title>Inets 5.5</title> <section><title>Fixed Bugs and Malfunctions</title> <list> @@ -120,9 +148,10 @@ </list> </section> -</section> + </section> <!-- 5.5 --> + -<section><title>Inets 5.4</title> + <section><title>Inets 5.4</title> <section><title>Improvements and New Features</title> <!-- diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index ae754fab94..04fae13b20 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -252,7 +252,7 @@ set_option(Key, Value, Profile) -> %% Description: Store the cookies from <SetCookieHeaders> %% in the cookie database %% for the profile <Profile>. This function shall be used when the option -%% cookie is set to verify. +%% cookies is set to verify. %%------------------------------------------------------------------------- store_cookies(SetCookieHeaders, Url) -> store_cookies(SetCookieHeaders, Url, default_profile()). diff --git a/lib/inets/src/http_lib/http_chunk.erl b/lib/inets/src/http_lib/http_chunk.erl index 621bc68eae..57647438e9 100644 --- a/lib/inets/src/http_lib/http_chunk.erl +++ b/lib/inets/src/http_lib/http_chunk.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -17,7 +17,8 @@ %% %CopyrightEnd% %% %% Description: Implements chunked transfer encoding see RFC2616 section -%% 3.6.1 +%% 3.6.1 + -module(http_chunk). -include("http_internal.hrl"). @@ -28,6 +29,7 @@ %% little at a time on a socket. -export([decode_size/1, ignore_extensions/1, decode_data/1, decode_trailer/1]). + %%%========================================================================= %%% API %%%========================================================================= @@ -81,6 +83,9 @@ encode(Chunk) when is_binary(Chunk)-> HEXSize = list_to_binary(http_util:integer_to_hexlist(size(Chunk))), <<HEXSize/binary, ?CR, ?LF, Chunk/binary, ?CR, ?LF>>; +encode([<<>>]) -> + []; + encode(Chunk) when is_list(Chunk)-> HEXSize = http_util:integer_to_hexlist(erlang:iolist_size(Chunk)), [HEXSize, ?CR, ?LF, Chunk, ?CR, ?LF]. @@ -88,6 +93,7 @@ encode(Chunk) when is_list(Chunk)-> encode_last() -> <<$0, ?CR, ?LF, ?CR, ?LF >>. + %%------------------------------------------------------------------------- %% handle_headers(HeaderRecord, ChunkedHeaders) -> NewHeaderRecord %% diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 0194c65db9..07da8ca961 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -1,7 +1,7 @@ %% This is an -*- erlang -*- file. %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,6 +18,11 @@ {"%VSN%", [ + {"5.5.1", + [ + {load_module, http_chunk, soft_purge, soft_purge, []} + ] + }, {"5.5", [ {restart_application, inets} @@ -30,7 +35,12 @@ } ], [ - {"5.4", + {"5.5.1", + [ + {load_module, http_chunk, soft_purge, soft_purge, []} + ] + }, + {"5.5", [ {restart_application, inets} ] diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 67737ee552..b1de3fef43 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2010. All Rights Reserved. +# Copyright Ericsson AB 2001-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml index 8e7192a496..aa171c77c2 100644 --- a/lib/kernel/doc/src/gen_tcp.xml +++ b/lib/kernel/doc/src/gen_tcp.xml @@ -74,6 +74,7 @@ posix() socket() as returned by accept/1,2 and connect/3,4</code> + <marker id="connect"></marker> </section> <funcs> <func> diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index feb5131aad..b0f99305f2 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -72,39 +72,42 @@ %% User interface. %% -%% objfile_extension() -> ".beam" -%% set_path(Dir*) -> true -%% get_path() -> Dir* -%% add_path(Dir) -> true | {error, What} -%% add_patha(Dir) -> true | {error, What} -%% add_pathz(Dir) -> true | {error, What} -%% add_paths(DirList) -> true | {error, What} -%% add_pathsa(DirList) -> true | {error, What} -%% add_pathsz(DirList) -> true | {error, What} -%% del_path(Dir) -> true | {error, What} -%% replace_path(Name,Dir) -> true | {error, What} -%% load_file(File) -> {error,What} | {module, Mod} -%% load_abs(File) -> {error,What} | {module, Mod} -%% load_abs(File,Mod) -> {error,What} | {module, Mod} -%% load_binary(Mod,File,Bin) -> {error,What} | {module,Mod} -%% ensure_loaded(Module) -> {error,What} | {module, Mod} -%% delete(Module) -%% purge(Module) kills all procs running old code -%% soft_purge(Module) -> true | false -%% is_loaded(Module) -> {file, File} | false -%% all_loaded() -> {Module, File}* -%% get_object_code(Mod) -> error | {Mod, Bin, Filename} -%% stop() -> true -%% root_dir() -%% compiler_dir() -%% lib_dir() -%% priv_dir(Name) -%% stick_dir(Dir) -> ok | error -%% unstick_dir(Dir) -> ok | error -%% is_sticky(Module) -> true | false -%% which(Module) -> Filename -%% set_primary_archive((FileName, Bin, FileInfo) -> ok | {error, Reason} -%% clash() -> -> print out +%% objfile_extension() -> ".beam" +%% get_path() -> [Dir] +%% set_path([Dir]) -> true | {error, bad_directory | bad_path} +%% add_path(Dir) -> true | {error, bad_directory} +%% add_patha(Dir) -> true | {error, bad_directory} +%% add_pathz(Dir) -> true | {error, bad_directory} +%% add_paths([Dir]) -> ok +%% add_pathsa([Dir]) -> ok +%% add_pathsz([Dir]) -> ok +%% del_path(Dir) -> boolean() | {error, bad_name} +%% replace_path(Name, Dir) -> true | replace_path_error() +%% load_file(Module) -> {module, Module} | {error, What :: atom()} +%% load_abs(File) -> {module, Module} | {error, What :: atom()} +%% load_abs(File, Module) -> {module, Module} | {error, What :: atom()} +%% load_binary(Module, File, Bin)-> {module, Module} | {error, What :: atom()} +%% ensure_loaded(Module) -> {module, Module} | {error, What :: atom()} +%% delete(Module) -> boolean() +%% purge(Module) -> boolean() kills all procs running old code +%% soft_purge(Module) -> boolean() +%% is_loaded(Module) -> {file, loaded_filename()} | false +%% all_loaded() -> [{Module, loaded_filename()}] +%% get_object_code(Module) -> {Module, Bin, Filename} | error +%% stop() -> no_return() +%% root_dir() -> Dir +%% compiler_dir() -> Dir +%% lib_dir() -> Dir +%% lib_dir(Application) -> Dir | {error, bad_name} +%% priv_dir(Application) -> Dir | {error, bad_name} +%% stick_dir(Dir) -> ok | error +%% unstick_dir(Dir) -> ok | error +%% stick_mod(Module) -> true +%% unstick_mod(Module) -> true +%% is_sticky(Module) -> boolean() +%% which(Module) -> Filename | loaded_ret_atoms() | non_existing +%% set_primary_archive((FileName, Bin, FileInfo) -> ok | {error, Reason} +%% clash() -> ok prints out number of clashes %%---------------------------------------------------------------------------- %% Some types for basic exported functions of this module @@ -120,7 +123,7 @@ %% User interface %%---------------------------------------------------------------------------- --spec objfile_extension() -> file:filename(). +-spec objfile_extension() -> nonempty_string(). objfile_extension() -> init:objfile_extension(). @@ -138,21 +141,21 @@ load_abs(File) when is_list(File); is_atom(File) -> call({load_abs,File,[]}). %% XXX Filename is also an atom(), e.g. 'cover_compiled' -spec load_abs(Filename :: loaded_filename(), Module :: atom()) -> load_ret(). -load_abs(File,M) when (is_list(File) orelse is_atom(File)), is_atom(M) -> +load_abs(File, M) when (is_list(File) orelse is_atom(File)), is_atom(M) -> call({load_abs,File,M}). %% XXX Filename is also an atom(), e.g. 'cover_compiled' -spec load_binary(Module :: atom(), Filename :: loaded_filename(), Binary :: binary()) -> load_ret(). -load_binary(Mod,File,Bin) +load_binary(Mod, File, Bin) when is_atom(Mod), (is_list(File) orelse is_atom(File)), is_binary(Bin) -> call({load_binary,Mod,File,Bin}). -spec load_native_partial(Module :: atom(), Binary :: binary()) -> load_ret(). -load_native_partial(Mod,Bin) when is_atom(Mod), is_binary(Bin) -> +load_native_partial(Mod, Bin) when is_atom(Mod), is_binary(Bin) -> call({load_native_partial,Mod,Bin}). -spec load_native_sticky(Module :: atom(), Binary :: binary(), WholeModule :: 'false' | binary()) -> load_ret(). -load_native_sticky(Mod,Bin,WholeModule) +load_native_sticky(Mod, Bin, WholeModule) when is_atom(Mod), is_binary(Bin), (is_binary(WholeModule) orelse WholeModule =:= false) -> call({load_native_sticky,Mod,Bin,WholeModule}). @@ -160,7 +163,7 @@ load_native_sticky(Mod,Bin,WholeModule) -spec delete(Module :: atom()) -> boolean(). delete(Mod) when is_atom(Mod) -> call({delete,Mod}). --spec purge/1 :: (Module :: atom()) -> boolean(). +-spec purge(Module :: atom()) -> boolean(). purge(Mod) when is_atom(Mod) -> call({purge,Mod}). -spec soft_purge(Module :: atom()) -> boolean(). @@ -195,7 +198,7 @@ lib_dir(App, SubDir) when is_atom(App), is_atom(SubDir) -> call({dir,{lib_dir,Ap compiler_dir() -> call({dir,compiler_dir}). %% XXX is_list() is for backwards compatibility -- take out in future version --spec priv_dir(Appl :: atom()) -> file:filename() | {'error', 'bad_name'}. +-spec priv_dir(App :: atom()) -> file:filename() | {'error', 'bad_name'}. priv_dir(App) when is_atom(App) ; is_list(App) -> call({dir,{priv_dir,App}}). -spec stick_dir(Directory :: file:filename()) -> 'ok' | 'error'. @@ -220,13 +223,14 @@ set_path(PathList) when is_list(PathList) -> call({set_path,PathList}). -spec get_path() -> [file:filename()]. get_path() -> call(get_path). --spec add_path(Directory :: file:filename()) -> 'true' | {'error', 'bad_directory'}. +-type add_path_ret() :: 'true' | {'error', 'bad_directory'}. +-spec add_path(Directory :: file:filename()) -> add_path_ret(). add_path(Dir) when is_list(Dir) -> call({add_path,last,Dir}). --spec add_pathz(Directory :: file:filename()) -> 'true' | {'error', 'bad_directory'}. +-spec add_pathz(Directory :: file:filename()) -> add_path_ret(). add_pathz(Dir) when is_list(Dir) -> call({add_path,last,Dir}). --spec add_patha(Directory :: file:filename()) -> 'true' | {'error', 'bad_directory'}. +-spec add_patha(Directory :: file:filename()) -> add_path_ret(). add_patha(Dir) when is_list(Dir) -> call({add_path,first,Dir}). -spec add_paths(Directories :: [file:filename()]) -> 'ok'. @@ -243,8 +247,8 @@ del_path(Name) when is_list(Name) ; is_atom(Name) -> call({del_path,Name}). -type replace_path_error() :: {'error', 'bad_directory' | 'bad_name' | {'badarg',_}}. -spec replace_path(Name:: atom(), Dir :: file:filename()) -> 'true' | replace_path_error(). -replace_path(Name, Dir) when (is_atom(Name) or is_list(Name)) and - (is_atom(Dir) or is_list(Dir)) -> +replace_path(Name, Dir) when (is_atom(Name) orelse is_list(Name)), + (is_atom(Dir) orelse is_list(Dir)) -> call({replace_path,Name,Dir}). -spec rehash() -> 'ok'. @@ -275,21 +279,14 @@ start_link(Flags) -> do_start(Flags) -> %% The following module_info/1 calls are here to ensure - %% that the modules are loaded prior to their use elsewhere in + %% that these modules are loaded prior to their use elsewhere in %% the code_server. %% Otherwise a deadlock may occur when the code_server is starting. - code_server:module_info(module), - packages:module_info(module), + code_server = code_server:module_info(module), + packages = packages:module_info(module), catch hipe_unified_loader:load_hipe_modules(), - gb_sets:module_info(module), - gb_trees:module_info(module), - - ets:module_info(module), - os:module_info(module), - binary:module_info(module), - unicode:module_info(module), - filename:module_info(module), - lists:module_info(module), + Modules2 = [gb_sets, gb_trees, ets, os, binary, unicode, filename, lists], + lists:foreach(fun (M) -> M = M:module_info(module) end, Modules2), Mode = get_mode(Flags), case init:get_argument(root) of @@ -297,7 +294,7 @@ do_start(Flags) -> Root = filename:join([Root0]), % Normalize. Use filename case code_server:start_link([Root,Mode]) of {ok,_Pid} = Ok2 -> - if + if Mode =:= interactive -> case lists:member(stick, Flags) of true -> do_stick_dirs(); @@ -306,14 +303,14 @@ do_start(Flags) -> true -> ok end, - % Quietly load the native code for all modules loaded so far. + %% Quietly load native code for all modules loaded so far catch load_native_code_for_all_loaded(), Ok2; Other -> Other end; Other -> - error_logger:error_msg("Can not start code server ~w ~n",[Other]), + error_logger:error_msg("Can not start code server ~w ~n", [Other]), {error, crash} end. @@ -330,7 +327,7 @@ do_s(Lib) -> %% The return value is intentionally ignored. Missing %% directories is not a fatal error. (In embedded systems, %% there is usually no compiler directory.) - stick_dir(filename:append(Dir, "ebin")), + _ = stick_dir(filename:append(Dir, "ebin")), ok end. @@ -428,7 +425,7 @@ where_is_file(Path, File) when is_list(Path), is_list(File) -> -spec set_primary_archive(ArchiveFile :: file:filename(), ArchiveBin :: binary(), - FileInfo :: #file_info{}) + FileInfo :: file:file_info()) -> 'ok' | {'error', atom()}. set_primary_archive(ArchiveFile0, ArchiveBin, #file_info{} = FileInfo) @@ -485,13 +482,13 @@ filter(Ext, _, {ok,Files}) -> filter2(Ext, length(Ext), Files). filter2(_Ext, _Extlen, []) -> []; -filter2(Ext, Extlen,[File|Tail]) -> - case has_ext(Ext,Extlen, File) of +filter2(Ext, Extlen, [File|Tail]) -> + case has_ext(Ext, Extlen, File) of true -> [File | filter2(Ext, Extlen, Tail)]; false -> filter2(Ext, Extlen, Tail) end. -has_ext(Ext, Extlen,File) -> +has_ext(Ext, Extlen, File) -> L = length(File), case catch lists:nthtail(L - Extlen, File) of Ext -> true; diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index f5e2820bbe..23db85e1f4 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -322,24 +322,19 @@ init({Name, LongOrShortNames, TickT}) -> process_flag(priority, max), Ticktime = to_integer(TickT), Ticker = spawn_link(net_kernel, ticker, [self(), Ticktime]), - case auth:get_cookie(Node) of - Cookie when is_atom(Cookie) -> - {ok, #state{name = Name, - node = Node, - type = LongOrShortNames, - tick = #tick{ticker = Ticker, time = Ticktime}, - connecttime = connecttime(), - connections = - ets:new(sys_dist,[named_table, - protected, - {keypos, 2}]), - listen = Listeners, - allowed = [], - verbose = 0 - }}; - _ELSE -> - {stop, {error,{bad_cookie, Node}}} - end; + {ok, #state{name = Name, + node = Node, + type = LongOrShortNames, + tick = #tick{ticker = Ticker, time = Ticktime}, + connecttime = connecttime(), + connections = + ets:new(sys_dist,[named_table, + protected, + {keypos, 2}]), + listen = Listeners, + allowed = [], + verbose = 0 + }}; Error -> {stop, Error} end. diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl index ce8c581e08..95a2f71ec0 100644 --- a/lib/kernel/src/os.erl +++ b/lib/kernel/src/os.erl @@ -231,9 +231,13 @@ start_port_srv(Request) -> catch error:_ -> false end, - start_port_srv_loop(Request, StayAlive). + start_port_srv_handle(Request), + case StayAlive of + true -> start_port_srv_loop(); + false -> exiting + end. -start_port_srv_loop({Ref,Client}, StayAlive) -> +start_port_srv_handle({Ref,Client}) -> Reply = try open_port({spawn, ?SHELL},[stream]) of Port when is_port(Port) -> (catch port_connect(Port, Client)), @@ -243,20 +247,18 @@ start_port_srv_loop({Ref,Client}, StayAlive) -> error:Reason -> {Reason,erlang:get_stacktrace()} end, - Client ! {Ref,Reply}, - case StayAlive of - true -> start_port_srv_loop(get_open_port_request(), true); - false -> exiting - end. + Client ! {Ref,Reply}. -get_open_port_request() -> + +start_port_srv_loop() -> receive {Ref, Client} = Request when is_reference(Ref), is_pid(Client) -> - Request; + start_port_srv_handle(Request); _Junk -> - get_open_port_request() - end. + ignore + end, + start_port_srv_loop(). %% %% unix_get_data(Port) -> Result diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index c8fe602ac2..d9abeb808b 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -180,34 +180,38 @@ t_fdopen(Config) when is_list(Config) -> %%% implicit inet6 option to api functions t_implicit_inet6(Config) when is_list(Config) -> - ?line Hostname = ok(inet:gethostname()), + ?line Host = ok(inet:gethostname()), + ?line + case inet:getaddr(Host, inet6) of + {ok,Addr} -> + ?line t_implicit_inet6(Host, Addr); + {error,Reason} -> + {skip, + "Can not look up IPv6 address: " + ++atom_to_list(Reason)} + end. + +t_implicit_inet6(Host, Addr) -> ?line case gen_tcp:listen(0, [inet6]) of {ok,S1} -> - ?line - case inet:getaddr(Hostname, inet6) of - {ok,Host} -> - ?line Loopback = {0,0,0,0,0,0,0,1}, - ?line io:format("~s ~p~n", ["Loopback",Loopback]), - ?line implicit_inet6(S1, Loopback), - ?line ok = gen_tcp:close(S1), - %% - ?line Localhost = - ok(inet:getaddr("localhost", inet6)), - ?line io:format("~s ~p~n", ["localhost",Localhost]), - ?line S2 = ok(gen_tcp:listen(0, [{ip,Localhost}])), - ?line implicit_inet6(S2, Localhost), - ?line ok = gen_tcp:close(S2), - %% - ?line io:format("~s ~p~n", [Hostname,Host]), - ?line S3 = ok(gen_tcp:listen(0, [{ifaddr,Host}])), - ?line implicit_inet6(S3, Host), - ?line ok = gen_tcp:close(S1); - {error,eafnosupport} -> - ?line ok = gen_tcp:close(S1), - {skip,"Can not look up IPv6 address"} - end; - _ -> + ?line Loopback = {0,0,0,0,0,0,0,1}, + ?line io:format("~s ~p~n", ["::1",Loopback]), + ?line implicit_inet6(S1, Loopback), + ?line ok = gen_tcp:close(S1), + %% + ?line Localhost = "localhost", + ?line Localaddr = ok(inet:getaddr(Localhost, inet6)), + ?line io:format("~s ~p~n", [Localhost,Localaddr]), + ?line S2 = ok(gen_tcp:listen(0, [{ip,Localaddr}])), + ?line implicit_inet6(S2, Localaddr), + ?line ok = gen_tcp:close(S2), + %% + ?line io:format("~s ~p~n", [Host,Addr]), + ?line S3 = ok(gen_tcp:listen(0, [{ifaddr,Addr}])), + ?line implicit_inet6(S3, Addr), + ?line ok = gen_tcp:close(S3); + {error,_} -> {skip,"IPv6 not supported"} end. diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index ee9288bc75..0ea2d53af0 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -450,36 +450,38 @@ connect(Config) when is_list(Config) -> ok. implicit_inet6(Config) when is_list(Config) -> - ?line Hostname = ok(inet:gethostname()), + ?line Host = ok(inet:gethostname()), + ?line + case inet:getaddr(Host, inet6) of + {ok,Addr} -> + ?line implicit_inet6(Host, Addr); + {error,Reason} -> + {skip, + "Can not look up IPv6 address: " + ++atom_to_list(Reason)} + end. + +implicit_inet6(Host, Addr) -> ?line Active = {active,false}, ?line case gen_udp:open(0, [inet6,Active]) of {ok,S1} -> - ?line - case inet:getaddr(Hostname, inet6) of - {ok,Host} -> - ?line Loopback = {0,0,0,0,0,0,0,1}, - ?line io:format("~s ~p~n", ["Loopback",Loopback]), - ?line implicit_inet6(S1, Active, Loopback), - ?line ok = gen_udp:close(S1), - %% - ?line Localhost = - ok(inet:getaddr("localhost", inet6)), - ?line io:format("~s ~p~n", ["localhost",Localhost]), - ?line S2 = - ok(gen_udp:open(0, [{ip,Localhost},Active])), - ?line implicit_inet6(S2, Active, Localhost), - ?line ok = gen_udp:close(S2), - %% - ?line io:format("~s ~p~n", [Hostname,Host]), - ?line S3 = - ok(gen_udp:open(0, [{ifaddr,Host},Active])), - ?line implicit_inet6(S3, Active, Host), - ?line ok = gen_udp:close(S1); - {error,eafnosupport} -> - ?line ok = gen_udp:close(S1), - {skip,"Can not look up IPv6 address"} - end; + ?line Loopback = {0,0,0,0,0,0,0,1}, + ?line io:format("~s ~p~n", ["::1",Loopback]), + ?line implicit_inet6(S1, Active, Loopback), + ?line ok = gen_udp:close(S1), + %% + ?line Localhost = "localhost", + ?line Localaddr = ok(inet:getaddr(Localhost, inet6)), + ?line io:format("~s ~p~n", [Localhost,Localaddr]), + ?line S2 = ok(gen_udp:open(0, [{ip,Localaddr},Active])), + ?line implicit_inet6(S2, Active, Localaddr), + ?line ok = gen_udp:close(S2), + %% + ?line io:format("~s ~p~n", [Host,Addr]), + ?line S3 = ok(gen_udp:open(0, [{ifaddr,Addr},Active])), + ?line implicit_inet6(S3, Active, Addr), + ?line ok = gen_udp:close(S3); _ -> {skip,"IPv6 not supported"} end. @@ -500,5 +502,4 @@ implicit_inet6(S1, Active, Addr) -> ?line {Addr,P2,"pong"} = ok(gen_udp:recv(S1, 1024)), ?line ok = gen_udp:close(S2). - ok({ok,V}) -> V. diff --git a/lib/megaco/Makefile b/lib/megaco/Makefile index d4698eb558..10efaf667f 100644 --- a/lib/megaco/Makefile +++ b/lib/megaco/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# Copyright Ericsson AB 1999-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -97,12 +97,19 @@ endif CONFIGURE_OPTS = $(FLEX_SCANNER_LINENO_ENABLER) $(FLEX_SCANNER_REENTRANT_ENABLER) +MEGACO_DIA_PLT = ./priv/megaco.plt +MEGACO_DIA_PLT_LOG = $(basename $(MEGACO_DIA_PLT)).dialyzer_plt_log +MEGACO_DIA_LOG = $(basename $(MEGACO_DIA_PLT)).dialyzer_log + # ---------------------------------------------------- # Default Subdir Targets # ---------------------------------------------------- include $(ERL_TOP)/make/otp_subdir.mk +.PHONY: reconf conf dconf econf configure setup info version \ + app_install dialyzer + reconf: (cd $(ERL_TOP) && \ ./otp_build autoconf && \ @@ -132,6 +139,10 @@ info: @echo "APP_TAR_FILE: $(APP_TAR_FILE)" @echo "OTP_INSTALL_DIR: $(OTP_INSTALL_DIR)" @echo "APP_INSTALL_DIR: $(APP_INSTALL_DIR)" + @echo "" + @echo "MEGACO_PLT = $(MEGACO_PLT)" + @echo "MEGACO_DIA_LOG = $(MEGACO_DIA_LOG)" + @echo "" version: @echo "$(VSN)" @@ -190,9 +201,18 @@ tar: $(APP_TAR_FILE) $(APP_TAR_FILE): $(APP_DIR) (cd $(APP_RELEASE_DIR); gtar zcf $(APP_TAR_FILE) $(DIR_NAME)) -dialyzer: - (cd ./ebin; \ - dialyzer --build_plt \ - --output_plt ../priv/megaco.plt \ - -r ../../megaco/ebin \ - --verbose) +dialyzer_plt: $(MEGACO_DIA_PLT) + +$(MEGACO_DIA_PLT): + @echo "Building megaco plt file" + @dialyzer --build_plt \ + --output_plt $@ \ + -r ../megaco/ebin \ + -o $(MEGACO_DIA_PLT_LOG) \ + --verbose + +dialyzer: $(MEGACO_DIA_PLT) + (dialyzer --plt $< \ + -o $(MEGACO_DIA_LOG) \ + ../megaco/ebin \ + && (shell cat $(MEGACO_DIA_LOG))) diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml index 81c9305542..4f678a2a1b 100644 --- a/lib/megaco/doc/src/notes.xml +++ b/lib/megaco/doc/src/notes.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> <header> <copyright> - <year>2000</year><year>2010</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -35,22 +35,90 @@ thus constitutes one section in this document. The title of each section is the version number of Megaco.</p> + + <section><title>Megaco 3.15.1</title> + + <p>Version 3.15.1 supports code replacement in runtime from/to + version 3.15, 3.14.1.1, 3.14.1 and 3.14.</p> + + <section> + <title>Improvements and new features</title> + + <p>-</p> + +<!-- + <list type="bulleted"> + <item> + <p>Updated the + <seealso marker="megaco_performance">performance</seealso> + chapter. </p> + <p>Own Id: OTP-8696</p> + </item> + + </list> +--> + + </section> + + <section> + <title>Fixed bugs and malfunctions</title> + +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>Fixing miscellaneous things detected by dialyzer. </p> + <p>Own Id: OTP-9075</p> + <!-- <p>Aux Id: Seq 11579</p> --> + </item> + + </list> + + </section> + + </section> <!-- 3.15.1 --> + + <section><title>Megaco 3.15</title> <section><title>Improvements and New Features</title> - <list> + +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>Fixing auto-import issues.</p> + <p>Own Id: OTP-8842</p> + </item> + </list> + </section> + + <section> + <title>Fixed bugs and malfunctions</title> + <p>-</p> + +<!-- + <list type="bulleted"> <item> - <p> - Fixing auto-import issues.</p> - <p> - Own Id: OTP-8842</p> + <p>Eliminated a possible race condition while creating + pending counters. </p> + <p>Own Id: OTP-8634</p> + <p>Aux Id: Seq 11579</p> </item> + </list> +--> + </section> -</section> + </section> <!-- 3.15 --> -<section> + + <section> <title>Megaco 3.14.1.1</title> <p>Version 3.14.1.1 supports code replacement in runtime from/to diff --git a/lib/megaco/src/app/megaco.app.src b/lib/megaco/src/app/megaco.app.src index 503fcd7176..c0d8218ac8 100644 --- a/lib/megaco/src/app/megaco.app.src +++ b/lib/megaco/src/app/megaco.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -67,6 +67,7 @@ megaco_compact_text_encoder_prev3c, megaco_compact_text_encoder_v3, megaco_config, + megaco_config_misc, megaco_digit_map, megaco_encoder, megaco_edist_compress, diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src index 66068f650f..01b070d79f 100644 --- a/lib/megaco/src/app/megaco.appup.src +++ b/lib/megaco/src/app/megaco.appup.src @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -133,50 +133,34 @@ %% | %% v %% 3.15 +%% | +%% v +%% 3.15.1 %% %% {"%VSN%", [ - {"3.14.1.1", + {"3.15", [ - {load_module, megaco_binary_transformer_prev3a, soft_purge, soft_purge, []}, - {load_module, megaco_binary_transformer_prev3b, soft_purge, soft_purge, []}, - {load_module, megaco_binary_transformer_prev3c, soft_purge, soft_purge, []}, + {load_module, megaco_flex_scanner, soft_purge, soft_purge, []}, {load_module, megaco_sdp, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_v1, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_v1, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_v2, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_v2, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_prev3a, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_prev3a, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_prev3b, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_prev3b, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_prev3c, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_prev3c, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_v3, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_v3, soft_purge, soft_purge, []} + {load_module, megaco_filter, soft_purge, soft_purge, []}, + {load_module, megaco_timer, soft_purge, soft_purge, [megaco_config_misc]}, + {update, megaco_config, soft, soft_purge, soft_purge, + [megaco_timer, megaco_config_misc]}, + {add_module, megaco_config_misc} ] } ], [ - {"3.14.1.1", + {"3.15", [ - {load_module, megaco_binary_transformer_prev3a, soft_purge, soft_purge, []}, - {load_module, megaco_binary_transformer_prev3b, soft_purge, soft_purge, []}, - {load_module, megaco_binary_transformer_prev3c, soft_purge, soft_purge, []}, + {load_module, megaco_flex_scanner, soft_purge, soft_purge, []}, {load_module, megaco_sdp, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_v1, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_v1, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_v2, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_v2, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_prev3a, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_prev3a, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_prev3b, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_prev3b, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_prev3c, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_prev3c, soft_purge, soft_purge, []}, - {load_module, megaco_compact_text_encoder_v3, soft_purge, soft_purge, []}, - {load_module, megaco_pretty_text_encoder_v3, soft_purge, soft_purge, []} + {load_module, megaco_filter, soft_purge, soft_purge, []}, + {load_module, megaco_timer, soft_purge, soft_purge, [megaco_config]}, + {update, megaco_config, soft, soft_purge, soft_purge, []}, + {remove, {megaco_config_misc, soft_purge, brutal_purge}} ] } ] diff --git a/lib/megaco/src/binary/megaco_binary_encoder_lib.erl b/lib/megaco/src/binary/megaco_binary_encoder_lib.erl index 842d6b70d1..967ee93935 100644 --- a/lib/megaco/src/binary/megaco_binary_encoder_lib.erl +++ b/lib/megaco/src/binary/megaco_binary_encoder_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -134,6 +134,12 @@ encode_transaction(EC, {Tag, _} = Trans, AsnMod, TransMod, Type) encode_transaction(_EC, T, _AsnMod, _TransMod, _Type) -> {error, {no_megaco_transaction, T}}. +-spec do_encode_transaction(EC :: list(), + Trans :: tuple(), + AnsMod :: atom(), + TransMod :: atom(), + Type :: atom()) -> + {'ok', binary()} | {'error', any()}. do_encode_transaction([native], _Trans, _AsnMod, _TransMod, binary) -> %% asn1rt:encode(AsnMod, element(1, T), T); {error, not_implemented}; @@ -160,6 +166,12 @@ do_encode_transaction(EC, _Trans, _AsnMod, _TransMod, _Type) -> %% Convert a list of ActionRequest record's into a binary %% Return {ok, DeepIoList} | {error, Reason} %%---------------------------------------------------------------------- +-spec encode_action_requests(EC :: list(), + ARs :: list(), + AnsMod :: atom(), + TransMod :: atom(), + Type :: atom()) -> + {'ok', binary()} | {'error', any()}. encode_action_requests([native], _ARs, _AsnMod, _TransMod, binary) -> %% asn1rt:encode(AsnMod, element(1, T), T); {error, not_implemented}; @@ -183,13 +195,20 @@ encode_action_requests(EC, _ARs, _AsnMod, _TransMod, _Type) -> %% Convert a ActionRequest record into a binary %% Return {ok, DeepIoList} | {error, Reason} %%---------------------------------------------------------------------- -encode_action_request([native], _ARs, _AsnMod, _TransMod, binary) -> + +-spec encode_action_request(EC :: list(), + AR :: tuple(), + AnsMod :: atom(), + TransMod :: atom(), + Type :: atom()) -> + {'ok', binary()} | {'error', any()}. +encode_action_request([native], _AR, _AsnMod, _TransMod, binary) -> %% asn1rt:encode(AsnMod, element(1, T), T); {error, not_implemented}; -encode_action_request(_EC, _ARs0, _AsnMod, _TransMod, binary) -> +encode_action_request(_EC, _AR, _AsnMod, _TransMod, binary) -> {error, not_implemented}; -encode_action_request(EC, ARs, AsnMod, TransMod, io_list) -> - case encode_action_request(EC, ARs, AsnMod, TransMod, binary) of +encode_action_request(EC, AR, AsnMod, TransMod, io_list) -> + case encode_action_request(EC, AR, AsnMod, TransMod, binary) of {ok, Bin} when is_binary(Bin) -> {ok, Bin}; {ok, DeepIoList} -> @@ -198,7 +217,7 @@ encode_action_request(EC, ARs, AsnMod, TransMod, io_list) -> {error, Reason} -> {error, Reason} end; -encode_action_request(EC, _ARs, _AsnMod, _TransMod, _Type) -> +encode_action_request(EC, _AR, _AsnMod, _TransMod, _Type) -> {error, {bad_encoding_config, EC}}. diff --git a/lib/megaco/src/engine/depend.mk b/lib/megaco/src/engine/depend.mk index 8d8c83e923..935eb813e5 100644 --- a/lib/megaco/src/engine/depend.mk +++ b/lib/megaco/src/engine/depend.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# Copyright Ericsson AB 2003-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -17,6 +17,8 @@ # # %CopyrightEnd% +$(EBIN)/megaco_config_misc.$(EMULATOR): megaco_config_misc.erl + $(EBIN)/megaco_config.$(EMULATOR): megaco_config.erl \ ../../include/megaco.hrl \ ../app/megaco_internal.hrl diff --git a/lib/megaco/src/engine/megaco_config.erl b/lib/megaco/src/engine/megaco_config.erl index 6805db790d..b65ddbe232 100644 --- a/lib/megaco/src/engine/megaco_config.erl +++ b/lib/megaco/src/engine/megaco_config.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% Copyright Ericsson AB 2000-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -46,10 +46,10 @@ %% Verification functions verify_val/2, - verify_strict_uint/1, - verify_strict_int/1, verify_strict_int/2, - verify_uint/1, - verify_int/1, verify_int/2, +%% verify_strict_uint/1, +%% verify_strict_int/1, verify_strict_int/2, +%% verify_uint/1, +%% verify_int/1, verify_int/2, %% Reply limit counter @@ -1501,28 +1501,37 @@ verify_val(Item, Val) -> mid -> true; local_mid -> true; remote_mid -> true; - min_trans_id -> verify_strict_uint(Val, 4294967295); % uint32 - max_trans_id -> verify_uint(Val, 4294967295); % uint32 + min_trans_id -> + megaco_config_misc:verify_strict_uint(Val, 4294967295); % uint32 + max_trans_id -> + megaco_config_misc:verify_uint(Val, 4294967295); % uint32 request_timer -> verify_timer(Val); long_request_timer -> verify_timer(Val); - auto_ack -> verify_bool(Val); + auto_ack -> + megaco_config_misc:verify_bool(Val); - trans_ack -> verify_bool(Val); - trans_ack_maxcount -> verify_uint(Val); + trans_ack -> + megaco_config_misc:verify_bool(Val); + trans_ack_maxcount -> + megaco_config_misc:verify_uint(Val); - trans_req -> verify_bool(Val); - trans_req_maxcount -> verify_uint(Val); - trans_req_maxsize -> verify_uint(Val); + trans_req -> + megaco_config_misc:verify_bool(Val); + trans_req_maxcount -> + megaco_config_misc:verify_uint(Val); + trans_req_maxsize -> + megaco_config_misc:verify_uint(Val); - trans_timer -> verify_timer(Val) and (Val >= 0); - trans_sender when Val == undefined -> true; + trans_timer -> + verify_timer(Val) and (Val >= 0); + trans_sender when Val =:= undefined -> true; pending_timer -> verify_timer(Val); - sent_pending_limit -> verify_uint(Val) andalso - (Val > 0); - recv_pending_limit -> verify_uint(Val) andalso - (Val > 0); + sent_pending_limit -> + megaco_config_misc:verify_uint(Val) andalso (Val > 0); + recv_pending_limit -> + megaco_config_misc:verify_uint(Val) andalso (Val > 0); reply_timer -> verify_timer(Val); control_pid when is_pid(Val) -> true; monitor_ref -> true; % Internal usage only @@ -1530,110 +1539,43 @@ verify_val(Item, Val) -> send_handle -> true; encoding_mod when is_atom(Val) -> true; encoding_config when is_list(Val) -> true; - protocol_version -> verify_strict_uint(Val); + protocol_version -> + megaco_config_misc:verify_strict_uint(Val); auth_data -> true; user_mod when is_atom(Val) -> true; user_args when is_list(Val) -> true; reply_data -> true; - threaded -> verify_bool(Val); - strict_version -> verify_bool(Val); - long_request_resend -> verify_bool(Val); - call_proxy_gc_timeout -> verify_strict_uint(Val); - cancel -> verify_bool(Val); + threaded -> + megaco_config_misc:verify_bool(Val); + strict_version -> + megaco_config_misc:verify_bool(Val); + long_request_resend -> + megaco_config_misc:verify_bool(Val); + call_proxy_gc_timeout -> + megaco_config_misc:verify_strict_uint(Val); + cancel -> + megaco_config_misc:verify_bool(Val); resend_indication -> verify_resend_indication(Val); - segment_reply_ind -> verify_bool(Val); - segment_recv_acc -> verify_bool(Val); + segment_reply_ind -> + megaco_config_misc:verify_bool(Val); + segment_recv_acc -> + megaco_config_misc:verify_bool(Val); segment_recv_timer -> verify_timer(Val); segment_send -> verify_segmentation_window(Val); segment_send_timer -> verify_timer(Val); - max_pdu_size -> verify_int(Val) andalso (Val > 0); + max_pdu_size -> + megaco_config_misc:verify_int(Val) andalso (Val > 0); request_keep_alive_timeout -> - (verify_uint(Val) orelse (Val =:= plain)); + (megaco_config_misc:verify_uint(Val) orelse (Val =:= plain)); _ -> false end. -verify_bool(true) -> true; -verify_bool(false) -> true; -verify_bool(_) -> false. - verify_resend_indication(flag) -> true; -verify_resend_indication(Val) -> verify_bool(Val). - --spec verify_strict_int(Int :: integer()) -> boolean(). -verify_strict_int(Int) when is_integer(Int) -> true; -verify_strict_int(_) -> false. - --spec verify_strict_int(Int :: integer(), - Max :: integer() | 'infinity') -> boolean(). -verify_strict_int(Int, infinity) -> - verify_strict_int(Int); -verify_strict_int(Int, Max) -> - verify_strict_int(Int) andalso verify_strict_int(Max) andalso (Int =< Max). - --spec verify_strict_uint(Int :: non_neg_integer()) -> boolean(). -verify_strict_uint(Int) when is_integer(Int) andalso (Int >= 0) -> true; -verify_strict_uint(_) -> false. - --spec verify_strict_uint(Int :: non_neg_integer(), - Max :: non_neg_integer() | 'infinity') -> boolean(). -verify_strict_uint(Int, infinity) -> - verify_strict_uint(Int); -verify_strict_uint(Int, Max) -> - verify_strict_int(Int, 0, Max). - --spec verify_uint(Val :: non_neg_integer() | 'infinity') -> boolean(). -verify_uint(infinity) -> true; -verify_uint(Val) -> verify_strict_uint(Val). - --spec verify_int(Val :: integer() | 'infinity') -> boolean(). -verify_int(infinity) -> true; -verify_int(Val) -> verify_strict_int(Val). - --spec verify_int(Int :: integer() | 'infinity', - Max :: integer() | 'infinity') -> boolean(). -verify_int(Int, infinity) -> - verify_int(Int); -verify_int(infinity, _Max) -> - true; -verify_int(Int, Max) -> - verify_strict_int(Int) andalso verify_strict_int(Max) andalso (Int =< Max). - --spec verify_uint(Int :: non_neg_integer() | 'infinity', - Max :: non_neg_integer() | 'infinity') -> boolean(). -verify_uint(Int, infinity) -> - verify_uint(Int); -verify_uint(infinity, _Max) -> - true; -verify_uint(Int, Max) -> - verify_strict_int(Int, 0, Max). - --spec verify_strict_int(Int :: integer(), - Min :: integer(), - Max :: integer()) -> boolean(). -verify_strict_int(Val, Min, Max) - when (is_integer(Val) andalso - is_integer(Min) andalso - is_integer(Max) andalso - (Val >= Min) andalso - (Val =< Max)) -> - true; -verify_strict_int(_Val, _Min, _Max) -> - false. - --spec verify_int(Val :: integer() | 'infinity', - Min :: integer(), - Max :: integer() | 'infinity') -> boolean(). -verify_int(infinity, Min, infinity) -> - verify_strict_int(Min); -verify_int(Val, Min, infinity) -> - verify_strict_int(Val) andalso - verify_strict_int(Min) andalso (Val >= Min); -verify_int(Int, Min, Max) -> - verify_strict_int(Int, Min, Max). +verify_resend_indication(Val) -> megaco_config_misc:verify_bool(Val). verify_timer(Timer) -> megaco_timer:verify(Timer). @@ -1641,7 +1583,7 @@ verify_timer(Timer) -> verify_segmentation_window(none) -> true; verify_segmentation_window(K) -> - verify_int(K, 1, infinity). + megaco_config_misc:verify_int(K, 1, infinity). handle_stop_user(UserMid) -> case catch user_info(UserMid, mid) of diff --git a/lib/megaco/src/engine/megaco_config_misc.erl b/lib/megaco/src/engine/megaco_config_misc.erl new file mode 100644 index 0000000000..0a1601c766 --- /dev/null +++ b/lib/megaco/src/engine/megaco_config_misc.erl @@ -0,0 +1,113 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Utility module for megaco_config +%%---------------------------------------------------------------------- +%% + +-module(megaco_config_misc). + +%% Application internal exports +-export([ + verify_bool/1, + + verify_int/1, verify_int/2, verify_int/3, + verify_strict_int/1, verify_strict_int/2, verify_strict_int/3, + + verify_uint/1, verify_uint/2, + verify_strict_uint/1, verify_strict_uint/2 + ]). + + +%%%---------------------------------------------------------------------- +%%% API +%%%---------------------------------------------------------------------- + +verify_bool(true) -> true; +verify_bool(false) -> true; +verify_bool(_) -> false. + + +%% verify_int(Val) -> boolean() +verify_int(infinity) -> true; +verify_int(Val) -> verify_strict_int(Val). + +%% verify_int(Val, Max) -> boolean() +verify_int(Int, infinity) -> + verify_int(Int); +verify_int(infinity, _Max) -> + true; +verify_int(Int, Max) -> + verify_strict_int(Int) andalso verify_strict_int(Max) andalso (Int =< Max). + +%% verify_int(Val, Min, Max) -> boolean() +verify_int(infinity, Min, infinity) -> + verify_strict_int(Min); +verify_int(Val, Min, infinity) -> + verify_strict_int(Val) andalso + verify_strict_int(Min) andalso (Val >= Min); +verify_int(Int, Min, Max) -> + verify_strict_int(Int, Min, Max). + +%% verify_strict_int(Val) -> boolean() +verify_strict_int(Int) when is_integer(Int) -> true; +verify_strict_int(_) -> false. + +%% verify_strict_int(Val, Max) -> boolean() +verify_strict_int(Int, infinity) -> + verify_strict_int(Int); +verify_strict_int(Int, Max) -> + verify_strict_int(Int) andalso verify_strict_int(Max) andalso (Int =< Max). + +%% verify_strict_int(Val, Min, Max) -> boolean() +verify_strict_int(Val, Min, Max) + when (is_integer(Val) andalso + is_integer(Min) andalso + is_integer(Max) andalso + (Val >= Min) andalso + (Val =< Max)) -> + true; +verify_strict_int(_Val, _Min, _Max) -> + false. + + +%% verify_uint(Val) -> boolean() +verify_uint(infinity) -> true; +verify_uint(Val) -> verify_strict_uint(Val). + +%% verify_uint(Val, Max) -> boolean() +verify_uint(Int, infinity) -> + verify_uint(Int); +verify_uint(infinity, _Max) -> + true; +verify_uint(Int, Max) -> + verify_strict_int(Int, 0, Max). + +%% verify_strict_uint(Val) -> boolean() +verify_strict_uint(Int) when is_integer(Int) andalso (Int >= 0) -> true; +verify_strict_uint(_) -> false. + +%% verify_strict_uint(Val, Max) -> boolean() +verify_strict_uint(Int, infinity) -> + verify_strict_uint(Int); +verify_strict_uint(Int, Max) -> + verify_strict_int(Int, 0, Max). + diff --git a/lib/megaco/src/engine/megaco_filter.erl b/lib/megaco/src/engine/megaco_filter.erl index 9df752789c..fb0c700a82 100644 --- a/lib/megaco/src/engine/megaco_filter.erl +++ b/lib/megaco/src/engine/megaco_filter.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% Copyright Ericsson AB 2000-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,6 +21,7 @@ %%---------------------------------------------------------------------- %% Purpose : Megaco/H.248 customization of the Event Tracer tool %%---------------------------------------------------------------------- +%% -module(megaco_filter). @@ -33,6 +34,7 @@ -include_lib("megaco/src/app/megaco_internal.hrl"). -include_lib("et/include/et.hrl"). + %%---------------------------------------------------------------------- %% BUGBUG: There are some opportunities for improvements: %% @@ -43,7 +45,8 @@ %% records that already are defined in megaco_message_{v1,v2,v3}.hrl. %% * The records megaco_udp and megaco_tcp are copied from the files %% megaco_udp.hrl and megaco_tcp.hrl respectively, as we cannot include -%% both header files. They both defines the macros HEAP_SIZE and GC_MSG_LIMIT. +%% both header files. +%% They both defines the macros HEAP_SIZE and GC_MSG_LIMIT. %%-include("megaco_message_internal.hrl"). -record('megaco_transaction_reply', @@ -76,6 +79,8 @@ module = megaco, serialize = false % false: Spawn a new process for each message }). + + %%---------------------------------------------------------------------- start() -> @@ -360,28 +365,24 @@ pretty(_ConnData, MegaMsg) when is_record(MegaMsg, 'MegacoMessage') -> {ok, Bin} = megaco_pretty_text_encoder:encode_message([], MegaMsg), term_to_string(Bin); pretty(_ConnData, CmdReq) when is_record(CmdReq, 'CommandRequest') -> - {ok, IoList} = megaco_pretty_text_encoder:encode_command_request(CmdReq), - term_to_string(lists:flatten(IoList)); + {ok, Bin} = megaco_pretty_text_encoder:encode_command_request(CmdReq), + term_to_string(Bin); pretty(_ConnData, {complete_success, ContextId, RepList}) -> ActRep = #'ActionReply'{contextId = ContextId, commandReply = RepList}, - {ok, IoList} = megaco_pretty_text_encoder:encode_action_reply(ActRep), - term_to_string(lists:flatten(IoList)); + {ok, Bin} = megaco_pretty_text_encoder:encode_action_reply(ActRep), + term_to_string(Bin); pretty(_ConnData, AR) when is_record(AR, 'ActionReply') -> - {ok, IoList} = megaco_pretty_text_encoder:encode_action_reply(AR), - term_to_string(lists:flatten(IoList)); + {ok, Bin} = megaco_pretty_text_encoder:encode_action_reply(AR), + term_to_string(Bin); pretty(_ConnData, {partial_failure, ContextId, RepList}) -> ActRep = #'ActionReply'{contextId = ContextId, commandReply = RepList}, - {ok, IoList} = megaco_pretty_text_encoder:encode_action_reply(ActRep), - term_to_string(lists:flatten(IoList)); + {ok, Bin} = megaco_pretty_text_encoder:encode_action_reply(ActRep), + term_to_string(Bin); pretty(_ConnData, {trans, Trans}) -> - case megaco_pretty_text_encoder:encode_transaction(Trans) of - {ok, Bin} when is_binary(Bin) -> - term_to_string(binary_to_list(Bin)); - {ok, IoList} -> - term_to_string(lists:flatten(IoList)) - end; + {ok, Bin} = megaco_pretty_text_encoder:encode_transaction(Trans), + term_to_string(Bin); pretty(__ConnData, Other) -> term_to_string(Other). diff --git a/lib/megaco/src/engine/megaco_sdp.erl b/lib/megaco/src/engine/megaco_sdp.erl index 37f28cac59..96732584fb 100644 --- a/lib/megaco/src/engine/megaco_sdp.erl +++ b/lib/megaco/src/engine/megaco_sdp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -877,9 +877,7 @@ decode_bandwidth_bwt("CT") -> decode_bandwidth_bwt("AS") -> as; decode_bandwidth_bwt(BwType) when is_list(BwType) -> - BwType; -decode_bandwidth_bwt(BadBwType) -> - error({invalid_bandwidth_bwtype, BadBwType}). + BwType. encode_bandwidth_bwt(ct) -> "CT"; diff --git a/lib/megaco/src/engine/megaco_timer.erl b/lib/megaco/src/engine/megaco_timer.erl index 9f524523a8..1336be0b5b 100644 --- a/lib/megaco/src/engine/megaco_timer.erl +++ b/lib/megaco/src/engine/megaco_timer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -42,7 +42,7 @@ %% NewTimer = megaco_timer() %% TimeoutTime = infinity | integer() %% -init(SingleWaitFor) when SingleWaitFor == infinity -> +init(SingleWaitFor) when SingleWaitFor =:= infinity -> {SingleWaitFor, timeout}; init(SingleWaitFor) when is_integer(SingleWaitFor) and (SingleWaitFor >= 0) -> {SingleWaitFor, timeout}; @@ -76,17 +76,17 @@ verify(#megaco_incr_timer{wait_for = WaitFor, factor = Factor, incr = Incr, max_retries = MaxRetries}) -> - (megaco_config:verify_strict_uint(WaitFor) and - megaco_config:verify_strict_uint(Factor) and - megaco_config:verify_strict_int(Incr) and + (megaco_config_misc:verify_strict_uint(WaitFor) and + megaco_config_misc:verify_strict_uint(Factor) and + megaco_config_misc:verify_strict_int(Incr) and verify_max_retries(MaxRetries)); verify(Timer) -> - megaco_config:verify_uint(Timer). + megaco_config_misc:verify_uint(Timer). verify_max_retries(infinity_restartable) -> true; verify_max_retries(Val) -> - megaco_config:verify_uint(Val). + megaco_config_misc:verify_uint(Val). %%----------------------------------------------------------------- diff --git a/lib/megaco/src/engine/modules.mk b/lib/megaco/src/engine/modules.mk index 44bcadc37b..4bc57cd63e 100644 --- a/lib/megaco/src/engine/modules.mk +++ b/lib/megaco/src/engine/modules.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# Copyright Ericsson AB 2001-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -24,6 +24,7 @@ BEHAVIOUR_MODULES = \ MODULES = \ $(BEHAVIOUR_MODULES) \ + megaco_config_misc \ megaco_config \ megaco_digit_map \ megaco_erl_dist_encoder \ diff --git a/lib/megaco/src/flex/megaco_flex_scanner.erl b/lib/megaco/src/flex/megaco_flex_scanner.erl index e471412c13..508f8905e7 100644 --- a/lib/megaco/src/flex/megaco_flex_scanner.erl +++ b/lib/megaco/src/flex/megaco_flex_scanner.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,21 +30,11 @@ -define(SCHED_ID(), erlang:system_info(scheduler_id)). -define(SMP_SUPPORT_DEFAULT(), erlang:system_info(smp_support)). -is_enabled() -> - case ?ENABLE_MEGACO_FLEX_SCANNER of - true -> - true; - _ -> - false - end. +is_enabled() -> + (true =:= ?ENABLE_MEGACO_FLEX_SCANNER). is_reentrant_enabled() -> - case ?MEGACO_REENTRANT_FLEX_SCANNER of - true -> - true; - _ -> - false - end. + (true =:= ?MEGACO_REENTRANT_FLEX_SCANNER). is_scanner_port(Port, Port) when is_port(Port) -> true; diff --git a/lib/megaco/test/megaco_SUITE.erl b/lib/megaco/test/megaco_SUITE.erl index 4faa6736e6..007677ba4d 100644 --- a/lib/megaco/test/megaco_SUITE.erl +++ b/lib/megaco/test/megaco_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% Copyright Ericsson AB 2000-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -46,42 +46,53 @@ init() -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Top test case -suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,1}]}]}]. +suite() -> [{ct_hooks, [{ts_install_cth, [{nodenames,1}]}]}]. all() -> - [{group, app_test}, {group, appup_test}, - {group, config}, {group, flex}, {group, udp}, - {group, tcp}, {group, examples}, {group, digit_map}, - {group, mess}, {group, measure}, - {group, binary_term_id}, {group, codec}, {group, sdp}, - {group, mib}, {group, trans}, {group, actions}, - {group, load}, {group, pending_limit}, - {group, segmented}, {group, timer}]. + [{group, app_test}, + {group, appup_test}, + {group, config}, + {group, flex}, + {group, udp}, + {group, tcp}, + {group, examples}, + {group, digit_map}, + {group, mess}, + {group, measure}, + {group, binary_term_id}, + {group, codec}, + {group, sdp}, + {group, mib}, + {group, trans}, + {group, actions}, + {group, load}, + {group, pending_limit}, + {group, segmented}, + {group, timer}]. groups() -> - [{tickets, [], [{group, mess}, {group, codec}]}, - {app_test, [], [{megaco_app_test, all}]}, - {appup_test, [], [{megaco_appup_test, all}]}, - {config, [], [{megaco_config_test, all}]}, - {call_flow, [], [{megaco_call_flow_test, all}]}, - {digit_map, [], [{megaco_digit_map_test, all}]}, - {mess, [], [{megaco_mess_test, all}]}, - {udp, [], [{megaco_udp_test, all}]}, - {tcp, [], [{megaco_tcp_test, all}]}, - {examples, [], [{megaco_examples_test, all}]}, - {measure, [], [{megaco_measure_test, all}]}, - {binary_term_id, [], - [{megaco_binary_term_id_test, all}]}, - {codec, [], [{megaco_codec_test, all}]}, - {sdp, [], [{megaco_sdp_test, all}]}, - {mib, [], [{megaco_mib_test, all}]}, - {trans, [], [{megaco_trans_test, all}]}, - {actions, [], [{megaco_actions_test, all}]}, - {load, [], [{megaco_load_test, all}]}, - {pending_limit, [], [{megaco_pending_limit_test, all}]}, - {segmented, [], [{megaco_segment_test, all}]}, - {timer, [], [{megaco_timer_test, all}]}, - {flex, [], [{megaco_flex_test, all}]}]. + [{tickets, [], [{group, mess}, {group, codec}]}, + {app_test, [], [{megaco_app_test, all}]}, + {appup_test, [], [{megaco_appup_test, all}]}, + {config, [], [{megaco_config_test, all}]}, + {call_flow, [], [{megaco_call_flow_test, all}]}, + {digit_map, [], [{megaco_digit_map_test, all}]}, + {mess, [], [{megaco_mess_test, all}]}, + {udp, [], [{megaco_udp_test, all}]}, + {tcp, [], [{megaco_tcp_test, all}]}, + {examples, [], [{megaco_examples_test, all}]}, + {measure, [], [{megaco_measure_test, all}]}, + {binary_term_id, [], [{megaco_binary_term_id_test, all}]}, + {codec, [], [{megaco_codec_test, all}]}, + {sdp, [], [{megaco_sdp_test, all}]}, + {mib, [], [{megaco_mib_test, all}]}, + {trans, [], [{megaco_trans_test, all}]}, + {actions, [], [{megaco_actions_test, all}]}, + {load, [], [{megaco_load_test, all}]}, + {pending_limit, [], [{megaco_pending_limit_test, all}]}, + {segmented, [], [{megaco_segment_test, all}]}, + {timer, [], [{megaco_timer_test, all}]}, + {flex, [], [{megaco_flex_test, all}]}]. init_per_suite(Config) -> Config. diff --git a/lib/megaco/test/megaco_app_test.erl b/lib/megaco/test/megaco_app_test.erl index 0bfa388ef6..00f7b7fb68 100644 --- a/lib/megaco/test/megaco_app_test.erl +++ b/lib/megaco/test/megaco_app_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% Copyright Ericsson AB 2002-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -42,11 +42,17 @@ init_per_testcase(Case, Config) -> end_per_testcase(Case, Config) -> megaco_test_lib:end_per_testcase(Case, Config). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% all() -> - [fields, modules, exportall, app_depend, - undef_funcs]. + [ + fields, + modules, + exportall, + app_depend, + undef_funcs + ]. groups() -> []. @@ -112,7 +118,7 @@ fields(doc) -> []; fields(Config) when is_list(Config) -> AppFile = key1search(app_file, Config), - Fields = [vsn, description, modules, registered, applications], + Fields = [vsn, description, modules, registered, applications], case check_fields(Fields, AppFile, []) of [] -> ok; diff --git a/lib/megaco/test/megaco_appup_test.erl b/lib/megaco/test/megaco_appup_test.erl index a49ab0a968..40eebcae86 100644 --- a/lib/megaco/test/megaco_appup_test.erl +++ b/lib/megaco/test/megaco_appup_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% Copyright Ericsson AB 2002-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -24,6 +24,7 @@ -module(megaco_appup_test). -compile(export_all). +-compile({no_auto_import,[error/1]}). -include("megaco_test_lib.hrl"). diff --git a/lib/megaco/test/megaco_codec_v1_test.erl b/lib/megaco/test/megaco_codec_v1_test.erl index 7068d005da..3a548c4d9e 100644 --- a/lib/megaco/test/megaco_codec_v1_test.erl +++ b/lib/megaco/test/megaco_codec_v1_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,6 +26,10 @@ %% ---- +-compile({no_auto_import,[error/1]}). + +%% ---- + -include_lib("megaco/include/megaco.hrl"). -include_lib("megaco/include/megaco_message_v1.hrl"). -include("megaco_test_lib.hrl"). @@ -458,76 +462,122 @@ end_per_testcase(Case, Config) -> %% Top test case all() -> - [{group, text}, {group, binary}, {group, erl_dist}, - {group, tickets}]. + [ + {group, text}, + {group, binary}, + {group, erl_dist}, + {group, tickets} + ]. groups() -> - [{text, [], - [{group, pretty}, {group, flex_pretty}, - {group, compact}, {group, flex_compact}]}, - {binary, [], - [{group, bin}, {group, ber}, {group, ber_bin}, - {group, per}, {group, per_bin}]}, - {erl_dist, [], [{group, erl_dist_m}]}, - {pretty, [], [pretty_test_msgs]}, - {compact, [], [compact_test_msgs]}, - {flex_pretty, [], flex_pretty_cases()}, - {flex_compact, [], flex_compact_cases()}, - {bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]}, - {ber_bin, [], [ber_bin_test_msgs]}, - {per, [], [per_test_msgs]}, - {per_bin, [], [per_bin_test_msgs]}, - {erl_dist_m, [], [erl_dist_m_test_msgs]}, - {tickets, [], - [{group, compact_tickets}, {group, pretty_tickets}, - {group, flex_compact_tickets}, - {group, flex_pretty_tickets}]}, - {compact_tickets, [], - [compact_otp4011_msg1, compact_otp4011_msg2, - compact_otp4011_msg3, compact_otp4013_msg1, - compact_otp4085_msg1, compact_otp4085_msg2, - compact_otp4280_msg1, compact_otp4299_msg1, - compact_otp4299_msg2, compact_otp4359_msg1, - compact_otp4920_msg0, compact_otp4920_msg1, - compact_otp4920_msg2, compact_otp4920_msg3, - compact_otp4920_msg4, compact_otp4920_msg5, - compact_otp4920_msg6, compact_otp4920_msg7, - compact_otp4920_msg8, compact_otp4920_msg9, - compact_otp4920_msg10, compact_otp4920_msg11, - compact_otp4920_msg12, compact_otp4920_msg20, - compact_otp4920_msg21, compact_otp4920_msg22, - compact_otp4920_msg23, compact_otp4920_msg24, - compact_otp4920_msg25, compact_otp5186_msg01, - compact_otp5186_msg02, compact_otp5186_msg03, - compact_otp5186_msg04, compact_otp5186_msg05, - compact_otp5186_msg06, compact_otp5793_msg01, - compact_otp5993_msg01, compact_otp5993_msg02, - compact_otp5993_msg03, compact_otp6017_msg01, - compact_otp6017_msg02, compact_otp6017_msg03]}, - {flex_compact_tickets, [], - flex_compact_tickets_cases()}, - {pretty_tickets, [], - [pretty_otp4632_msg1, pretty_otp4632_msg2, - pretty_otp4632_msg3, pretty_otp4632_msg4, - pretty_otp4710_msg1, pretty_otp4710_msg2, - pretty_otp4945_msg1, pretty_otp4945_msg2, - pretty_otp4945_msg3, pretty_otp4945_msg4, - pretty_otp4945_msg5, pretty_otp4945_msg6, - pretty_otp4949_msg1, pretty_otp4949_msg2, - pretty_otp4949_msg3, pretty_otp5042_msg1, - pretty_otp5068_msg1, pretty_otp5085_msg1, - pretty_otp5085_msg2, pretty_otp5085_msg3, - pretty_otp5085_msg4, pretty_otp5085_msg5, - pretty_otp5085_msg6, pretty_otp5085_msg7, - pretty_otp5600_msg1, pretty_otp5600_msg2, - pretty_otp5601_msg1, pretty_otp5793_msg01, - pretty_otp5882_msg01, pretty_otp6490_msg01, - pretty_otp6490_msg02, pretty_otp6490_msg03, - pretty_otp6490_msg04, pretty_otp6490_msg05, - pretty_otp6490_msg06, pretty_otp7671_msg01, - pretty_otp7671_msg02, pretty_otp7671_msg03, - pretty_otp7671_msg04, pretty_otp7671_msg05]}, - {flex_pretty_tickets, [], flex_pretty_tickets_cases()}]. + [{text, [], [{group, pretty}, + {group, flex_pretty}, + {group, compact}, + {group, flex_compact}]}, + {binary, [], [{group, bin}, + {group, ber}, + {group, ber_bin}, + {group, per}, + {group, per_bin}]}, + {erl_dist, [], [{group, erl_dist_m}]}, + {pretty, [], [pretty_test_msgs]}, + {compact, [], [compact_test_msgs]}, + {flex_pretty, [], flex_pretty_cases()}, + {flex_compact, [], flex_compact_cases()}, + {bin, [], [bin_test_msgs]}, + {ber, [], [ber_test_msgs]}, + {ber_bin, [], [ber_bin_test_msgs]}, + {per, [], [per_test_msgs]}, + {per_bin, [], [per_bin_test_msgs]}, + {erl_dist_m, [], [erl_dist_m_test_msgs]}, + {tickets, [], [{group, compact_tickets}, + {group, pretty_tickets}, + {group, flex_compact_tickets}, + {group, flex_pretty_tickets}]}, + {compact_tickets, [], [compact_otp4011_msg1, + compact_otp4011_msg2, + compact_otp4011_msg3, + compact_otp4013_msg1, + compact_otp4085_msg1, + compact_otp4085_msg2, + compact_otp4280_msg1, + compact_otp4299_msg1, + compact_otp4299_msg2, + compact_otp4359_msg1, + compact_otp4920_msg0, + compact_otp4920_msg1, + compact_otp4920_msg2, + compact_otp4920_msg3, + compact_otp4920_msg4, + compact_otp4920_msg5, + compact_otp4920_msg6, + compact_otp4920_msg7, + compact_otp4920_msg8, + compact_otp4920_msg9, + compact_otp4920_msg10, + compact_otp4920_msg11, + compact_otp4920_msg12, + compact_otp4920_msg20, + compact_otp4920_msg21, + compact_otp4920_msg22, + compact_otp4920_msg23, + compact_otp4920_msg24, + compact_otp4920_msg25, + compact_otp5186_msg01, + compact_otp5186_msg02, + compact_otp5186_msg03, + compact_otp5186_msg04, + compact_otp5186_msg05, + compact_otp5186_msg06, + compact_otp5793_msg01, + compact_otp5993_msg01, + compact_otp5993_msg02, + compact_otp5993_msg03, + compact_otp6017_msg01, + compact_otp6017_msg02, + compact_otp6017_msg03]}, + {flex_compact_tickets, [], flex_compact_tickets_cases()}, + {pretty_tickets, [], [pretty_otp4632_msg1, + pretty_otp4632_msg2, + pretty_otp4632_msg3, + pretty_otp4632_msg4, + pretty_otp4710_msg1, + pretty_otp4710_msg2, + pretty_otp4945_msg1, + pretty_otp4945_msg2, + pretty_otp4945_msg3, + pretty_otp4945_msg4, + pretty_otp4945_msg5, + pretty_otp4945_msg6, + pretty_otp4949_msg1, + pretty_otp4949_msg2, + pretty_otp4949_msg3, + pretty_otp5042_msg1, + pretty_otp5068_msg1, + pretty_otp5085_msg1, + pretty_otp5085_msg2, + pretty_otp5085_msg3, + pretty_otp5085_msg4, + pretty_otp5085_msg5, + pretty_otp5085_msg6, + pretty_otp5085_msg7, + pretty_otp5600_msg1, + pretty_otp5600_msg2, + pretty_otp5601_msg1, + pretty_otp5793_msg01, + pretty_otp5882_msg01, + pretty_otp6490_msg01, + pretty_otp6490_msg02, + pretty_otp6490_msg03, + pretty_otp6490_msg04, + pretty_otp6490_msg05, + pretty_otp6490_msg06, + pretty_otp7671_msg01, + pretty_otp7671_msg02, + pretty_otp7671_msg03, + pretty_otp7671_msg04, + pretty_otp7671_msg05]}, + {flex_pretty_tickets, [], flex_pretty_tickets_cases()}]. init_per_group(flex_pretty_tickets, Config) -> flex_pretty_init(Config); diff --git a/lib/megaco/test/megaco_test_generator.erl b/lib/megaco/test/megaco_test_generator.erl index a021d2451b..4fbc86262e 100644 --- a/lib/megaco/test/megaco_test_generator.erl +++ b/lib/megaco/test/megaco_test_generator.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,6 +26,10 @@ -behaviour(gen_server). +-compile({no_auto_import,[error/2]}). + +%% ---- + -export([ start_link/3, start_link/4, diff --git a/lib/megaco/test/megaco_test_lib.erl b/lib/megaco/test/megaco_test_lib.erl index 0d2b4a3f4e..41f6c2c4cb 100644 --- a/lib/megaco/test/megaco_test_lib.erl +++ b/lib/megaco/test/megaco_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -146,28 +146,28 @@ tickets(Mod, Func, Config) -> end, lists:map(Map, Cases); - {req, _, {conf, Init, Cases, Finish}} -> - case (catch Mod:Init(Config)) of - Conf when is_list(Conf) -> - io:format("Expand: ~p:~p ...~n", [Mod, Func]), - Map = fun({M,_}) when is_atom(M) -> - tickets(M, tickets, Config); - (F) when is_atom(F) -> - tickets(Mod, F, Config); - (Case) -> Case - end, - Res = lists:map(Map, Cases), - (catch Mod:Finish(Conf)), - Res; +%% {req, _, {conf, Init, Cases, Finish}} -> +%% case (catch Mod:Init(Config)) of +%% Conf when is_list(Conf) -> +%% io:format("Expand: ~p:~p ...~n", [Mod, Func]), +%% Map = fun({M,_}) when is_atom(M) -> +%% tickets(M, tickets, Config); +%% (F) when is_atom(F) -> +%% tickets(Mod, F, Config); +%% (Case) -> Case +%% end, +%% Res = lists:map(Map, Cases), +%% (catch Mod:Finish(Conf)), +%% Res; - {'EXIT', {skipped, Reason}} -> - io:format(" => skipping: ~p~n", [Reason]), - [{skipped, {Mod, Func}, Reason}]; +%% {'EXIT', {skipped, Reason}} -> +%% io:format(" => skipping: ~p~n", [Reason]), +%% [{skipped, {Mod, Func}, Reason}]; - Error -> - io:format(" => init failed: ~p~n", [Error]), - [{failed, {Mod, Func}, Error}] - end; +%% Error -> +%% io:format(" => init failed: ~p~n", [Error]), +%% [{failed, {Mod, Func}, Error}] +%% end; {'EXIT', {undef, _}} -> io:format("Undefined: ~p~n", [{Mod, Func}]), @@ -252,6 +252,8 @@ alloc_instance_mem_info(Key, InstanceInfo) -> end. +t([Case]) when is_atom(Case) -> + t(Case); t(Case) -> process_flag(trap_exit, true), MEM = fun() -> case (catch erlang:memory()) of @@ -266,11 +268,65 @@ t(Case) -> Res = lists:flatten(t(Case, default_config())), Alloc2 = alloc_info(), Mem2 = MEM(), - %% io:format("Res: ~p~n", [Res]), display_result(Res, Alloc1, Mem1, Alloc2, Mem2), Res. -t({Mod, Fun}, Config) when is_atom(Mod) andalso is_atom(Fun) -> + +groups(Mod) when is_atom(Mod) -> + try Mod:groups() of + Groups when is_list(Groups) -> + Groups; + BadGroups -> + exit({bad_groups, Mod, BadGroups}) + catch + _:_ -> + [] + end. + +init_suite(Mod, Config) -> + Mod:init_per_suite(Config). + +end_suite(Mod, Config) -> + Mod:end_per_suite(Config). + +init_group(Mod, Group, Config) -> + Mod:init_per_group(Group, Config). + +end_group(Mod, Group, Config) -> + Mod:init_per_group(Group, Config). + +%% This is for sub-SUITEs +t({_Mod, {NewMod, all}, _Groups}, _Config) when is_atom(NewMod) -> + t(NewMod); +t({Mod, {group, Name} = Group, Groups}, Config) + when is_atom(Mod) andalso is_atom(Name) andalso is_list(Groups) -> + case lists:keysearch(Name, 1, Groups) of + {value, {Name, _Props, GroupsAndCases}} -> + try init_group(Mod, Name, Config) of + Config2 when is_list(Config2) -> + Res = [t({Mod, Case, Groups}, Config2) || + Case <- GroupsAndCases], + (catch end_group(Mod, Name, Config2)), + Res; + Error -> + io:format(" => group (~w) init failed: ~p~n", + [Name, Error]), + [{failed, {Mod, Group}, Error}] + catch + exit:{skipped, SkipReason} -> + io:format(" => skipping group: ~p~n", [SkipReason]), + [{skipped, {Mod, Group}, SkipReason, 0}]; + exit:{undef, _} -> + [t({Mod, Case, Groups}, Config) || + Case <- GroupsAndCases]; + T:E -> + [{failed, {Mod, Group}, {T,E}, 0}] + end; + false -> + exit({unknown_group, Mod, Name, Groups}) + end; +t({Mod, Fun, _}, Config) + when is_atom(Mod) andalso is_atom(Fun) -> case catch apply(Mod, Fun, [suite]) of [] -> io:format("Eval: ~p:", [{Mod, Fun}]), @@ -286,26 +342,6 @@ t({Mod, Fun}, Config) when is_atom(Mod) andalso is_atom(Fun) -> end, t(lists:map(Map, Cases), Config); - {req, _, {conf, Init, Cases, Finish}} -> - case (catch apply(Mod, Init, [Config])) of - Conf when is_list(Conf) -> - io:format("Expand: ~p ...~n", [{Mod, Fun}]), - Map = fun(Case) when is_atom(Case) -> {Mod, Case}; - (Case) -> Case - end, - Res = t(lists:map(Map, Cases), Conf), - (catch apply(Mod, Finish, [Conf])), - Res; - - {'EXIT', {skipped, Reason}} -> - io:format(" => skipping: ~p~n", [Reason]), - [{skipped, {Mod, Fun}, Reason, 0}]; - - Error -> - io:format(" => failed: ~p~n", [Error]), - [{failed, {Mod, Fun}, Error, 0}] - end; - {'EXIT', {undef, _}} -> io:format("Undefined: ~p~n", [{Mod, Fun}]), [{nyi, {Mod, Fun}, ok, 0}]; @@ -315,10 +351,38 @@ t({Mod, Fun}, Config) when is_atom(Mod) andalso is_atom(Fun) -> [{failed, {Mod, Fun}, Error, 0}] end; t(Mod, Config) when is_atom(Mod) -> - Res = t({Mod, all}, Config), - Res; -t(Cases, Config) when is_list(Cases) -> - [t(Case, Config) || Case <- Cases]; + %% This is assumed to be a test suite, so we start by calling + %% the top test suite function(s) (all/0 and groups/0). + case (catch Mod:all()) of + Cases when is_list(Cases) -> + %% The list may contain atoms (actual test cases) and + %% group-tuples (a tuple naming a group of test cases). + %% A group is defined by the (optional) groups/0 function. + Groups = groups(Mod), + try init_suite(Mod, Config) of + Config2 when is_list(Config2) -> + Res = [t({Mod, Case, Groups}, Config2) || Case <- Cases], + (catch end_suite(Mod, Config2)), + Res; + Error -> + io:format(" => suite init failed: ~p~n", [Error]), + [{failed, {Mod, init_per_suite}, Error}] + catch + exit:{skipped, SkipReason} -> + io:format(" => skipping suite: ~p~n", [SkipReason]), + [{skipped, {Mod, init_per_suite}, SkipReason, 0}]; + exit:{undef, _} -> + [t({Mod, Case, Groups}, Config) || Case <- Cases]; + T:E -> + [{failed, {Mod, init_per_suite}, {T,E}, 0}] + end; + {'EXIT', {undef, _}} -> + io:format("Undefined: ~p~n", [{Mod, all}]), + [{nyi, {Mod, all}, ok, 0}]; + + Crap -> + Crap + end; t(Bad, _Config) -> [{badarg, Bad, ok, 0}]. @@ -495,28 +559,56 @@ do_display_memory([{Key, Mem1}|MemInfo1], MemInfo2) -> display_result([]) -> io:format("OK~n", []); display_result(Res) when is_list(Res) -> - Ok = [{MF, Time} || {ok, MF, _, Time} <- Res], - Nyi = [MF || {nyi, MF, _, _Time} <- Res], - Skipped = [{MF, Reason} || {skipped, MF, Reason, _Time} <- Res], - Failed = [{MF, Reason} || {failed, MF, Reason, _Time} <- Res], - Crashed = [{MF, Reason} || {crashed, MF, Reason, _Time} <- Res], - display_summery(Ok, Nyi, Skipped, Failed, Crashed), + Ok = [{MF, Time} || {ok, MF, _, Time} <- Res], + Nyi = [MF || {nyi, MF, _, _Time} <- Res], + SkippedGrps = [{{M,G}, Reason} || + {skipped, {M, {group, G}}, Reason, _Time} <- Res], + SkippedCases = [{MF, Reason} || + {skipped, {_M, F} = MF, Reason, _Time} <- Res, + is_atom(F)], + FailedGrps = [{{M,G}, Reason} || + {failed, {M, {group, G}}, Reason, _Time} <- Res], + FailedCases = [{MF, Reason} || + {failed, {_M, F} = MF, Reason, _Time} <- Res, + is_atom(F)], + Crashed = [{MF, Reason} || {crashed, MF, Reason, _Time} <- Res], + display_summery(Ok, Nyi, + SkippedGrps, SkippedCases, + FailedGrps, FailedCases, + Crashed), display_ok(Ok), - display_skipped(Skipped), - display_failed(Failed), + display_skipped("groups", SkippedGrps), + display_skipped("test cases", SkippedCases), + display_failed("groups", FailedGrps), + display_failed("test cases", FailedCases), display_crashed(Crashed). -display_summery(Ok, Nyi, Skipped, Failed, Crashed) -> +display_summery(Ok, Nyi, + SkippedGrps, SkippedCases, + FailedGrps, FailedCases, + Crashed) -> io:format("~nTest case summery:~n", []), - display_summery(Ok, "successfull"), - display_summery(Nyi, "not yet implemented"), - display_summery(Skipped, "skipped"), - display_summery(Failed, "failed"), - display_summery(Crashed, "crashed"), + display_summery(Ok, "test case", "successfull"), + display_summery(Nyi, "test case", "not yet implemented"), + display_summery(SkippedGrps, "group", "skipped"), + display_summery(SkippedCases, "test case", "skipped"), + display_summery(FailedGrps, "group", "failed"), + display_summery(FailedCases, "test case", "failed"), + display_summery(Crashed, "test case", "crashed"), io:format("~n", []). -display_summery(Res, Info) -> - io:format(" ~w test cases ~s~n", [length(Res), Info]). + +display_summery(Res, Kind, Info) -> + Len = length(Res), + if + Len =:= 1 -> + display_summery(Len, Kind ++ " " ++ Info); + true -> + display_summery(Len, Kind ++ "s " ++ Info) + end. + +display_summery(Len, Info) -> + io:format(" ~w ~s~n", [Len, Info]). display_ok([]) -> ok; @@ -528,20 +620,20 @@ display_ok(Ok) -> lists:foreach(F, Ok), io:format("~n", []). -display_skipped([]) -> +display_skipped(_, []) -> ok; -display_skipped(Skipped) -> - io:format("Skipped test cases:~n", []), - F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end, +display_skipped(Pre, Skipped) -> + io:format("Skipped ~s:~n", [Pre]), + F = fun({X, Reason}) -> io:format(" ~p => ~p~n", [X, Reason]) end, lists:foreach(F, Skipped), io:format("~n", []). -display_failed([]) -> +display_failed(_, []) -> ok; -display_failed(Failed) -> - io:format("Failed test cases:~n", []), - F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end, +display_failed(Pre, Failed) -> + io:format("Failed ~s:~n", [Pre]), + F = fun({X, Reason}) -> io:format(" ~p => ~p~n", [X, Reason]) end, lists:foreach(F, Failed), io:format("~n", []). @@ -837,5 +929,5 @@ start_nodes([Node | Nodes], File, Line) -> start_nodes([], _File, _Line) -> ok. -p(F,A) -> - io:format("~p" ++ F ++ "~n", [self()|A]). +p(F, A) -> + io:format("~p~w:" ++ F ++ "~n", [self(), ?MODULE |A]). diff --git a/lib/megaco/test/megaco_test_megaco_generator.erl b/lib/megaco/test/megaco_test_megaco_generator.erl index 21b33e4abc..f0c723d2cf 100644 --- a/lib/megaco/test/megaco_test_megaco_generator.erl +++ b/lib/megaco/test/megaco_test_megaco_generator.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,6 +26,8 @@ -behaviour(megaco_test_generator). +-compile({no_auto_import,[error/1]}). + %% API -export([ start_link/1, start_link/2, diff --git a/lib/megaco/test/megaco_test_msg_prev3a_lib.erl b/lib/megaco/test/megaco_test_msg_prev3a_lib.erl index 2fb0752865..fad7f29831 100644 --- a/lib/megaco/test/megaco_test_msg_prev3a_lib.erl +++ b/lib/megaco/test/megaco_test_msg_prev3a_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,6 +26,10 @@ %% ---- +-compile({no_auto_import,[error/1]}). + +%% ---- + -include_lib("megaco/include/megaco_message_prev3a.hrl"). -include_lib("megaco/include/megaco.hrl"). diff --git a/lib/megaco/test/megaco_test_msg_prev3b_lib.erl b/lib/megaco/test/megaco_test_msg_prev3b_lib.erl index 6e042080b7..2f1a093728 100644 --- a/lib/megaco/test/megaco_test_msg_prev3b_lib.erl +++ b/lib/megaco/test/megaco_test_msg_prev3b_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,6 +26,10 @@ %% ---- +-compile({no_auto_import,[error/1]}). + +%% ---- + -include_lib("megaco/include/megaco_message_prev3b.hrl"). -include_lib("megaco/include/megaco.hrl"). diff --git a/lib/megaco/test/megaco_test_msg_prev3c_lib.erl b/lib/megaco/test/megaco_test_msg_prev3c_lib.erl index c768105194..884e2f2bad 100644 --- a/lib/megaco/test/megaco_test_msg_prev3c_lib.erl +++ b/lib/megaco/test/megaco_test_msg_prev3c_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,6 +26,10 @@ %% ---- +-compile({no_auto_import,[error/1]}). + +%% ---- + -include_lib("megaco/include/megaco_message_prev3c.hrl"). -include_lib("megaco/include/megaco.hrl"). diff --git a/lib/megaco/test/megaco_test_msg_v1_lib.erl b/lib/megaco/test/megaco_test_msg_v1_lib.erl index 424a66b7c9..76665cb575 100644 --- a/lib/megaco/test/megaco_test_msg_v1_lib.erl +++ b/lib/megaco/test/megaco_test_msg_v1_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -28,6 +28,10 @@ %% ---- +-compile({no_auto_import,[error/1]}). + +%% ---- + -include_lib("megaco/include/megaco_message_v1.hrl"). -include_lib("megaco/include/megaco.hrl"). diff --git a/lib/megaco/test/megaco_test_msg_v2_lib.erl b/lib/megaco/test/megaco_test_msg_v2_lib.erl index b29920006d..66e423284a 100644 --- a/lib/megaco/test/megaco_test_msg_v2_lib.erl +++ b/lib/megaco/test/megaco_test_msg_v2_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,6 +26,10 @@ %% ---- +-compile({no_auto_import,[error/1]}). + +%% ---- + -include_lib("megaco/include/megaco_message_v2.hrl"). -include_lib("megaco/include/megaco.hrl"). diff --git a/lib/megaco/test/megaco_test_msg_v3_lib.erl b/lib/megaco/test/megaco_test_msg_v3_lib.erl index fee61542b7..24492167ff 100644 --- a/lib/megaco/test/megaco_test_msg_v3_lib.erl +++ b/lib/megaco/test/megaco_test_msg_v3_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,6 +26,10 @@ %% ---- +-compile({no_auto_import,[error/1]}). + +%% ---- + -include_lib("megaco/include/megaco_message_v3.hrl"). -include_lib("megaco/include/megaco.hrl"). diff --git a/lib/megaco/test/megaco_test_tcp_generator.erl b/lib/megaco/test/megaco_test_tcp_generator.erl index 416d56d742..3ed4c49bab 100644 --- a/lib/megaco/test/megaco_test_tcp_generator.erl +++ b/lib/megaco/test/megaco_test_tcp_generator.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,6 +26,8 @@ -behaviour(megaco_test_generator). +-compile({no_auto_import,[error/1]}). + %% API -export([ start_link/1, start_link/2, diff --git a/lib/megaco/test/megaco_timer_test.erl b/lib/megaco/test/megaco_timer_test.erl index cccf4651ab..9b9103c40b 100644 --- a/lib/megaco/test/megaco_timer_test.erl +++ b/lib/megaco/test/megaco_timer_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -23,6 +23,8 @@ %%---------------------------------------------------------------------- -module(megaco_timer_test). +-compile({no_auto_import,[error/1]}). + -export([ t/0, t/1, init_per_testcase/2, end_per_testcase/2, diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk index 9fc0e0f2fa..5f71712360 100644 --- a/lib/megaco/vsn.mk +++ b/lib/megaco/vsn.mk @@ -1,4 +1,23 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + APPLICATION = megaco -MEGACO_VSN = 3.15 -PRE_VSN = -APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)" +MEGACO_VSN = 3.15.1 +PRE_VSN = +APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)" diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl index fb29007780..025b32f506 100644 --- a/lib/mnesia/src/mnesia.erl +++ b/lib/mnesia/src/mnesia.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -302,7 +302,7 @@ ms() -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Activity mgt --spec(abort/1 :: (_) -> no_return()). +-spec abort(_) -> no_return(). abort(Reason) -> exit({aborted, Reason}). @@ -1835,6 +1835,7 @@ do_dirty_rpc(Tab, Node, M, F, Args) -> %% Info %% Info about one table +-spec table_info(atom(), any()) -> any(). table_info(Tab, Item) -> case get(mnesia_activity_state) of undefined -> @@ -1868,7 +1869,7 @@ any_table_info(Tab, Item) when is_atom(Tab) -> type -> case ?catch_val({Tab, setorbag}) of {'EXIT', _} -> - bad_info_reply(Tab, Item); + abort({no_exists, Tab, Item}); Val -> Val end; @@ -1886,7 +1887,7 @@ any_table_info(Tab, Item) when is_atom(Tab) -> _ -> case ?catch_val({Tab, Item}) of {'EXIT', _} -> - bad_info_reply(Tab, Item); + abort({no_exists, Tab, Item}); Val -> Val end diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl index 37a8258d74..47dcdad7ac 100644 --- a/lib/mnesia/src/mnesia_bup.erl +++ b/lib/mnesia/src/mnesia_bup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -65,6 +65,8 @@ default_op = keep_tables }). +-type fallback_args() :: #fallback_args{}. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Backup iterator @@ -108,6 +110,7 @@ iter(R, Header, Schema, Fun, Acc, BupItems) -> Acc2 = Fun(BupItems, Header, Schema, Acc), iter(R, Header, Schema, Fun, Acc2, []). +-spec safe_apply(#restore{}, atom(), list()) -> tuple(). safe_apply(R, write, [_, Items]) when Items =:= [] -> R; safe_apply(R, What, Args) -> @@ -570,6 +573,7 @@ fallback_bup() -> mnesia_lib:dir(fallback_name()). fallback_tmp_name() -> "FALLBACK.TMP". %% fallback_full_tmp_name() -> mnesia_lib:dir(fallback_tmp_name()). +-spec fallback_receiver(pid(), fallback_args()) -> no_return(). fallback_receiver(Master, FA) -> process_flag(trap_exit, true), @@ -981,6 +985,7 @@ do_uninstall_fallback(FA) -> {error, Reason} end. +-spec uninstall_fallback_master(pid(), fallback_args()) -> no_return(). uninstall_fallback_master(ClientPid, FA) -> process_flag(trap_exit, true), diff --git a/lib/mnesia/src/mnesia_frag.erl b/lib/mnesia/src/mnesia_frag.erl index a2958ab461..6cc16c80fd 100644 --- a/lib/mnesia/src/mnesia_frag.erl +++ b/lib/mnesia/src/mnesia_frag.erl @@ -1,7 +1,7 @@ %%% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -448,13 +448,15 @@ do_remote_select(_ReplyTo, _Ref, [], _MatchSpec) -> local_collect(Ref, Pid, Type, LocalMatch, OldSelectFun) -> receive - {local_select, Ref, LocalRes} -> - remote_collect(Ref, Type, LocalRes, LocalMatch, OldSelectFun); + {local_select, Ref, ok} -> + remote_collect_ok(Ref, Type, LocalMatch, OldSelectFun); + {local_select, Ref, {error, Reason}} -> + remote_collect_error(Ref, Type, Reason, OldSelectFun); {'EXIT', Pid, Reason} -> - remote_collect(Ref, Type, {error, Reason}, [], OldSelectFun) + remote_collect_error(Ref, Type, Reason, OldSelectFun) end. -remote_collect(Ref, Type, LocalRes = ok, Acc, OldSelectFun) -> +remote_collect_ok(Ref, Type, Acc, OldSelectFun) -> receive {remote_select, Ref, Node, RemoteRes} -> case RemoteRes of @@ -463,19 +465,21 @@ remote_collect(Ref, Type, LocalRes = ok, Acc, OldSelectFun) -> ordered_set -> lists:merge(RemoteMatch, Acc); _ -> RemoteMatch ++ Acc end, - remote_collect(Ref, Type, LocalRes, Matches, OldSelectFun); + remote_collect_ok(Ref, Type, Matches, OldSelectFun); _ -> - remote_collect(Ref, Type, {error, {node_not_running, Node}}, [], OldSelectFun) + Reason = {node_not_running, Node}, + remote_collect_error(Ref, Type, Reason, OldSelectFun) end after 0 -> Acc - end; -remote_collect(Ref, Type, LocalRes = {error, Reason}, _Acc, OldSelectFun) -> + end. + +remote_collect_error(Ref, Type, Reason, OldSelectFun) -> receive {remote_select, Ref, _Node, _RemoteRes} -> - remote_collect(Ref, Type, LocalRes, [], OldSelectFun) + remote_collect_error(Ref, Type, Reason, OldSelectFun) after 0 -> - mnesia:abort(Reason) + mnesia:abort({error, Reason}) end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl index 4e6e8a997c..61210d7e55 100644 --- a/lib/mnesia/src/mnesia_index.erl +++ b/lib/mnesia/src/mnesia_index.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl index 3da3dd2f5c..36bcfe8de9 100644 --- a/lib/mnesia/src/mnesia_lib.erl +++ b/lib/mnesia/src/mnesia_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -399,7 +399,7 @@ other_val(Var, Other) -> pr_other(Var, Other) end. --spec(pr_other/2 :: (_,_) -> no_return()). +-spec pr_other(_,_) -> no_return(). pr_other(Var, Other) -> Why = diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl index 6b5770d91e..ca0cc79c45 100644 --- a/lib/mnesia/src/mnesia_locker.erl +++ b/lib/mnesia/src/mnesia_locker.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1104,6 +1104,7 @@ do_stop() -> system_continue(_Parent, _Debug, State) -> loop(State). +-spec system_terminate(_, _, _, _) -> no_return(). system_terminate(_Reason, _Parent, _Debug, _State) -> do_stop(). diff --git a/lib/mnesia/src/mnesia_recover.erl b/lib/mnesia/src/mnesia_recover.erl index 7435b6896a..b3eed1de6e 100644 --- a/lib/mnesia/src/mnesia_recover.erl +++ b/lib/mnesia/src/mnesia_recover.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/mnesia/src/mnesia_snmp_hook.erl b/lib/mnesia/src/mnesia_snmp_hook.erl index 8b4b5231e1..893b39f3c0 100644 --- a/lib/mnesia/src/mnesia_snmp_hook.erl +++ b/lib/mnesia/src/mnesia_snmp_hook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl index f3ffac5493..bb8e788b40 100644 --- a/lib/mnesia/src/mnesia_tm.erl +++ b/lib/mnesia/src/mnesia_tm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1604,6 +1604,7 @@ tell_participants([Pid | Pids], Msg) -> tell_participants([], _Msg) -> ok. +-spec commit_participant(_, _, _, _, _) -> no_return(). %% Trap exit because we can get a shutdown from application manager commit_participant(Coord, Tid, Bin, DiscNs, RamNs) when is_binary(Bin) -> process_flag(trap_exit, true), @@ -2279,6 +2280,7 @@ fixtable(Tab, Lock, Me) -> system_continue(_Parent, _Debug, State) -> doit_loop(State). +-spec system_terminate(_, _, _, _) -> no_return(). system_terminate(_Reason, _Parent, _Debug, State) -> do_stop(State). diff --git a/lib/observer/doc/src/crashdump.xml b/lib/observer/doc/src/crashdump.xml index f8d7641524..b6056c2ed1 100644 --- a/lib/observer/doc/src/crashdump.xml +++ b/lib/observer/doc/src/crashdump.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2003</year> - <year>2007</year> + <year>2011</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -38,6 +38,10 @@ <description> <p>The Crashdump Viewer is an HTML based tool for browsing Erlang crashdumps. Crashdump Viewer runs under the WebTool application.</p> + + <p>See the <seealso marker="crashdump_ug">user's guide</seealso> + for more information about how to get started with the Crashdump + Viewer.</p> </description> <funcs> <func> diff --git a/lib/observer/doc/src/crashdump_help.html b/lib/observer/doc/src/crashdump_help.html index 736a024288..268b9495d6 100644 --- a/lib/observer/doc/src/crashdump_help.html +++ b/lib/observer/doc/src/crashdump_help.html @@ -131,7 +131,7 @@ SRC="min_head.gif"></a> - <a NAME="ets_tables"> + <a NAME="ets_tables"><a NAME="internal_ets_tables"> <h3>ETS tables</h3> <p>The ETS table information page shows all ETS table @@ -304,4 +304,4 @@ Copyright © 1991-2003 </font> </center> </body> -</html>
\ No newline at end of file +</html> diff --git a/lib/observer/doc/src/crashdump_ug.xml b/lib/observer/doc/src/crashdump_ug.xml index 9913b30e38..dc65fe5b39 100644 --- a/lib/observer/doc/src/crashdump_ug.xml +++ b/lib/observer/doc/src/crashdump_ug.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2009</year> + <year>2003</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -38,12 +38,31 @@ <section> <title>Getting Started</title> - <p>From an erlang node, start Crashdump Viewer by calling - <c>crashdump_viewer:start()</c>. This will automatically start - WebTool and display the web address where WebTool can be - found. See the documentation for the WebTool application for - further information about how to use WebTool. - </p> + + <p>The easiest way to start Crashdump Viewer is to use the + provided shell script named <c>cdv</c> with the full path to the + erlang crashdump as an argument. The script can be found in the + priv directory of the <c>observer</c> application. This starts + WebTool, Crashdump Viewer and a web browser, and loads the given + file. The browser should then display a page named General + Information which shows a short summary of the information in + the crashdump.</p> + + <p>The default browser is Internet Explorer on Windows or else + Firefox. To use another browser, give the browser's start command + as the second argument to <c>cdv</c>. If the given browser name is + not known to Crashdump Viewer, the browser argument is executed as + a command with the start URL as the only argument.</p> + + <p>Under Windows the batch file <c>cdv.bat</c> can be used.</p> + + <p>It is also possible to start the Crashdump Viewer from within + an erlang node by calling <seealso + marker="crashdump_viewer#start/0">crashdump_viewer:start/0</seealso>. This + will automatically start WebTool and display the web address where + WebTool can be found. See the documentation for the WebTool + application for further information about how to use WebTool.</p> + <p>Point your web browser to the address displayed, and you should now see the start page of WebTool. At the top of the page, you will see a link to "CrashDumpViewer". Click this link to get to @@ -52,15 +71,12 @@ connection to the internet, or you must set no proxy for localhost.) </p> - <p>You can also start WebTool, Crashdump Viewer and a browser in - one go by running the <c>start_webtool</c> script found in the - <c>priv</c> directory of the WebTool application, e.g. - <br></br> -<c>>start_webtool crashdump_viewer</c></p> <p>From the start page of Crashdump Viewer, push the "Load Crashdump" button to load a crashdump into the tool. Then enter - the filename of the crashdump in the entry field and push the "Ok" - button. + the filename of the crashdump in the entry field and push the + "Ok" button. This will bring you to the General Information + page, i.e. the same page as the <c>cdv</c> script will open in + the browser. </p> <p>Crashdumps generated by OTP R9C and later are loaded directly into the Crashdump Viewer, while dumps from earlier releases first diff --git a/lib/observer/doc/src/etop.xml b/lib/observer/doc/src/etop.xml index 1ea67e6864..78047caab3 100644 --- a/lib/observer/doc/src/etop.xml +++ b/lib/observer/doc/src/etop.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2002</year> - <year>2007</year> + <year>2011</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -26,27 +26,33 @@ <title>etop</title> <prepared>Siri hansen</prepared> <responsible></responsible> - <docno>1</docno> + <docno></docno> <approved></approved> <checked></checked> - <date>2002-03-27</date> - <rev>PA1</rev> - <file>etop.sgml</file> + <date></date> + <rev></rev> + <file></file> </header> <module>etop</module> <modulesummary>Erlang Top is a tool for presenting information about erlang processes similar to the information presented by "top" in UNIX.</modulesummary> <description> + <p><c>etop</c> should be started with the provided scripts <c>etop</c> and <c>getop</c> for text based and graphical - presentation respectively. Under Windows the batch files - <c>etop.bat</c> and <c>getop.bat</c> can be used. - </p> - <p>All interaction with <c>etop</c> when running the graphical - presentation should happen via the menus. For the text based - presentation the functions described below can be used. - </p> - <p>The following configuration parameters exist for <c>etop</c>. - </p> + presentation respectively. This will start a hidden erlang node + which connects to the node to be measured. The measured node is + given with the <c>-node</c> option. If the measured node has a + different cookie than the default cookie for the user who + invokes the script, the cookie must be explicitly given witht + the <c>-setcookie</c> option.</p> + + <p>Under Windows the batch files <c>etop.bat</c> and + <c>getop.bat</c> can be used.</p> + + <p>The following configuration parameters exist for the + <c>etop</c> tool. When executing the <c>etop</c> or <c>getop</c> + scripts, these parameters can be given as command line options, + e.g. <c>getop -node testnode@myhost -setcookie MyCookie</c>.</p> <taglist> <tag>node</tag> <item>The measured node. @@ -96,6 +102,15 @@ Default: <c>runtime</c> (<c>reductions</c> if Value: <c>on | off</c> <br></br> Default: <c>on</c></item> </taglist> + + <p>All interaction with <c>etop</c> when running the graphical + presentation should happen via the menus. For the text based + presentation the functions described below can be used. + </p> + + <p>See the <seealso marker="etop_ug">user's guide</seealso> for + more information about the <c>etop</c> tool.</p> + </description> <funcs> <func> diff --git a/lib/observer/priv/bin/cdv b/lib/observer/priv/bin/cdv new file mode 100755 index 0000000000..1c44785ac2 --- /dev/null +++ b/lib/observer/priv/bin/cdv @@ -0,0 +1,4 @@ +#!/bin/sh + +erl -sname cdv -noinput -s crashdump_viewer script_start $@ + diff --git a/lib/observer/priv/bin/cdv.bat b/lib/observer/priv/bin/cdv.bat new file mode 100644 index 0000000000..efa8bf8687 --- /dev/null +++ b/lib/observer/priv/bin/cdv.bat @@ -0,0 +1,2 @@ +@ECHO OFF +CALL werl -sname cdv -s crashdump_viewer script_start %* diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile index b4eb518dd7..2d06cb6bc4 100644 --- a/lib/observer/src/Makefile +++ b/lib/observer/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2002-2009. All Rights Reserved. +# Copyright Ericsson AB 2002-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -59,8 +59,10 @@ BINDIR= $(PRIVDIR)/bin EXECUTABLES= \ $(BINDIR)/etop \ $(BINDIR)/getop \ + $(BINDIR)/cdv \ $(BINDIR)/etop.bat \ - $(BINDIR)/getop.bat + $(BINDIR)/getop.bat \ + $(BINDIR)/cdv.bat CDVDIR= $(PRIVDIR)/crashdump_viewer GIF_FILES= \ $(CDVDIR)/collapsd.gif \ diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl index 978541e470..3b8d17c7d9 100644 --- a/lib/observer/src/crashdump_viewer.erl +++ b/lib/observer/src/crashdump_viewer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ %% the server started by webtool and the API for the crashdump viewer tool. %% %% All functions in the API except configData/0 and start_link/0 are -%% called from HTML pages via erl_scheme. +%% called from HTML pages via erl_scheme (mod_esi). %% %% Tables %% ------ @@ -34,18 +34,21 @@ %% %% cdv_dump_index_table: This table holds all tags read from the crashdump. %% Each tag indicates where the information about a specific item starts. -%% The table entry for a tag includes the start and end positions for -%% this item-information. All tags start with a "=" at the beginning of +%% The table entry for a tag includes the start position for this +%% item-information. All tags start with a "=" at the beginning of %% a line. %% %% Process state %% ------------- %% file: The name of the crashdump currently viewed. %% procs_summary: Process summary represented by a list of -%% #proc records. This is used for efficiency reasons when sorting -%% the process summary table instead of reading all processes from -%% the dump again. -%% sorted: atom(), indicated what item was last sorted in process summary. +%% #proc records. This is used for efficiency reasons when sorting the +%% process summary table instead of reading all processes from the +%% dump again. Note that if the dump contains more than +%% ?max_sort_process_num processes, the sort functionality is not +%% available, and the procs_summary field in the state will have the +%% value 'too_many'. +%% sorted: string(), indicated what item was last sorted in process summary. %% This is needed so reverse sorting can be done. %% shared_heap: 'true' if crashdump comes from a system running shared heap, %% else 'false'. @@ -54,7 +57,7 @@ %% %% User API --export([start/0,stop/0]). +-export([start/0,stop/0,script_start/0,script_start/1]). %% Webtool API -export([configData/0, @@ -68,26 +71,27 @@ initial_info_frame/2, toggle/2, general_info/2, - processes/2, + processes/3, proc_details/2, - ports/2, - ets_tables/2, - timers/2, - fun_table/2, - atoms/2, + port/2, + ports/3, + ets_tables/3, + internal_ets_tables/2, + timers/3, + fun_table/3, + atoms/3, dist_info/2, - loaded_modules/2, + loaded_modules/3, loaded_mod_details/2, memory/2, allocated_areas/2, allocator_info/2, hash_tables/2, index_tables/2, - sort_procs/2, + sort_procs/3, expand/2, expand_binary/2, - expand_memory/2, - next/2]). + expand_memory/2]). %% gen_server callbacks @@ -113,24 +117,49 @@ % this, it must be explicitly expanded. -define(max_display_binary_size,50). % max size of a binary that will be % directly displayed. +-define(max_sort_process_num,10000). % Max number of processes that allows + % sorting. If more than this number of + % processes exist, they will be displayed + % in the order they are found in the log. +-define(items_chunk_size,?max_sort_process_num). % Number of items per chunk + % when page of many items + % is displayed, e.g. processes, + % timers, funs... + % Must be equal to + % ?max_sort_process_num! + +%% All possible tags - use macros in order to avoid misspelling in the code +-define(allocated_areas,allocated_areas). +-define(allocator,allocator). +-define(atoms,atoms). +-define(binary,binary). +-define(debug_proc_dictionary,debug_proc_dictionary). +-define(ende,ende). +-define(erl_crash_dump,erl_crash_dump). +-define(ets,ets). +-define(fu,fu). +-define(hash_table,hash_table). +-define(hidden_node,hidden_node). +-define(index_table,index_table). +-define(instr_data,instr_data). +-define(internal_ets,internal_ets). +-define(loaded_modules,loaded_modules). +-define(memory,memory). +-define(mod,mod). +-define(no_distribution,no_distribution). +-define(node,node). +-define(not_connected,not_connected). +-define(num_atoms,num_atoms). +-define(old_instr_data,old_instr_data). +-define(port,port). +-define(proc,proc). +-define(proc_dictionary,proc_dictionary). +-define(proc_heap,proc_heap). +-define(proc_messages,proc_messages). +-define(proc_stack,proc_stack). +-define(timer,timer). +-define(visible_node,visible_node). --define(initial_proc_record(Pid), - #proc{pid=Pid, - %% msg_q_len, reds and stack_heap are integers because it must - %% be possible to sort on them. All other fields are strings - msg_q_len=0,reds=0,stack_heap=0, - %% for old dumps start_time, parent and number of heap frament - %% does not exist - start_time="unknown", - parent="unknown", - num_heap_frag="unknown", - %% current_func can be both "current function" and - %% "last scheduled in for" - current_func={"Current Function",?space}, - %% stack_dump, message queue and dictionaries should only be - %% displayed as a link to "Expand" (if dump is from OTP R9B - %% or newer) - _=?space}). -record(state,{file,procs_summary,sorted,shared_heap=false, wordsize=4,num_atoms="unknown",binaries,bg_status}). @@ -177,6 +206,85 @@ stop() -> webtool:stop(). %%%----------------------------------------------------------------- +%%% Start crashdump_viewer via the cdv script located in +%%% $OBSERVER_PRIV_DIR/bin +script_start() -> + usage(). +script_start([File]) -> + DefaultBrowser = + case os:type() of + {win32,_} -> iexplore; + _ -> firefox + end, + script_start([File,DefaultBrowser]); +script_start([FileAtom,Browser]) -> + File = atom_to_list(FileAtom), + case filelib:is_regular(File) of + true -> + io:format("Starting crashdump_viewer...\n"), + start(), + io:format("Reading crashdump..."), + read_file(File), + redirect([],[]), + io:format("done\n"), + start_browser(Browser); + false -> + io:format("cdv error: the given file does not exist\n"), + usage() + end. + +start_browser(Browser) -> + PortStr = integer_to_list(gen_server:call(web_tool,get_port)), + Url = "http://localhost:" ++ PortStr ++ ?START_PAGE, + {OSType,_} = os:type(), + case Browser of + none -> + ok; + iexplore when OSType == win32-> + io:format("Starting internet explorer...\n"), + {ok,R} = win32reg:open(""), + Key="\\local_machine\\SOFTWARE\\Microsoft\\IE Setup\\Setup", + win32reg:change_key(R,Key), + {ok,Val} = win32reg:value(R,"Path"), + IExplore=filename:join(win32reg:expand(Val),"iexplore.exe"), + os:cmd("\"" ++ IExplore ++ "\" " ++ Url); + _ when OSType == win32 -> + io:format("Starting ~w...\n",[Browser]), + os:cmd("\"" ++ atom_to_list(Browser) ++ "\" " ++ Url); + B when B==firefox; B==mozilla -> + io:format("Sending URL to ~w...",[Browser]), + BStr = atom_to_list(Browser), + SendCmd = BStr ++ " -raise -remote \'openUrl(" ++ Url ++ ")\'", + Port = open_port({spawn,SendCmd},[exit_status]), + receive + {Port,{exit_status,0}} -> + io:format("done\n"); + {Port,{exit_status,_Error}} -> + io:format(" not running, starting ~w...\n",[Browser]), + os:cmd(BStr ++ " " ++ Url) + after 5000 -> + io:format(" failed, starting ~w...\n",[Browser]), + erlang:port_close(Port), + os:cmd(BStr ++ " " ++ Url) + end; + _ -> + io:format("Starting ~w...\n",[Browser]), + os:cmd(atom_to_list(Browser) ++ " " ++ Url) + end, + ok. + +usage() -> + io:format( + "\nusage: cdv file [ browser ]\n" + "\tThe \'file\' must be an existing erlang crash dump.\n" + "\tDefault browser is \'iexplore\' (Internet Explorer) on Windows\n" + "\tor else \'firefox\'.\n", + []). + + + + +%%%----------------------------------------------------------------- %%% Return config data used by webtool configData() -> Dir = filename:join(code:priv_dir(observer),"crashdump_viewer"), @@ -266,22 +374,24 @@ toggle(_Env,Input) -> %%% The following functions are called when menu items are clicked. general_info(_Env,_Input) -> call(general_info). -processes(_Env,_Input) -> - call(procs_summary). -ports(_Env,Input) -> % this is also called when a link to a port is clicked - call({ports,Input}). -ets_tables(_Env,Input) -> - call({ets_tables,Input}). -timers(_Env,Input) -> - call({timers,Input}). -fun_table(_Env,_Input) -> - call(funs). -atoms(_Env,_Input) -> - call(atoms). +processes(SessionId,_Env,_Input) -> + call({procs_summary,SessionId}). +ports(SessionId,_Env,_Input) -> + call({ports,SessionId}). +ets_tables(SessionId,_Env,Input) -> + call({ets_tables,SessionId,Input}). +internal_ets_tables(_Env,_Input) -> + call(internal_ets_tables). +timers(SessionId,_Env,Input) -> + call({timers,SessionId,Input}). +fun_table(SessionId,_Env,_Input) -> + call({funs,SessionId}). +atoms(SessionId,_Env,_Input) -> + call({atoms,SessionId}). dist_info(_Env,_Input) -> call(dist_info). -loaded_modules(_Env,_Input) -> - call(loaded_mods). +loaded_modules(SessionId,_Env,_Input) -> + call({loaded_mods,SessionId}). loaded_mod_details(_Env,Input) -> call({loaded_mod_details,Input}). memory(_Env,_Input) -> @@ -303,8 +413,13 @@ proc_details(_Env,Input) -> %%%----------------------------------------------------------------- %%% Called when one of the headings in the process summary table are %%% clicked. It sorts the processes by the clicked heading. -sort_procs(_Env,Input) -> - call({sort_procs,Input}). +sort_procs(SessionId,_Env,Input) -> + call({sort_procs,SessionId,Input}). + +%%%----------------------------------------------------------------- +%%% Called when a link to a port is clicked. +port(_Env,Input) -> + call({port,Input}). %%%----------------------------------------------------------------- %%% Called when the "Expand" link in a call stack (Last Calls) is @@ -325,11 +440,6 @@ expand_binary(_Env,Input) -> call({expand_binary,Input}). %%%----------------------------------------------------------------- -%%% Called when the "Next" link under atoms is clicked. -next(_Env,Input) -> - call({next,Input}). - -%%%----------------------------------------------------------------- %%% Called on regular intervals while waiting for a dump to be read redirect(_Env,_Input) -> call(redirect). @@ -348,7 +458,7 @@ redirect(_Env,_Input) -> %%-------------------------------------------------------------------- init([]) -> ets:new(cdv_menu_table,[set,named_table,{keypos,#menu_item.index},public]), - ets:new(cdv_dump_index_table,[bag,named_table,public]), + ets:new(cdv_dump_index_table,[ordered_set,named_table,public]), {ok, #state{}}. %%-------------------------------------------------------------------- @@ -373,16 +483,7 @@ handle_call(start_page, _From, State) -> Reply = crashdump_viewer_html:start_page(), {reply,Reply,State}; handle_call({read_file,Input}, _From, _State) -> - {ok,File0} = get_value("path",httpd:parse_query(Input)), - File = - case File0 of - [$"|FileAndSome] -> - %% Opera adds \"\" around the filename! - [$"|Elif] = lists:reverse(FileAndSome), - lists:reverse(Elif); - _ -> - File0 - end, + {ok,File} = get_value("path",httpd:parse_query(Input)), spawn_link(fun() -> read_file(File) end), Status = background_status(reading,File), Reply = crashdump_viewer_html:redirect(Status), @@ -399,8 +500,17 @@ handle_call(initial_info_frame,_From,State=#state{file=File}) -> GenInfo = general_info(File), NumAtoms = GenInfo#general_info.num_atoms, {WS,SH} = parse_vsn_str(GenInfo#general_info.system_vsn,4,false), + NumProcs = list_to_integer(GenInfo#general_info.num_procs), + ProcsSummary = + if NumProcs > ?max_sort_process_num -> too_many; + true -> State#state.procs_summary + end, + NewState = State#state{shared_heap=SH, + wordsize=WS, + num_atoms=NumAtoms, + procs_summary=ProcsSummary}, Reply = crashdump_viewer_html:general_info(GenInfo), - {reply,Reply,State#state{shared_heap=SH,wordsize=WS,num_atoms=NumAtoms}}; + {reply,Reply,NewState}; handle_call({toggle,Input},_From,State) -> {ok,Index} = get_value("index",httpd:parse_query(Input)), do_toggle(list_to_integer(Index)), @@ -429,7 +539,7 @@ handle_call({expand,Input},_From,State=#state{file=File}) -> handle_call({expand_memory,Input},_From,State=#state{file=File,binaries=B}) -> [{"pid",Pid},{"what",What}] = httpd:parse_query(Input), Reply = - case truncated_warning([{"=proc",Pid}]) of + case truncated_warning([{?proc,Pid}]) of [] -> Expanded = expand_memory(File,What,Pid,B), crashdump_viewer_html:expanded_memory(What,Expanded); @@ -450,149 +560,129 @@ handle_call({expand_binary,Input},_From,State=#state{file=File}) -> close(Fd), Reply=crashdump_viewer_html:expanded_binary(io_lib:format("~p",[Bin])), {reply,Reply,State}; -handle_call({next,Input},_From,State=#state{file=File}) -> - [{"pos",Pos},{"num",N},{"start",Start},{"what",What}] = - httpd:parse_query(Input), - Tags = related_tags(What), - TW = truncated_warning(Tags), - Next = get_next(File,list_to_integer(Pos),list_to_integer(N), - list_to_integer(Start),What), - Reply = crashdump_viewer_html:next(Next,TW), - {reply,Reply,State}; handle_call(general_info,_From,State=#state{file=File}) -> GenInfo=general_info(File), Reply = crashdump_viewer_html:general_info(GenInfo), {reply,Reply,State}; -handle_call(procs_summary,_From,State=#state{file=File,shared_heap=SH}) -> - ProcsSummary = - case State#state.procs_summary of - undefined -> procs_summary(File); - PS -> PS - end, - TW = truncated_warning(["=proc"]), - Reply = crashdump_viewer_html:procs_summary("pid",ProcsSummary,TW,SH), - {reply,Reply,State#state{procs_summary=ProcsSummary,sorted="pid"}}; -handle_call({sort_procs,Input}, _From, State=#state{shared_heap=SH}) -> +handle_call({procs_summary,SessionId},_From,State) -> + TW = truncated_warning([?proc]), + NewState = procs_summary(SessionId,TW,"pid",State#state{sorted=undefined}), + {reply,ok,NewState}; +handle_call({sort_procs,SessionId,Input}, _From, State) -> {ok,Sort} = get_value("sort",httpd:parse_query(Input)), - {ProcsSummary,Sorted} = do_sort_procs(Sort, - State#state.procs_summary, - State#state.sorted), - TW = truncated_warning(["=proc"]), - Reply = crashdump_viewer_html:procs_summary(Sort,ProcsSummary,TW,SH), - {reply,Reply,State#state{sorted=Sorted}}; + TW = truncated_warning([?proc]), + NewState = procs_summary(SessionId,TW,Sort,State), + {reply,ok,NewState}; handle_call({proc_details,Input},_From,State=#state{file=File,shared_heap=SH}) -> {ok,Pid} = get_value("pid",httpd:parse_query(Input)), Reply = case get_proc_details(File,Pid) of {ok,Proc} -> - TW = truncated_warning([{"=proc",Pid}]), + TW = truncated_warning([{?proc,Pid}]), crashdump_viewer_html:proc_details(Pid,Proc,TW,SH); {other_node,Node} -> - TW = truncated_warning(["=visible_node", - "=hidden_node", - "=not_connected"]), + TW = truncated_warning([?visible_node, + ?hidden_node, + ?not_connected]), crashdump_viewer_html:nods(Node,TW); not_found -> crashdump_viewer_html:info_page(["Could not find process: ", Pid],?space) end, {reply, Reply, State}; -handle_call({ports,Input},_From,State=#state{file=File}) -> +handle_call({port,Input},_From,State=#state{file=File}) -> + {ok,P} = get_value("port",httpd:parse_query(Input)), + Id = [$#|P], Reply = - case get_value("port",httpd:parse_query(Input)) of - {ok,P} -> - Id = [$#|P], - case get_port(File,Id) of - {ok,PortInfo} -> - TW = truncated_warning([{"=port",Id}]), - crashdump_viewer_html:ports(Id,[PortInfo],TW); - {other_node,Node} -> - TW = truncated_warning(["=visible_node", - "=hidden_node", - "=not_connected"]), - crashdump_viewer_html:nods(Node,TW); - not_found -> - crashdump_viewer_html:info_page( - ["Could not find port: ",Id],?space) - end; - error -> % no port identity in Input - get all ports - Ports=get_ports(File), - TW = truncated_warning(["=port"]), - crashdump_viewer_html:ports("Port Information",Ports,TW) + case get_port(File,Id) of + {ok,PortInfo} -> + TW = truncated_warning([{?port,Id}]), + crashdump_viewer_html:port(Id,PortInfo,TW); + {other_node,Node} -> + TW = truncated_warning([?visible_node, + ?hidden_node, + ?not_connected]), + crashdump_viewer_html:nods(Node,TW); + not_found -> + crashdump_viewer_html:info_page( + ["Could not find port: ",Id],?space) end, {reply,Reply,State}; -handle_call({ets_tables,Input},_From,State=#state{file=File,wordsize=WS}) -> - {Pid,Heading,InternalEts} = +handle_call({ports,SessionId},_From,State=#state{file=File}) -> + TW = truncated_warning([?port]), + get_ports(SessionId,File,TW), + {reply,ok,State}; +handle_call({ets_tables,SessionId,Input},_From,State=#state{file=File,wordsize=WS}) -> + {Pid,Heading} = case get_value("pid",httpd:parse_query(Input)) of {ok,P} -> - {P,["ETS Tables for Process ",P],[]}; + {P,["ETS Tables for Process ",P]}; error -> - I = get_internal_ets_tables(File,WS), - {'_',"ETS Table Information",I} + {'$2',"ETS Table Information"} end, - EtsTables = get_ets_tables(File,Pid,WS), - TW = truncated_warning(["=ets"]), - Reply = crashdump_viewer_html:ets_tables(Heading,EtsTables,InternalEts,TW), + TW = truncated_warning([?ets]), + get_ets_tables(SessionId,File,Heading,TW,Pid,WS), + {reply,ok,State}; +handle_call(internal_ets_tables,_From,State=#state{file=File,wordsize=WS}) -> + InternalEts = get_internal_ets_tables(File,WS), + TW = truncated_warning([?internal_ets]), + Reply = crashdump_viewer_html:internal_ets_tables(InternalEts,TW), {reply,Reply,State}; -handle_call({timers,Input},_From,State=#state{file=File}) -> +handle_call({timers,SessionId,Input},_From,State=#state{file=File}) -> {Pid,Heading} = case get_value("pid",httpd:parse_query(Input)) of {ok,P} -> {P,["Timers for Process ",P]}; - error -> {'_',"Timer Information"} + error -> {'$2',"Timer Information"} end, - Timers=get_timers(File,Pid), - TW = truncated_warning(["=timer"]), - Reply = crashdump_viewer_html:timers(Heading,Timers,TW), - {reply,Reply,State}; + TW = truncated_warning([?timer]), + get_timers(SessionId,File,Heading,TW,Pid), + {reply,ok,State}; handle_call(dist_info,_From,State=#state{file=File}) -> Nods=nods(File), - TW = truncated_warning(["=visible_node","=hidden_node","=not_connected"]), + TW = truncated_warning([?visible_node,?hidden_node,?not_connected]), Reply = crashdump_viewer_html:nods(Nods,TW), {reply,Reply,State}; -handle_call(loaded_mods,_From,State=#state{file=File}) -> - LoadedMods=loaded_mods(File), - TW = truncated_warning(["=mod"]), - Reply = crashdump_viewer_html:loaded_mods(LoadedMods,TW), - {reply,Reply,State}; +handle_call({loaded_mods,SessionId},_From,State=#state{file=File}) -> + TW = truncated_warning([?mod]), + loaded_mods(SessionId,File,TW), + {reply,ok,State}; handle_call({loaded_mod_details,Input},_From,State=#state{file=File}) -> {ok,Mod} = get_value("mod",httpd:parse_query(Input)), ModInfo = get_loaded_mod_details(File,Mod), - TW = truncated_warning([{"=mod",Mod}]), + TW = truncated_warning([{?mod,Mod}]), Reply = crashdump_viewer_html:loaded_mod_details(ModInfo,TW), {reply,Reply,State}; -handle_call(funs,_From,State=#state{file=File}) -> - Funs=funs(File), - TW = truncated_warning(["=fun"]), - Reply = crashdump_viewer_html:funs(Funs,TW), - {reply,Reply,State}; -handle_call(atoms,_From,State=#state{file=File,num_atoms=Num}) -> - Atoms=atoms(File), - TW = truncated_warning(["=atoms","=num_atoms"]), - Reply = crashdump_viewer_html:atoms(Atoms,Num,TW), - {reply,Reply,State}; +handle_call({funs,SessionId},_From,State=#state{file=File}) -> + TW = truncated_warning([?fu]), + funs(SessionId,File,TW), + {reply,ok,State}; +handle_call({atoms,SessionId},_From,State=#state{file=File,num_atoms=Num}) -> + TW = truncated_warning([?atoms,?num_atoms]), + atoms(SessionId,File,TW,Num), + {reply,ok,State}; handle_call(memory,_From,State=#state{file=File}) -> Memory=memory(File), - TW = truncated_warning(["=memory"]), + TW = truncated_warning([?memory]), Reply = crashdump_viewer_html:memory(Memory,TW), {reply,Reply,State}; handle_call(allocated_areas,_From,State=#state{file=File}) -> AllocatedAreas=allocated_areas(File), - TW = truncated_warning(["=allocated_areas"]), + TW = truncated_warning([?allocated_areas]), Reply = crashdump_viewer_html:allocated_areas(AllocatedAreas,TW), {reply,Reply,State}; handle_call(allocator_info,_From,State=#state{file=File}) -> SlAlloc=allocator_info(File), - TW = truncated_warning(["=allocator"]), + TW = truncated_warning([?allocator]), Reply = crashdump_viewer_html:allocator_info(SlAlloc,TW), {reply,Reply,State}; handle_call(hash_tables,_From,State=#state{file=File}) -> HashTables=hash_tables(File), - TW = truncated_warning(["=hash_table","=index_table"]), + TW = truncated_warning([?hash_table,?index_table]), Reply = crashdump_viewer_html:hash_tables(HashTables,TW), {reply,Reply,State}; handle_call(index_tables,_From,State=#state{file=File}) -> IndexTables=index_tables(File), - TW = truncated_warning(["=hash_table","=index_table"]), + TW = truncated_warning([?hash_table,?index_table]), Reply = crashdump_viewer_html:index_tables(IndexTables,TW), {reply,Reply,State}. @@ -682,9 +772,9 @@ truncated_here(Tag) -> %% Check if the dump was truncated with the same tag, but earlier id. -%% Eg if this is {"=proc","<0.30.0>"}, we should warn if the dump was -%% truncated in {"=proc","<0.29.0>"} or earlier -truncated_earlier({"=proc",Pid}) -> +%% Eg if this is {?proc,"<0.30.0>"}, we should warn if the dump was +%% truncated in {?proc,"<0.29.0>"} or earlier +truncated_earlier({?proc,Pid}) -> compare_pid(Pid,get(truncated_proc)); truncated_earlier(_Tag) -> false. @@ -718,9 +808,37 @@ open(File) -> close(Fd) -> erase(chunk), file:close(Fd). + +%% Set position relative to beginning of file +%% If position is within the already read Chunk, then adjust 'chunk' +%% and 'pos' in process dictionary. Else set position in file. pos_bof(Fd,Pos) -> + case get(pos) of + undefined -> + hard_pos_bof(Fd,Pos); + OldPos when Pos>=OldPos -> + case get(chunk) of + undefined -> + hard_pos_bof(Fd,Pos); + Chunk -> + ChunkSize = byte_size(Chunk), + ChunkEnd = OldPos+ChunkSize, + if Pos=<ChunkEnd -> + Diff = Pos-OldPos, + put(pos,Pos), + put(chunk,binary:part(Chunk,Diff,ChunkEnd-Pos)); + true -> + hard_pos_bof(Fd,Pos) + end + end; + _ -> + hard_pos_bof(Fd,Pos) + end. + +hard_pos_bof(Fd,Pos) -> reset_chunk(), - file:position(Fd,{bof,Pos}). + file:position(Fd,{bof,Pos}). + get_chunk(Fd) -> case erase(chunk) of @@ -979,7 +1097,9 @@ initial_menu() -> [menu_item(0, {"./general_info","General information"},0), menu_item(0, {"./processes","Processes"}, 0), menu_item(0, {"./ports","Ports"}, 0), - menu_item(0, {"./ets_tables","ETS tables"}, 0), + menu_item(2, "ETS tables", 0), + menu_item(0, {"./ets_tables","ETS tables"}, 1), + menu_item(0, {"./internal_ets_tables","Internal ETS tables"}, 1), menu_item(0, {"./timers","Timers"}, 0), menu_item(0, {"./fun_table","Fun table"}, 0), menu_item(0, {"./atoms","Atoms"}, 0), @@ -1066,9 +1186,9 @@ read_file(File) -> {ok,<<$=:8,TagAndRest/binary>>} -> {Tag,Id,Rest,N1} = tag(Fd,TagAndRest,1), case Tag of - "=erl_crash_dump" -> - ets:delete_all_objects(cdv_dump_index_table), - ets:insert(cdv_dump_index_table,{Tag,Id,N1+1}), + ?erl_crash_dump -> + reset_index_table(), + insert_index(Tag,Id,N1+1), put(last_tag,{Tag,""}), Status = background_status(processing,File), background_status(Status), @@ -1107,34 +1227,35 @@ read_file(File) -> background_done({R,undefined,undefined}) end. -indexify(Fd,<<"\n=",TagAndRest/binary>>,N) -> - {Tag,Id,Rest,N1} = tag(Fd,TagAndRest,N+2), - ets:insert(cdv_dump_index_table,{Tag,Id,N1+1}), % +1 to get past newline - put(last_tag,{Tag,Id}), - indexify(Fd,Rest,N1); -indexify(Fd,<<>>,N) -> - case read(Fd) of - {ok,Chunk} when is_binary(Chunk) -> - indexify(Fd,Chunk,N); - eof -> - eof - end; -indexify(Fd,<<$\n>>,N) -> - %% This clause is needed in case the chunk ends with a newline and - %% the next chunk starts with a tag (i.e. "\n=....") - case read(Fd) of - {ok,Chunk} when is_binary(Chunk) -> - indexify(Fd,<<$\n,Chunk/binary>>,N); - eof -> - eof - end; -indexify(Fd,<<_Char:8,Rest/binary>>,N) -> - indexify(Fd,Rest,N+1). +indexify(Fd,Bin,N) -> + case binary:match(Bin,<<"\n=">>) of + {Start,Len} -> + Pos = Start+Len, + <<_:Pos/binary,TagAndRest/binary>> = Bin, + {Tag,Id,Rest,N1} = tag(Fd,TagAndRest,N+Pos), + insert_index(Tag,Id,N1+1), % +1 to get past newline + put(last_tag,{Tag,Id}), + indexify(Fd,Rest,N1); + nomatch -> + case read(Fd) of + {ok,Chunk0} when is_binary(Chunk0) -> + {Chunk,N1} = + case binary:last(Bin) of + $\n -> + {<<$\n,Chunk0/binary>>,N+byte_size(Bin)-1}; + _ -> + {Chunk0,N+byte_size(Bin)} + end, + indexify(Fd,Chunk,N1); + eof -> + eof + end + end. tag(Fd,Bin,N) -> tag(Fd,Bin,N,[],[],tag). tag(_Fd,<<$\n:8,_/binary>>=Rest,N,Gat,Di,_Now) -> - {[$=|lists:reverse(Gat)],lists:reverse(Di),Rest,N}; + {tag_to_atom(lists:reverse(Gat)),lists:reverse(Di),Rest,N}; tag(Fd,<<$\r:8,Rest/binary>>,N,Gat,Di,Now) -> tag(Fd,Rest,N+1,Gat,Di,Now); tag(Fd,<<$::8,IdAndRest/binary>>,N,Gat,Di,tag) -> @@ -1148,12 +1269,12 @@ tag(Fd,<<>>,N,Gat,Di,Now) -> {ok,Chunk} when is_binary(Chunk) -> tag(Fd,Chunk,N,Gat,Di,Now); eof -> - {[$=|lists:reverse(Gat)],lists:reverse(Di),<<>>,N} + {tag_to_atom(lists:reverse(Gat)),lists:reverse(Di),<<>>,N} end. check_if_truncated() -> case get(last_tag) of - {"=end",_} -> + {?ende,_} -> put(truncated,false), put(truncated_proc,false); TruncatedTag -> @@ -1161,32 +1282,29 @@ check_if_truncated() -> find_truncated_proc(TruncatedTag) end. -find_truncated_proc({"=atom",_Id}) -> +find_truncated_proc({?atoms,_Id}) -> put(truncated_proc,false); find_truncated_proc({Tag,Pid}) -> case is_proc_tag(Tag) of true -> put(truncated_proc,Pid); false -> - %% This means that the dump is truncated between "=proc" and - %% "=proc_heap" => memory info is missing for all procs. + %% This means that the dump is truncated between ?proc and + %% ?proc_heap => memory info is missing for all procs. put(truncated_proc,"<0.0.0>") end. -is_proc_tag(Tag) when Tag=="=proc"; - Tag=="=proc_dictionary"; - Tag=="=proc_messages"; - Tag=="=proc_dictionary"; - Tag=="=debug_proc_dictionary"; - Tag=="=proc_stack"; - Tag=="=proc_heap" -> +is_proc_tag(Tag) when Tag==?proc; + Tag==?proc_dictionary; + Tag==?proc_messages; + Tag==?proc_dictionary; + Tag==?debug_proc_dictionary; + Tag==?proc_stack; + Tag==?proc_heap -> true; is_proc_tag(_) -> false. -related_tags("Atoms") -> - ["=atoms","=num_atoms"]. - %%% Inform the crashdump_viewer_server that a background job is completed. background_done(Result) -> Dict = get(), @@ -1198,8 +1316,7 @@ background_status(Status) -> %%%----------------------------------------------------------------- %%% Functions for reading information from the dump general_info(File) -> - [{"=erl_crash_dump",_Id,Start}] = - ets:lookup(cdv_dump_index_table,"=erl_crash_dump"), + [{_Id,Start}] = lookup_index(?erl_crash_dump), Fd = open(File), pos_bof(Fd,Start), Created = case get_rest_of_line(Fd) of @@ -1207,15 +1324,15 @@ general_info(File) -> WholeLine -> WholeLine end, - GI0 = get_general_info(Fd,#general_info{created=Created,_=?space}), + GI0 = get_general_info(Fd,#general_info{created=Created}), GI = case GI0#general_info.num_atoms of ?space -> GI0#general_info{num_atoms=get_num_atoms(Fd)}; _ -> GI0 end, {MemTot,MemMax} = - case ets:lookup(cdv_dump_index_table,"=memory") of - [{"=memory",_,MemStart}] -> + case lookup_index(?memory) of + [{_,MemStart}] -> pos_bof(Fd,MemStart), Memory = get_meminfo(Fd,[]), Tot = case lists:keysearch("total",1,Memory) of @@ -1232,33 +1349,34 @@ general_info(File) -> end, close(Fd), - {NumProcs,NumEts,NumFuns} = count(), + {NumProcs,NumEts,NumFuns,NumTimers} = count(), NodeName = - case ets:lookup(cdv_dump_index_table,"=node") of - [{"=node",N,_Start}] -> + case lookup_index(?node) of + [{N,_Start}] -> N; [] -> - case ets:lookup(cdv_dump_index_table,"=no_distribution") of + case lookup_index(?no_distribution) of [_] -> "nonode@nohost"; [] -> "unknown" end end, InstrInfo = - case ets:member(cdv_dump_index_table,"=old_instr_data") of - true -> - old_instr_data; - false -> - case ets:member(cdv_dump_index_table,"=instr_data") of - true -> - instr_data; - false -> - false - end + case lookup_index(?old_instr_data) of + [] -> + case lookup_index(?instr_data) of + [] -> + false; + _ -> + instr_data + end; + _ -> + old_instr_data end, GI#general_info{node_name=NodeName, num_procs=integer_to_list(NumProcs), num_ets=integer_to_list(NumEts), + num_timers=integer_to_list(NumTimers), num_fun=integer_to_list(NumFuns), mem_tot=MemTot, mem_max=MemMax, @@ -1285,8 +1403,8 @@ get_general_info(Fd,GenInfo) -> end. get_num_atoms(Fd) -> - case ets:match(cdv_dump_index_table,{"=hash_table","atom_tab",'$1'}) of - [[Pos]] -> + case lookup_index(?hash_table,"atom_tab") of + [{_,Pos}] -> pos_bof(Fd,Pos), skip_rest_of_line(Fd), % size skip_rest_of_line(Fd), % used @@ -1300,10 +1418,10 @@ get_num_atoms(Fd) -> get_num_atoms2() end. get_num_atoms2() -> - case ets:lookup(cdv_dump_index_table,"=num_atoms") of + case lookup_index(?num_atoms) of [] -> ?space; - [{"=num_atoms",NA,_Pos}] -> + [{NA,_Pos}] -> %% If dump is translated this will exist case get(truncated) of true -> @@ -1314,43 +1432,70 @@ get_num_atoms2() -> end. count() -> - {ets:select_count(cdv_dump_index_table,count_ms("=proc")), - ets:select_count(cdv_dump_index_table,count_ms("=ets")), - ets:select_count(cdv_dump_index_table,count_ms("=fun"))}. + {count_index(?proc),count_index(?ets),count_index(?fu),count_index(?timer)}. -count_ms(Tag) -> - [{{Tag,'_','_'},[],[true]}]. +%%----------------------------------------------------------------- +%% Page with all processes +%% +%% If there are less than ?max_sort_process_num processes in the dump, +%% we will store the list of processes in the server state in order to +%% allow sorting according to the different columns of the +%% table. Since ?max_sort_process_num=:=?items_chunk_size, there will +%% never be more than one chunk in this case. +%% +%% If there are more than ?max_sort_process_num processes in the dump, +%% no sorting will be allowed, and the processes must be read (chunk +%% by chunk) from the file each time the page is opened. This is to +%% avoid really big data in the server state. +procs_summary(SessionId,TW,_,State=#state{procs_summary=too_many}) -> + chunk_page(SessionId,State#state.file,TW,?proc,processes, + {no_sort,State#state.shared_heap},procs_summary_parsefun()), + State; +procs_summary(SessionId,TW,SortOn,State) -> + ProcsSummary = + case State#state.procs_summary of + undefined -> % first time - read from file + Fd = open(State#state.file), + {PS,_}=lookup_and_parse_index_chunk(first_chunk_pointer(?proc), + Fd,procs_summary_parsefun()), + close(Fd), + PS; + PS -> + PS + end, + {SortedPS,NewSorted} = do_sort_procs(SortOn,ProcsSummary,State#state.sorted), + HtmlInfo = + crashdump_viewer_html:chunk_page(processes,SessionId,TW, + {SortOn,State#state.shared_heap}, + SortedPS), + crashdump_viewer_html:chunk(SessionId,done,HtmlInfo), + State#state{procs_summary=ProcsSummary,sorted=NewSorted}. -procs_summary(File) -> - AllProcs = ets:lookup(cdv_dump_index_table,"=proc"), - Fd = open(File), - R = lists:map(fun({"=proc",Pid,Start}) -> - pos_bof(Fd,Start), - get_procinfo(Fd,fun main_procinfo/4, - ?initial_proc_record(Pid)) - end, - AllProcs), - close(Fd), - R. +procs_summary_parsefun() -> + fun(Fd,Pid) -> + get_procinfo(Fd,fun main_procinfo/4,#proc{pid=Pid}) + end. +%%----------------------------------------------------------------- +%% Page with one process get_proc_details(File,Pid) -> - DumpVsn = ets:lookup_element(cdv_dump_index_table,"=erl_crash_dump",2), - case ets:match(cdv_dump_index_table,{"=proc",Pid,'$1'}) of - [[Start]] -> + [{DumpVsn,_}] = lookup_index(?erl_crash_dump), + case lookup_index(?proc,Pid) of + [{_,Start}] -> Fd = open(File), pos_bof(Fd,Start), Proc0 = case DumpVsn of "0.0" -> %% Old version (translated) - ?initial_proc_record(Pid); + #proc{pid=Pid}; _ -> - (?initial_proc_record(Pid))#proc{ - stack_dump=if_exist("=proc_stack",Pid), - msg_q=if_exist("=proc_messages",Pid), - dict=if_exist("=proc_dictionary",Pid), - debug_dict=if_exist("=debug_proc_dictionary",Pid)} + #proc{pid=Pid, + stack_dump=if_exist(?proc_stack,Pid), + msg_q=if_exist(?proc_messages,Pid), + dict=if_exist(?proc_dictionary,Pid), + debug_dict=if_exist(?debug_proc_dictionary,Pid)} end, Proc = get_procinfo(Fd,fun all_procinfo/4,Proc0), close(Fd), @@ -1368,11 +1513,11 @@ get_proc_details(File,Pid) -> end. if_exist(Tag,Key) -> - case ets:select_count(cdv_dump_index_table,[{{Tag,Key,'_'},[],[true]}]) of + case count_index(Tag,Key) of 0 -> Tag1 = case is_proc_tag(Tag) of - true -> "=proc"; + true -> ?proc; false -> Tag end, case truncated_here({Tag1,Key}) of @@ -1523,13 +1668,14 @@ maybe_other_node(File,Id) -> N end, Ms = ets:fun2ms( - fun({Tag,Id,Start}) when Tag=:="=visible_node", Id=:=Channel -> + fun({{Tag,Start},Ch}) when Tag=:=?visible_node, Ch=:=Channel -> {"Visible Node",Start}; - ({Tag,Id,Start}) when Tag=:="=hidden_node", Id=:=Channel -> + ({{Tag,Start},Ch}) when Tag=:=?hidden_node, Ch=:=Channel -> {"Hidden Node",Start}; - ({Tag,Id,Start}) when Tag=:="=not_connected", Id=:=Channel -> + ({{Tag,Start},Ch}) when Tag=:=?not_connected, Ch=:=Channel -> {"Not Connected Node",Start} end), + case ets:select(cdv_dump_index_table,Ms) of [] -> not_found; @@ -1540,6 +1686,7 @@ maybe_other_node(File,Id) -> {other_node,Type,NodeInfo} end. + expand_memory(File,What,Pid,Binaries) -> Fd = open(File), put(fd,Fd), @@ -1548,8 +1695,8 @@ expand_memory(File,What,Pid,Binaries) -> case What of "StackDump" -> read_stack_dump(Fd,Pid,Dict); "MsgQueue" -> read_messages(Fd,Pid,Dict); - "Dictionary" -> read_dictionary(Fd,"=proc_dictionary",Pid,Dict); - "DebugDictionary" -> read_dictionary(Fd,"=debug_proc_dictionary",Pid,Dict) + "Dictionary" -> read_dictionary(Fd,?proc_dictionary,Pid,Dict); + "DebugDictionary" -> read_dictionary(Fd,?debug_proc_dictionary,Pid,Dict) end, erase(fd), close(Fd), @@ -1559,10 +1706,10 @@ expand_memory(File,What,Pid,Binaries) -> %%% Read binaries. %%% read_binaries(Fd) -> - AllBinaries = ets:match(cdv_dump_index_table,{"=binary",'$1','$2'}), + AllBinaries = lookup_index(?binary), read_binaries(Fd,AllBinaries, gb_trees:empty()). -read_binaries(Fd,[[Addr0,Pos]|Bins],Dict0) -> +read_binaries(Fd,[{Addr0,Pos}|Bins],Dict0) -> pos_bof(Fd,Pos), {Addr,_} = get_hex(Addr0), Dict = @@ -1603,15 +1750,15 @@ parse_binary(Addr, Line0, Dict) -> %%% read_stack_dump(Fd,Pid,Dict) -> - case ets:match(cdv_dump_index_table,{"=proc_stack",Pid,'$1'}) of - [[Start]] -> + case lookup_index(?proc_stack,Pid) of + [{_,Start}] -> pos_bof(Fd,Start), read_stack_dump1(Fd,Dict,[]); [] -> [] end. read_stack_dump1(Fd,Dict,Acc) -> - %% This function is never called if the dump is truncated in "=proc_heap:Pid" + %% This function is never called if the dump is truncated in {?proc_heap,Pid} case val(Fd) of "=" ++ _next_tag -> lists:reverse(Acc); @@ -1631,15 +1778,15 @@ parse_top(Line0, D) -> %%% read_messages(Fd,Pid,Dict) -> - case ets:match(cdv_dump_index_table,{"=proc_messages",Pid,'$1'}) of - [[Start]] -> + case lookup_index(?proc_messages,Pid) of + [{_,Start}] -> pos_bof(Fd,Start), read_messages1(Fd,Dict,[]); [] -> [] end. read_messages1(Fd,Dict,Acc) -> - %% This function is never called if the dump is truncated in "=proc_heap:Pid" + %% This function is never called if the dump is truncated in {?proc_heap,Pid} case val(Fd) of "=" ++ _next_tag -> lists:reverse(Acc); @@ -1659,15 +1806,15 @@ parse_message(Line0, D) -> %%% read_dictionary(Fd,Tag,Pid,Dict) -> - case ets:match(cdv_dump_index_table,{Tag,Pid,'$1'}) of - [[Start]] -> + case lookup_index(Tag,Pid) of + [{_,Start}] -> pos_bof(Fd,Start), read_dictionary1(Fd,Dict,[]); [] -> [] end. read_dictionary1(Fd,Dict,Acc) -> - %% This function is never called if the dump is truncated in "=proc_heap:Pid" + %% This function is never called if the dump is truncated in {?proc_heap,Pid} case val(Fd) of "=" ++ _next_tag -> lists:reverse(Acc); @@ -1686,8 +1833,8 @@ parse_dictionary(Line0, D) -> %%% read_heap(Fd,Pid,Dict0) -> - case ets:match(cdv_dump_index_table,{"=proc_heap",Pid,'$2'}) of - [[Pos]] -> + case lookup_index(?proc_heap,Pid) of + [{_,Pos}] -> pos_bof(Fd,Pos), read_heap(Dict0); [] -> @@ -1695,7 +1842,7 @@ read_heap(Fd,Pid,Dict0) -> end. read_heap(Dict0) -> - %% This function is never called if the dump is truncated in "=proc_heap:Pid" + %% This function is never called if the dump is truncated in {?proc_heap,Pid} case get(fd) of end_of_heap -> Dict0; @@ -1761,12 +1908,14 @@ do_sort_procs("name",Procs,Sorted) -> _ -> {Result,"name"} end. - +%%----------------------------------------------------------------- +%% Page with one port get_port(File,Port) -> - case ets:match(cdv_dump_index_table,{"=port",Port,'$1'}) of - [[Start]] -> + case lookup_index(?port,Port) of + [{_,Start}] -> Fd = open(File), - R = get_portinfo(Fd,Port,Start), + pos_bof(Fd,Start), + R = get_portinfo(Fd,#port{id=Port}), close(Fd), {ok,R}; [] -> @@ -1781,18 +1930,11 @@ get_port(File,Port) -> end end. -get_ports(File) -> - Ports = ets:lookup(cdv_dump_index_table,"=port"), - Fd = open(File), - R = lists:map(fun({"=port",Id,Start}) -> get_portinfo(Fd,Id,Start) end, - Ports), - close(Fd), - R. - - -get_portinfo(Fd,Id,Start) -> - pos_bof(Fd,Start), - get_portinfo(Fd,#port{id=Id,_=?space}). +%%----------------------------------------------------------------- +%% Page with all ports +get_ports(SessionId,File,TW) -> + ParseFun = fun(Fd,Id) -> get_portinfo(Fd,#port{id=Id}) end, + chunk_page(SessionId,File,TW,?port,ports,[],ParseFun). get_portinfo(Fd,Port) -> case line_head(Fd) of @@ -1802,6 +1944,10 @@ get_portinfo(Fd,Port) -> get_portinfo(Fd,Port#port{connected=val(Fd)}); "Links" -> get_portinfo(Fd,Port#port{links=val(Fd)}); + "Registered as" -> + get_portinfo(Fd,Port#port{name=val(Fd)}); + "Monitors" -> + get_portinfo(Fd,Port#port{monitors=val(Fd)}); "Port controls linked-in driver" -> get_portinfo(Fd,Port#port{controls=["Linked in driver: " | val(Fd)]}); @@ -1820,30 +1966,12 @@ get_portinfo(Fd,Port) -> Port end. -get_ets_tables(File,Pid,WS) -> - EtsTables = ets:match_object(cdv_dump_index_table,{"=ets",Pid,'_'}), - Fd = open(File), - R = lists:map(fun({"=ets",P,Start}) -> - get_etsinfo(Fd,P,Start,WS) - end, - EtsTables), - close(Fd), - R. -get_internal_ets_tables(File,WS) -> - InternalEts = ets:match_object(cdv_dump_index_table, - {"=internal_ets",'_','_'}), - Fd = open(File), - R = lists:map(fun({"=internal_ets",Descr,Start}) -> - {Descr,get_etsinfo(Fd,undefined,Start,WS)} - end, - InternalEts), - close(Fd), - R. - -get_etsinfo(Fd,Pid,Start,WS) -> - pos_bof(Fd,Start), - get_etsinfo(Fd,#ets_table{pid=Pid,type="hash",_=?space},WS). +%%----------------------------------------------------------------- +%% Page with external ets tables +get_ets_tables(SessionId,File,Heading,TW,Pid,WS) -> + ParseFun = fun(Fd,Id) -> get_etsinfo(Fd,#ets_table{pid=Id},WS) end, + chunk_page(SessionId,File,TW,{?ets,Pid},ets_tables,Heading,ParseFun). get_etsinfo(Fd,EtsTable,WS) -> case line_head(Fd) of @@ -1875,26 +2003,32 @@ get_etsinfo(Fd,EtsTable,WS) -> EtsTable end. -get_timers(File,Pid) -> - Timers = ets:match_object(cdv_dump_index_table,{"=timer",Pid,'$1'}), + +%% Internal ets table page +get_internal_ets_tables(File,WS) -> + InternalEts = lookup_index(?internal_ets), Fd = open(File), - R = lists:map(fun({"=timer",P,Start}) -> - get_timerinfo(Fd,P,Start) - end, - Timers), + R = lists:map( + fun({Descr,Start}) -> + pos_bof(Fd,Start), + {Descr,get_etsinfo(Fd,#ets_table{},WS)} + end, + InternalEts), close(Fd), R. -get_timerinfo(Fd,Pid,Start) -> - pos_bof(Fd,Start), - get_timerinfo(Fd,#timer{pid=Pid,_=?space}). +%%----------------------------------------------------------------- +%% Page with list of all timers +get_timers(SessionId,File,Heading,TW,Pid) -> + ParseFun = fun(Fd,Id) -> get_timerinfo_1(Fd,#timer{pid=Id}) end, + chunk_page(SessionId,File,TW,{?timer,Pid},timers,Heading,ParseFun). -get_timerinfo(Fd,Timer) -> +get_timerinfo_1(Fd,Timer) -> case line_head(Fd) of "Message" -> - get_timerinfo(Fd,Timer#timer{msg=val(Fd)}); + get_timerinfo_1(Fd,Timer#timer{msg=val(Fd)}); "Time left" -> - get_timerinfo(Fd,Timer#timer{time=val(Fd)}); + get_timerinfo_1(Fd,Timer#timer{time=val(Fd)}); "=" ++ _next_tag -> Timer; Other -> @@ -1902,25 +2036,27 @@ get_timerinfo(Fd,Timer) -> Timer end. +%%----------------------------------------------------------------- +%% Page with information about the erlang distribution nods(File) -> - case ets:lookup(cdv_dump_index_table,"=no_distribution") of + case lookup_index(?no_distribution) of [] -> - V = ets:lookup(cdv_dump_index_table,"=visible_node"), - H = ets:lookup(cdv_dump_index_table,"=hidden_node"), - N = ets:lookup(cdv_dump_index_table,"=not_connected"), + V = lookup_index(?visible_node), + H = lookup_index(?hidden_node), + N = lookup_index(?not_connected), Fd = open(File), Visible = lists:map( - fun({"=visible_node",Channel,Start}) -> + fun({Channel,Start}) -> get_nodeinfo(Fd,Channel,Start) end, V), Hidden = lists:map( - fun({"=hidden_node",Channel,Start}) -> + fun({Channel,Start}) -> get_nodeinfo(Fd,Channel,Start) end, H), NotConnected = lists:map( - fun({"=not_connected",Channel,Start}) -> + fun({Channel,Start}) -> get_nodeinfo(Fd,Channel,Start) end, N), @@ -1932,7 +2068,7 @@ nods(File) -> get_nodeinfo(Fd,Channel,Start) -> pos_bof(Fd,Start), - get_nodeinfo(Fd,#nod{channel=Channel,_=?space}). + get_nodeinfo(Fd,#nod{channel=Channel}). get_nodeinfo(Fd,Nod) -> case line_head(Fd) of @@ -1963,26 +2099,37 @@ get_nodeinfo(Fd,Nod) -> Nod end. -loaded_mods(File) -> - case ets:lookup(cdv_dump_index_table,"=loaded_modules") of - [{"=loaded_modules",_,StartTotal}] -> - Fd = open(File), - pos_bof(Fd,StartTotal), - {CC,OC} = get_loaded_mod_totals(Fd,{"unknown","unknown"}), - - Mods = ets:lookup(cdv_dump_index_table,"=mod"), - LM = lists:map(fun({"=mod",M,Start}) -> - pos_bof(Fd,Start), - InitLM = #loaded_mod{mod=M,_=?space}, - get_loaded_mod_info(Fd,InitLM, - fun main_modinfo/3) - end, - Mods), - close(Fd), - {CC,OC,LM}; - [] -> - {"unknown","unknown",[]} - end. +%%----------------------------------------------------------------- +%% Page with details about one loaded modules +get_loaded_mod_details(File,Mod) -> + [{_,Start}] = lookup_index(?mod,Mod), + Fd = open(File), + pos_bof(Fd,Start), + InitLM = #loaded_mod{mod=Mod,old_size="No old code exists"}, + ModInfo = get_loaded_mod_info(Fd,InitLM,fun all_modinfo/3), + close(Fd), + ModInfo. + +%%----------------------------------------------------------------- +%% Page with list of all loaded modules +loaded_mods(SessionId,File,TW) -> + ParseFun = + fun(Fd,Id) -> + get_loaded_mod_info(Fd,#loaded_mod{mod=Id}, + fun main_modinfo/3) + end, + {CC,OC} = + case lookup_index(?loaded_modules) of + [{_,StartTotal}] -> + Fd = open(File), + pos_bof(Fd,StartTotal), + R = get_loaded_mod_totals(Fd,{"unknown","unknown"}), + close(Fd), + R; + [] -> + {"unknown","unknown"} + end, + chunk_page(SessionId,File,TW,?mod,loaded_mods,{CC,OC},ParseFun). get_loaded_mod_totals(Fd,{CC,OC}) -> case line_head(Fd) of @@ -1997,16 +2144,6 @@ get_loaded_mod_totals(Fd,{CC,OC}) -> {CC,OC} % truncated file end. -get_loaded_mod_details(File,Mod) -> - [[Start]] = ets:match(cdv_dump_index_table,{"=mod",Mod,'$1'}), - Fd = open(File), - pos_bof(Fd,Start), - InitLM = #loaded_mod{mod=Mod,old_size="No old code exists", - _="No information available"}, - ModInfo = get_loaded_mod_info(Fd,InitLM,fun all_modinfo/3), - close(Fd), - ModInfo. - get_loaded_mod_info(Fd,LM,Fun) -> case line_head(Fd) of "Current size" -> @@ -2073,39 +2210,26 @@ hex_to_dec("A") -> 10; hex_to_dec(N) -> list_to_integer(N). +%%----------------------------------------------------------------- +%% Page with list of all funs +funs(SessionId,File,TW) -> + ParseFun = fun(Fd,_Id) -> get_funinfo(Fd,#fu{}) end, + chunk_page(SessionId,File,TW,?fu,funs,[],ParseFun). -funs(File) -> - case ets:lookup(cdv_dump_index_table,"=fun") of - [] -> - []; - AllFuns -> - Fd = open(File), - R = lists:map(fun({"=fun",_,Start}) -> - get_funinfo(Fd,Start) - end, - AllFuns), - close(Fd), - R - end. - -get_funinfo(Fd,Start) -> - pos_bof(Fd,Start), - get_funinfo1(Fd,#fu{_=?space}). - -get_funinfo1(Fd,Fu) -> +get_funinfo(Fd,Fu) -> case line_head(Fd) of "Module" -> - get_funinfo1(Fd,Fu#fu{module=val(Fd)}); + get_funinfo(Fd,Fu#fu{module=val(Fd)}); "Uniq" -> - get_funinfo1(Fd,Fu#fu{uniq=val(Fd)}); + get_funinfo(Fd,Fu#fu{uniq=val(Fd)}); "Index" -> - get_funinfo1(Fd,Fu#fu{index=val(Fd)}); + get_funinfo(Fd,Fu#fu{index=val(Fd)}); "Address" -> - get_funinfo1(Fd,Fu#fu{address=val(Fd)}); + get_funinfo(Fd,Fu#fu{address=val(Fd)}); "Native_address" -> - get_funinfo1(Fd,Fu#fu{native_address=val(Fd)}); + get_funinfo(Fd,Fu#fu{native_address=val(Fd)}); "Refc" -> - get_funinfo1(Fd,Fu#fu{refc=val(Fd)}); + get_funinfo(Fd,Fu#fu{refc=val(Fd)}); "=" ++ _next_tag -> Fu; Other -> @@ -2113,28 +2237,53 @@ get_funinfo1(Fd,Fu) -> Fu end. -atoms(File) -> - case ets:lookup(cdv_dump_index_table,"=atoms") of - [{_atoms,_Id,Start}] -> +%%----------------------------------------------------------------- +%% Page with list of all atoms +atoms(SessionId,File,TW,Num) -> + case lookup_index(?atoms) of + [{_Id,Start}] -> Fd = open(File), pos_bof(Fd,Start), - R = case get_n_lines_of_tag(Fd,100) of - {all,N,Lines} -> - {n_lines,1,N,"Atoms",Lines}; - {part,100,Lines} -> - {n_lines,1,100,"Atoms",Lines,get(pos)}; - empty -> - [] - end, - close(Fd), - R; + case get_atoms(Fd,?items_chunk_size) of + {Atoms,Cont} -> + crashdump_viewer_html:atoms(SessionId,TW,Num,Atoms), + atoms_chunks(Fd,SessionId,Cont); + done -> + crashdump_viewer_html:atoms(SessionId,TW,Num,done) + end; _ -> - [] + crashdump_viewer_html:atoms(SessionId,TW,Num,done) + end. + +get_atoms(Fd,Number) -> + case get_n_lines_of_tag(Fd,Number) of + {all,_,Lines} -> + close(Fd), + {Lines,done}; + {part,_,Lines} -> + {Lines,Number}; + empty -> + close(Fd), + done end. +atoms_chunks(_Fd,SessionId,done) -> + crashdump_viewer_html:atoms_chunk(SessionId,done); +atoms_chunks(Fd,SessionId,Number) -> + case get_atoms(Fd,Number) of + {Atoms,Cont} -> + crashdump_viewer_html:atoms_chunk(SessionId,Atoms), + atoms_chunks(Fd,SessionId,Cont); + done -> + atoms_chunks(Fd,SessionId,done) + end. + + +%%----------------------------------------------------------------- +%% Page with memory information memory(File) -> - case ets:lookup(cdv_dump_index_table,"=memory") of - [{"=memory",_,Start}] -> + case lookup_index(?memory) of + [{_,Start}] -> Fd = open(File), pos_bof(Fd,Start), R = get_meminfo(Fd,[]), @@ -2153,10 +2302,12 @@ get_meminfo(Fd,Acc) -> Key -> get_meminfo(Fd,[{Key,val(Fd)}|Acc]) end. - + +%%----------------------------------------------------------------- +%% Page with information about allocated areas allocated_areas(File) -> - case ets:lookup(cdv_dump_index_table,"=allocated_areas") of - [{"=allocated_areas",_,Start}] -> + case lookup_index(?allocated_areas) of + [{_,Start}] -> Fd = open(File), pos_bof(Fd,Start), R = get_allocareainfo(Fd,[]), @@ -2183,14 +2334,16 @@ get_allocareainfo(Fd,Acc) -> end, get_allocareainfo(Fd,[AllocInfo|Acc]) end. - + +%%----------------------------------------------------------------- +%% Page with information about allocators allocator_info(File) -> - case ets:lookup(cdv_dump_index_table,"=allocator") of + case lookup_index(?allocator) of [] -> []; AllAllocators -> Fd = open(File), - R = lists:map(fun({"=allocator",Heading,Start}) -> + R = lists:map(fun({Heading,Start}) -> {Heading,get_allocatorinfo(Fd,Start)} end, AllAllocators), @@ -2220,14 +2373,15 @@ get_all_vals([],Acc) -> get_all_vals([Char|Rest],Acc) -> get_all_vals(Rest,[Char|Acc]). - +%%----------------------------------------------------------------- +%% Page with hash table information hash_tables(File) -> - case ets:lookup(cdv_dump_index_table,"=hash_table") of + case lookup_index(?hash_table) of [] -> []; AllHashTables -> Fd = open(File), - R = lists:map(fun({"=hash_table",Name,Start}) -> + R = lists:map(fun({Name,Start}) -> get_hashtableinfo(Fd,Name,Start) end, AllHashTables), @@ -2237,7 +2391,7 @@ hash_tables(File) -> get_hashtableinfo(Fd,Name,Start) -> pos_bof(Fd,Start), - get_hashtableinfo1(Fd,#hash_table{name=Name,_=?space}). + get_hashtableinfo1(Fd,#hash_table{name=Name}). get_hashtableinfo1(Fd,HashTable) -> case line_head(Fd) of @@ -2256,13 +2410,15 @@ get_hashtableinfo1(Fd,HashTable) -> HashTable end. +%%----------------------------------------------------------------- +%% Page with index table information index_tables(File) -> - case ets:lookup(cdv_dump_index_table,"=index_table") of + case lookup_index(?index_table) of [] -> []; AllIndexTables -> Fd = open(File), - R = lists:map(fun({"=index_table",Name,Start}) -> + R = lists:map(fun({Name,Start}) -> get_indextableinfo(Fd,Name,Start) end, AllIndexTables), @@ -2272,7 +2428,7 @@ index_tables(File) -> get_indextableinfo(Fd,Name,Start) -> pos_bof(Fd,Start), - get_indextableinfo1(Fd,#index_table{name=Name,_=?space}). + get_indextableinfo1(Fd,#index_table{name=Name}). get_indextableinfo1(Fd,IndexTable) -> case line_head(Fd) of @@ -2284,6 +2440,8 @@ get_indextableinfo1(Fd,IndexTable) -> get_indextableinfo1(Fd,IndexTable#index_table{limit=val(Fd)}); "rate" -> get_indextableinfo1(Fd,IndexTable#index_table{rate=val(Fd)}); + "entries" -> + get_indextableinfo1(Fd,IndexTable#index_table{entries=val(Fd)}); "=" ++ _next_tag -> IndexTable; Other -> @@ -2295,6 +2453,8 @@ get_indextableinfo1(Fd,IndexTable) -> +%%----------------------------------------------------------------- +%% Expand a set of data which was shown in a truncated form on get_expanded(File,Pos,Size) -> Fd = open(File), R = case file:pread(Fd,Pos,Size) of @@ -2307,20 +2467,6 @@ get_expanded(File,Pos,Size) -> R. -get_next(File,Pos,N0,Start,What) -> - Fd = open(File), - pos_bof(Fd,Pos), - R = case get_n_lines_of_tag(Fd,N0) of - {all,N,Lines} -> - {n_lines,Start,N,What,Lines}; - {part,N,Lines} -> - {n_lines,Start,N,What,Lines,get(pos)} - end, - close(Fd), - R. - - - replace_all(From,To,[From|Rest],Acc) -> replace_all(From,To,Rest,[To|Acc]); replace_all(From,To,[Char|Rest],Acc) -> @@ -2567,3 +2713,110 @@ get_binary(_N, [], _Acc) -> cdvbin(Sz,Pos) -> "#CDVBin<"++integer_to_list(Sz)++","++integer_to_list(Pos)++">". + + +%%----------------------------------------------------------------- +%% Functions for accessing the cdv_dump_index_table +reset_index_table() -> + ets:delete_all_objects(cdv_dump_index_table). + +insert_index(Tag,Id,Pos) -> + ets:insert(cdv_dump_index_table,{{Tag,Pos},Id}). + +lookup_index(Tag) -> + lookup_index(Tag,'$2'). +lookup_index(Tag,Id) -> + ets:select(cdv_dump_index_table,[{{{Tag,'$1'},Id},[],[{{Id,'$1'}}]}]). + +lookup_index_chunk({'#CDVFirstChunk',Tag,Id}) -> + ets:select(cdv_dump_index_table, + [{{{Tag,'$1'},Id},[],[{{Id,'$1'}}]}], + ?items_chunk_size); +lookup_index_chunk(Cont) -> + ets:select(Cont). + +%% Create a tag which can be used instead of an ets Continuation for +%% the first call to lookup_index_chunk. +first_chunk_pointer({Tag,Id}) -> + {'#CDVFirstChunk',Tag,Id}; +first_chunk_pointer(Tag) -> + first_chunk_pointer({Tag,'$2'}). + +count_index(Tag) -> + ets:select_count(cdv_dump_index_table,[{{{Tag,'_'},'_'},[],[true]}]). +count_index(Tag,Id) -> + ets:select_count(cdv_dump_index_table,[{{{Tag,'_'},Id},[],[true]}]). + + +%%----------------------------------------------------------------- +%% Convert tags read from crashdump to atoms used as first part of key +%% in cdv_dump_index_table +tag_to_atom("allocated_areas") -> ?allocated_areas; +tag_to_atom("allocator") -> ?allocator; +tag_to_atom("atoms") -> ?atoms; +tag_to_atom("binary") -> ?binary; +tag_to_atom("debug_proc_dictionary") -> ?debug_proc_dictionary; +tag_to_atom("end") -> ?ende; +tag_to_atom("erl_crash_dump") -> ?erl_crash_dump; +tag_to_atom("ets") -> ?ets; +tag_to_atom("fun") -> ?fu; +tag_to_atom("hash_table") -> ?hash_table; +tag_to_atom("hidden_node") -> ?hidden_node; +tag_to_atom("index_table") -> ?index_table; +tag_to_atom("instr_data") -> ?instr_data; +tag_to_atom("internal_ets") -> ?internal_ets; +tag_to_atom("loaded_modules") -> ?loaded_modules; +tag_to_atom("memory") -> ?memory; +tag_to_atom("mod") -> ?mod; +tag_to_atom("no_distribution") -> ?no_distribution; +tag_to_atom("node") -> ?node; +tag_to_atom("not_connected") -> ?not_connected; +tag_to_atom("num_atoms") -> ?num_atoms; +tag_to_atom("old_instr_data") -> ?old_instr_data; +tag_to_atom("port") -> ?port; +tag_to_atom("proc") -> ?proc; +tag_to_atom("proc_dictionary") -> ?proc_dictionary; +tag_to_atom("proc_heap") -> ?proc_heap; +tag_to_atom("proc_messages") -> ?proc_messages; +tag_to_atom("proc_stack") -> ?proc_stack; +tag_to_atom("timer") -> ?timer; +tag_to_atom("visible_node") -> ?visible_node; +tag_to_atom(UnknownTag) -> + io:format("WARNING: Found unexpected tag:~s~n",[UnknownTag]), + list_to_atom(UnknownTag). + +%%%----------------------------------------------------------------- +%%% Create a page by sending chunk by chunk to crashdump_viewer_html +chunk_page(SessionId,File,TW,What,HtmlCB,HtmlExtra,ParseFun) -> + Fd = open(File), + case lookup_and_parse_index_chunk(first_chunk_pointer(What),Fd,ParseFun) of + done -> + crashdump_viewer_html:chunk_page(HtmlCB,SessionId,TW,HtmlExtra,done); + {Chunk,Cont} -> + HtmlInfo = crashdump_viewer_html:chunk_page( + HtmlCB, + SessionId,TW,HtmlExtra,Chunk), + chunk_page_1(Fd,HtmlInfo,SessionId,ParseFun, + lookup_and_parse_index_chunk(Cont,Fd,ParseFun)) + end. + +chunk_page_1(_Fd,HtmlInfo,SessionId,_ParseFun,done) -> + crashdump_viewer_html:chunk(SessionId,done,HtmlInfo); +chunk_page_1(Fd,HtmlInfo,SessionId,ParseFun,{Chunk,Cont}) -> + crashdump_viewer_html:chunk(SessionId,Chunk,HtmlInfo), + chunk_page_1(Fd,HtmlInfo,SessionId,ParseFun, + lookup_and_parse_index_chunk(Cont,Fd,ParseFun)). + +lookup_and_parse_index_chunk(Pointer,Fd,ParseFun) -> + case lookup_index_chunk(Pointer) of + '$end_of_table' -> + close(Fd), + done; + {Chunk,Cont} -> + R = lists:map(fun({Id,Start}) -> + pos_bof(Fd,Start), + ParseFun(Fd,Id) + end, + Chunk), + {R,Cont} + end. diff --git a/lib/observer/src/crashdump_viewer.hrl b/lib/observer/src/crashdump_viewer.hrl index 6ce727cd3e..466f33b63b 100644 --- a/lib/observer/src/crashdump_viewer.hrl +++ b/lib/observer/src/crashdump_viewer.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -17,117 +17,136 @@ %% %CopyrightEnd% %% -define(space, " "). +-define(unknown, "unknown"). -record(menu_item,{index,picture,text,depth,children,state,target}). -record(general_info, {created, - slogan, - system_vsn, - compile_time, - taints, - node_name, - num_atoms, - num_procs, - num_ets, - num_fun, - mem_tot, - mem_max, - instr_info}). + slogan=?space, + system_vsn=?space, + compile_time=?space, + taints=?space, + node_name=?space, + num_atoms=?space, + num_procs=?space, + num_ets=?space, + num_timers=?space, + num_fun=?space, + mem_tot=?space, + mem_max=?space, + instr_info=?space}). -record(proc, + %% Initial data according to the follwoing: + %% + %% msg_q_len, reds and stack_heap are integers because it must + %% be possible to sort on them. All other fields are strings + %% + %% for old dumps start_time, parent and number of heap frament + %% does not exist + %% + %% current_func can be both "current function" and + %% "last scheduled in for" + %% + %% stack_dump, message queue and dictionaries should only be + %% displayed as a link to "Expand" (if dump is from OTP R9B + %% or newer) {pid, - name, - init_func, - parent, - start_time, - state, - current_func, - msg_q_len, - msg_q, - last_calls, - links, - prog_count, - cp, - arity, - dict, - debug_dict, - reds, - num_heap_frag, - heap_frag_data, - stack_heap, - old_heap, - heap_unused, - old_heap_unused, - new_heap_start, - new_heap_top, - stack_top, - stack_end, - old_heap_start, - old_heap_top, - old_heap_end, - stack_dump}). + name=?space, + init_func=?space, + parent=?unknown, + start_time=?unknown, + state=?space, + current_func={"Current Function",?space}, + msg_q_len=0, + msg_q=?space, + last_calls=?space, + links=?space, + prog_count=?space, + cp=?space, + arity=?space, + dict=?space, + debug_dict=?space, + reds=0, + num_heap_frag=?unknown, + heap_frag_data=?space, + stack_heap=0, + old_heap=?space, + heap_unused=?space, + old_heap_unused=?space, + new_heap_start=?space, + new_heap_top=?space, + stack_top=?space, + stack_end=?space, + old_heap_start=?space, + old_heap_top=?space, + old_heap_end=?space, + stack_dump=?space}). -record(port, {id, - slot, - connected, - links, - controls}). + slot=?space, + connected=?space, + links=?space, + name=?space, + monitors=?space, + controls=?space}). -record(ets_table, {pid, - slot, - id, - name, - type, - buckets, - size, - memory}). + slot=?space, + id=?space, + name=?space, + type="hash", + buckets=?space, + size=?space, + memory=?space}). -record(timer, {pid, - msg, - time}). + msg=?space, + time=?space}). -record(fu, - {module, - uniq, - index, - address, - native_address, - refc}). + {module=?space, + uniq=?space, + index=?space, + address=?space, + native_address=?space, + refc=?space}). -record(nod, - {name, + {name=?space, channel, - controller, - creation, - remote_links, - remote_mon, - remote_mon_by, - error}). + controller=?space, + creation=?space, + remote_links=?space, + remote_mon=?space, + remote_mon_by=?space, + error=?space}). -record(loaded_mod, {mod, - current_size, - current_attrib, - current_comp_info, - old_size, - old_attrib, - old_comp_info}). + current_size=?space, + current_attrib=?space, + current_comp_info=?space, + old_size=?space, + old_attrib=?space, + old_comp_info=?space}). -record(hash_table, {name, - size, - used, - objs, - depth}). + size=?space, + used=?space, + objs=?space, + depth=?space}). -record(index_table, {name, - size, - used, - limit, - rate}). + size=?space, + used=?space, + limit=?space, + rate=?space, + entries=?space}). diff --git a/lib/observer/src/crashdump_viewer_html.erl b/lib/observer/src/crashdump_viewer_html.erl index 5e7bbf62a0..24a80b1916 100644 --- a/lib/observer/src/crashdump_viewer_html.erl +++ b/lib/observer/src/crashdump_viewer_html.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -32,25 +32,23 @@ general_info/1, pretty_info_page/2, info_page/2, - procs_summary/4, proc_details/4, expanded_memory/2, expanded_binary/1, - next/2, - ports/3, - timers/3, - ets_tables/4, + port/3, + internal_ets_tables/2, nods/2, - loaded_mods/2, loaded_mod_details/2, - funs/2, - atoms/3, + atoms/4, + atoms_chunk/2, memory/2, allocated_areas/2, allocator_info/2, hash_tables/2, index_tables/2, - error/2]). + error/2, + chunk_page/5, + chunk/3]). -include("crashdump_viewer.hrl"). @@ -79,23 +77,20 @@ read_file_frame() -> read_file_frame_body() -> - Entry = - case webtool:is_localhost() of - true -> [input("TYPE=file NAME=browse SIZE=40"), - input("TYPE=hidden NAME=path")]; - false -> input("TYPE=text NAME=path SIZE=60") - end, + %% Using a plain text input field instead of a file input field + %% (e.g. <INPUT TYPE=file NAME=pathj SIZE=40">) because most + %% browsers can not forward the full path from this dialog even if + %% the browser is running on localhost (Ref 'fakepath'-problem) + Entry = input("TYPE=text NAME=path SIZE=60"), Form = form( - "NAME=read_file_form METHOD=post ACTION= \"./read_file\"", + "NAME=read_file_form METHOD=post ACTION=\"./read_file\"", table( "BORDER=0", [tr(td("COLSPAN=2","Enter file to analyse")), tr( [td(Entry), - td("ALIGN=center", - input("TYPE=submit onClick=\"path.value=browse.value;\"" - "VALUE=Ok"))])])), + td("ALIGN=center",input("TYPE=submit VALUE=Ok"))])])), table( "WIDTH=100% HEIGHT=60%", tr("VALIGN=middle", @@ -235,6 +230,8 @@ general_info_body(Heading,GenInfo) -> td(GenInfo#general_info.num_procs)]), tr([th("ALIGN=left BGCOLOR=\"#8899AA\"","ETS tables"), td(GenInfo#general_info.num_ets)]), + tr([th("ALIGN=left BGCOLOR=\"#8899AA\"","Timers"), + td(GenInfo#general_info.num_timers)]), tr([th("ALIGN=left BGCOLOR=\"#8899AA\"","Funs"), td(GenInfo#general_info.num_fun)])]), case GenInfo#general_info.instr_info of @@ -295,60 +292,6 @@ pretty_info_body(Heading,Info) -> pre(pretty_format(Info))]. %%%----------------------------------------------------------------- -%%% Make table with summary of process information -procs_summary(Sorted,ProcsSummary,TW,SharedHeap) -> - Heading = "Process Information", - header(Heading, - body( - procs_summary_body(Heading,ProcsSummary,TW,Sorted,SharedHeap))). - -procs_summary_body(Heading,[],TW,_Sorted,_SharedHeap) -> - [h1(Heading), - warn(TW), - "No processes were found\n"]; -procs_summary_body(Heading,ProcsSummary,TW,Sorted,SharedHeap) -> - MemHeading = - if SharedHeap -> - "Stack"; - true -> - "Stack+heap" - end, - - [heading(Heading,"processes"), - warn(TW), - table( - "BORDER=4 CELLPADDING=4", - [tr( - [summary_table_head("pid","Pid",Sorted), - summary_table_head("name_func","Name/Spawned as",Sorted), - summary_table_head("state","State",Sorted), - summary_table_head("reds","Reductions",Sorted), - summary_table_head("mem",MemHeading,Sorted), - summary_table_head("msg_q_len","MsgQ Length",Sorted)]) | - lists:map(fun(Proc) -> procs_summary_table(Proc) end,ProcsSummary)])]. - -summary_table_head(Sorted,Text,Sorted) -> - %% Mark the sorted column (bigger and italic) - th(font("SIZE=\"+1\"",em(href("./sort_procs?sort="++Sorted,Text)))); -summary_table_head(SortOn,Text,_Sorted) -> - th(href("./sort_procs?sort="++SortOn,Text)). - -procs_summary_table(Proc) -> - #proc{pid=Pid,name=Name,state=State, - reds=Reds,stack_heap=Mem0,msg_q_len=MsgQLen}=Proc, - Mem = case Mem0 of - -1 -> "unknown"; - _ -> integer_to_list(Mem0) - end, - tr( - [td(href(["./proc_details?pid=",Pid],Pid)), - td(Name), - td(State), - td("ALIGN=right",integer_to_list(Reds)), - td("ALIGN=right",Mem), - td("ALIGN=right",integer_to_list(MsgQLen))]). - -%%%----------------------------------------------------------------- %%% Print details for one process proc_details(Pid,Proc,TW,SharedHeap) -> Script = @@ -594,83 +537,33 @@ expanded_binary_body(Heading,Bin) -> href("javascript:history.go(-1)","BACK")]. %%%----------------------------------------------------------------- -%%% Print table of ports -ports(Heading,Ports,TW) -> - header(Heading,body(ports_body(Heading,Ports,TW))). +%%% Print info for one port +port(Heading,Port,TW) -> + header(Heading,body(port_body(Heading,Port,TW))). -ports_body(Heading,[],TW) -> - [h1(Heading), - warn(TW), - "No ports were found\n"]; -ports_body(Heading,Ports,TW) -> +port_body(Heading,Port,TW) -> [heading(Heading,"ports"), warn(TW), table( "BORDER=4 CELLPADDING=4", - [tr( - [th("Id"), - th("Slot"), - th("Connected"), - th("Links"), - th("Controls")]) | - lists:map(fun(Port) -> ports_table(Port) end, Ports)])]. + [tr([th(Head) || Head <- port_table_head()]), ports_table(Port)])]. -ports_table(Port) -> - #port{id=Id,slot=Slot,connected=Connected,links=Links, - controls=Controls}=Port, - tr( - [td(Id), - td("ALIGHT=right",Slot), - td(href_proc_port(Connected)), - td(href_proc_port(Links)), - td(Controls)]). - %%%----------------------------------------------------------------- -%%% Print table of ETS tables -ets_tables(Heading,EtsTables,InternalEts,TW) -> - header(Heading,body(ets_tables_body(Heading,EtsTables,InternalEts,TW))). +%%% Print table of internal ETS tables +internal_ets_tables(InternalEts,TW) -> + Heading = "Internal ETS tables", + header(Heading,body(internal_ets_tables_body(Heading,InternalEts,TW))). -ets_tables_body(Heading,[],InternalEts,TW) -> +internal_ets_tables_body(Heading,[],TW) -> [h1(Heading), warn(TW), - "No ETS tables were found\n" | - internal_ets_tables_table(InternalEts)]; -ets_tables_body(Heading,EtsTables,InternalEts,TW) -> - [heading(Heading,"ets_tables"), + "No internal ETS tables were found\n"]; +internal_ets_tables_body(Heading,InternalEts,TW) -> + [heading(Heading,"internal_ets_tables"), warn(TW), table( "BORDER=4 CELLPADDING=4", [tr( - [th("Owner"), - th("Slot"), - th("Id"), - th("Name"), - th("Type"), - th("Buckets"), - th("Objects"), - th("Memory (bytes)")]) | - lists:map(fun(EtsTable) -> ets_tables_table(EtsTable) end, - EtsTables)]) | - internal_ets_tables_table(InternalEts)]. - -ets_tables_table(EtsTable) -> - #ets_table{pid=Pid,slot=Slot,id=Id,name=Name,type=Type, - buckets=Buckets,size=Size,memory=Memory} = EtsTable, - tr( - [td(href_proc_port(Pid)), - td(Slot), - td(Id), - td(Name), - td(Type), - td("ALIGN=right",Buckets), - td("ALIGN=right",Size), - td("ALIGN=right",Memory)]). - -internal_ets_tables_table(InternalEtsTables) -> - [h2("Internal ETS tables"), - table( - "BORDER=4 CELLPADDING=4", - [tr( [th("Description"), th("Id"), th("Name"), @@ -681,7 +574,7 @@ internal_ets_tables_table(InternalEtsTables) -> lists:map(fun(InternalEtsTable) -> internal_ets_tables_table1(InternalEtsTable) end, - InternalEtsTables)])]. + InternalEts)])]. internal_ets_tables_table1({Descr,InternalEtsTable}) -> #ets_table{id=Id,name=Name,type=Type,buckets=Buckets, @@ -696,33 +589,6 @@ internal_ets_tables_table1({Descr,InternalEtsTable}) -> td("ALIGN=right",Memory)]). %%%----------------------------------------------------------------- -%%% Print table of timers -timers(Heading,Timers,TW) -> - header(Heading,body(timers_body(Heading,Timers,TW))). - -timers_body(Heading,[],TW) -> - [h1(Heading), - warn(TW), - "No timers were found\n"]; -timers_body(Heading,Timers,TW) -> - [heading(Heading,"timers"), - warn(TW), - table( - "BORDER=4 CELLPADDING=4", - [tr( - [th("Owner"), - th("Message"), - th("Time left")]) | - lists:map(fun(Timer) -> timers_table(Timer) end, Timers)])]. - -timers_table(Timer) -> - #timer{pid=Pid,msg=Msg,time=Time}=Timer, - tr( - [td(href_proc_port(Pid)), - td(Msg), - td("ALIGN=right",Time)]). - -%%%----------------------------------------------------------------- %%% Print table of nodes in distribution nods(Nods,TW) -> header("Distribution Information",body(nodes_body(Nods,TW))). @@ -826,33 +692,6 @@ format_extra_info(Error) -> ?space -> ""; _ -> font("COLOR=\"#FF0000\"",["ERROR: ",Error,"\n"]) end. -%%%----------------------------------------------------------------- -%%% Print loaded modules information -loaded_mods({CC,OC,LM},TW) -> - Heading = "Loaded Modules Information", - header(Heading,body(loaded_mods_body(Heading,CC,OC,LM,TW))). - -loaded_mods_body(Heading,"unknown","unknown",[],TW) -> - [h1(Heading), - warn(TW), - "No loaded modules information was found\n"]; -loaded_mods_body(Heading,CC,OC,LM,TW) -> - [heading(Heading,"loaded_modules"), - warn(TW), - p([b("Current code: "),CC," bytes",br(), - b("Old code: "),OC," bytes"]), - table( - "BORDER=4 CELLPADDING=4", - [tr([th("Module"), - th("Current size (bytes)"), - th("Old size (bytes)")]) | - lists:map(fun(Mod) -> loaded_mods_table(Mod) end,LM)])]. - -loaded_mods_table(#loaded_mod{mod=Mod,current_size=CS,old_size=OS}) -> - tr([td(href(["loaded_mod_details?mod=",Mod],Mod)), - td("ALIGN=right",CS), - td("ALIGN=right",OS)]). - %%%----------------------------------------------------------------- %%% Print detailed information about one module @@ -882,107 +721,33 @@ loaded_mod_details_body(ModInfo,TW) -> %%%----------------------------------------------------------------- -%%% Print table of funs -funs(Funs,TW) -> - Heading = "Fun Information", - header(Heading,body(funs_body(Heading,Funs,TW))). - -funs_body(Heading,[],TW) -> - [h1(Heading), - warn(TW), - "No Fun information was found\n"]; -funs_body(Heading,Funs,TW) -> - [heading(Heading,"funs"), - warn(TW), - table( - "BORDER=4 CELLPADDING=4", - [tr( - [th("Module"), - th("Uniq"), - th("Index"), - th("Address"), - th("Native_address"), - th("Refc")]) | - lists:map(fun(Fun) -> funs_table(Fun) end, Funs)])]. - -funs_table(Fu) -> - #fu{module=Module,uniq=Uniq,index=Index,address=Address, - native_address=NativeAddress,refc=Refc}=Fu, - tr( - [td(Module), - td("ALIGN=right",Uniq), - td("ALIGN=right",Index), - td(Address), - td(NativeAddress), - td("ALIGN=right",Refc)]). - -%%%----------------------------------------------------------------- %%% Print atoms -atoms(Atoms,Num,TW) -> +atoms(SessionId,TW,Num,FirstChunk) -> Heading = "Atoms", - header(Heading,body(atoms_body(Heading,Atoms,Num,TW))). - -atoms_body(Heading,[],Num,TW) -> - [h1(Heading), - warn(TW), - "No atoms were found in log",br(), - "Total number of atoms in node was ", Num, br()]; -atoms_body(Heading,Atoms,Num,TW) -> - [heading(Heading,"atoms"), - warn(TW), - "Total number of atoms in node was ", Num, - br(), - "The last created atom is shown first", - br(),br() | - n_first(Atoms)]. - -n_first({n_lines,Start,N,What,Lines,Pos}) -> - NextHref = next_href(N,What,Pos,Start), - [What," number ",integer_to_list(Start),"-",integer_to_list(Start+N-1), - br(), - NextHref, - pre(Lines), - NextHref]; -n_first({n_lines,_Start,_N,_What,Lines}) -> - [pre(Lines)]. - -%%%----------------------------------------------------------------- -%%% Print next N lines of "something" -next(NLines,TW) -> - header(element(4,NLines),body(next_body(NLines,TW))). - -next_body({n_lines,Start,N,What,Lines,Pos},TW) -> - PrefHref = prev_href(), - NextHref = next_href(N,What,Pos,Start), - [warn(TW), - What," number ",integer_to_list(Start),"-",integer_to_list(Start+N-1), - br(), - PrefHref, - ?space, - NextHref, - pre(Lines), - PrefHref, - ?space, - NextHref]; -next_body({n_lines,Start,N,What,Lines},TW) -> - PrefHref = prev_href(), - [warn(TW), - What," number ",integer_to_list(Start),"-",integer_to_list(Start+N-1), - br(), - PrefHref, - pre(Lines), - PrefHref]. - - -prev_href() -> - href("javascript:history.back()",["Previous"]). - -next_href(N,What,Pos,Start) -> - href(["./next?pos=",integer_to_list(Pos), - "&num=",integer_to_list(N), - "&start=",integer_to_list(Start+N), - "&what=",What], - "Next"). + case FirstChunk of + done -> + deliver_first(SessionId,[start_html_page(Heading), + h1(Heading), + warn(TW), + "No atoms were found in log",br(), + "Total number of atoms in node was ", Num, + br()]); + _ -> + deliver_first(SessionId,[start_html_page(Heading), + heading(Heading,"atoms"), + warn(TW), + "Total number of atoms in node was ", Num, + br(), + "The last created atom is shown first", + br(), + start_pre()]), + atoms_chunk(SessionId,FirstChunk) + end. + +atoms_chunk(SessionId,done) -> + deliver(SessionId,[stop_pre(),stop_html_page()]); +atoms_chunk(SessionId,Atoms) -> + deliver(SessionId,Atoms). %%%----------------------------------------------------------------- %%% Print memory information @@ -1120,52 +885,92 @@ index_tables_body(Heading,IndexTables,TW) -> th("Size"), th("Limit"), th("Used"), - th("Rate")]) | + th("Rate"), + th("Entries")]) | lists:map(fun(IndexTable) -> index_tables_table(IndexTable) end, IndexTables)])]. index_tables_table(IndexTable) -> - #index_table{name=Name,size=Size,limit=Limit,used=Used,rate=Rate} = - IndexTable, + #index_table{name=Name,size=Size,limit=Limit,used=Used, + rate=Rate,entries=Entries} = IndexTable, tr( [td(Name), td("ALIGN=right",Size), td("ALIGN=right",Limit), td("ALIGN=right",Used), - td("ALIGN=right",Rate)]). + td("ALIGN=right",Rate), + td("ALIGN=right",Entries)]). %%%----------------------------------------------------------------- %%% Internal library +start_html_page(Title) -> + [only_http_header(), + start_html(), + only_html_header(Title), + start_html_body()]. + +stop_html_page() -> + [stop_html_body(), + stop_html()]. + +only_http_header() -> + ["Pragma:no-cache\r\n", + "Content-type: text/html\r\n\r\n"]. + +only_html_header(Title) -> + only_html_header(Title,""). +only_html_header(Title,JavaScript) -> + ["<HEAD>\n", + "<TITLE>", Title, "</TITLE>\n", + JavaScript, + "</HEAD>\n"]. + +start_html() -> + "<HTML>\n". +stop_html() -> + "</HTML>". +start_html_body() -> + "<BODY BGCOLOR=\"#FFFFFF\">\n". +stop_html_body() -> + "</BODY>\n". + header(Body) -> header("","",Body). header(Title,Body) -> header(Title,"",Body). header(Title,JavaScript,Body) -> - ["Pragma:no-cache\r\n", - "Content-type: text/html\r\n\r\n", + [only_http_header(), html_header(Title,JavaScript,Body)]. html_header(Title,JavaScript,Body) -> - ["<HTML>\n", - "<HEAD>\n", - "<TITLE>", Title, "</TITLE>\n", - JavaScript, - "</HEAD>\n", + [start_html(), + only_html_header(Title,JavaScript), Body, - "</HTML>"]. + stop_html()]. body(Text) -> - ["<BODY BGCOLOR=\"#FFFFFF\">\n", + [start_html_body(), Text, - "<\BODY>\n"]. + stop_html_body()]. frameset(Args,Frames) -> ["<FRAMESET ",Args,">\n", Frames, "\n</FRAMESET>\n"]. frame(Args) -> ["<FRAME ",Args, ">\n"]. +start_visible_table() -> + start_table("BORDER=\"4\" CELLPADDING=\"4\""). +start_visible_table(ColTitles) -> + [start_visible_table(), + tr([th(ColTitle) || ColTitle <- ColTitles])]. + +start_table(Args) -> + ["<TABLE ", Args, ">\n"]. +stop_table() -> + "</TABLE>\n". + table(Args,Text) -> - ["<TABLE ", Args, ">\n", Text, "\n</TABLE>\n"]. + [start_table(Args), Text, stop_table()]. tr(Text) -> ["<TR>\n", Text, "\n</TR>\n"]. tr(Args,Text) -> @@ -1183,8 +988,12 @@ b(Text) -> ["<B>",Text,"</B>"]. em(Text) -> ["<EM>",Text,"</EM>\n"]. +start_pre() -> + "<PRE>". +stop_pre() -> + "</PRE>". pre(Text) -> - ["<PRE>",Text,"</PRE>"]. + [start_pre(),Text,stop_pre()]. href(Link,Text) -> ["<A HREF=\"",Link,"\">",Text,"</A>"]. href(Args,Link,Text) -> @@ -1199,8 +1008,6 @@ input(Args) -> ["<INPUT ", Args, ">\n"]. h1(Text) -> ["<H1>",Text,"</H1>\n"]. -h2(Text) -> - ["<H2>",Text,"</H2>\n"]. font(Args,Text) -> ["<FONT ",Args,">\n",Text,"\n</FONT>\n"]. p(Text) -> @@ -1223,7 +1030,7 @@ href_proc_port([$#,$F,$u,$n,$<|T],Acc) -> href_proc_port([$#,$P,$o,$r,$t,$<|T],Acc) -> {[$#|Port]=HashPort,Rest} = to_gt(T,[$;,$t,$l,$&,$t,$r,$o,$P,$#]), href_proc_port(Rest,[href("TARGET=\"main\"", - ["./ports?port=",Port],HashPort)|Acc]); + ["./port?port=",Port],HashPort)|Acc]); href_proc_port([$<,$<|T],Acc) -> %% No links to binaries href_proc_port(T,[$;,$t,$l,$&,$;,$t,$l,$&|Acc]); @@ -1243,7 +1050,7 @@ href_proc_port([$",$#,$C,$D,$V,$P,$o,$r,$t,$<|T],Acc) -> %% Port written by crashdump_viewer:parse_term(...) {[$#|Port]=HashPort,[$"|Rest]} = to_gt(T,[$;,$t,$l,$&,$t,$r,$o,$P,$#]), href_proc_port(Rest,[href("TARGET=\"main\"", - ["./ports?port=",Port],HashPort)|Acc]); + ["./port?port=",Port],HashPort)|Acc]); href_proc_port([$",$#,$C,$D,$V,$P,$i,$d,$<|T],Acc) -> %% Pid written by crashdump_viewer:parse_term(...) {Pid,[$"|Rest]} = to_gt(T,[$;,$t,$l,$&]), @@ -1422,7 +1229,7 @@ replace_insrt("'trsni$'"++Rest,[H|T],Acc) -> % the list is reversed here! "<" ++ _Pid -> href("TARGET=\"main\"",["./proc_details?pid=",H],H); "#Port<" ++ Port -> - href("TARGET=\"main\"",["./ports?port=","Port<"++Port],H); + href("TARGET=\"main\"",["./port?port=","Port<"++Port],H); "#" ++ _other -> H end, @@ -1431,3 +1238,173 @@ replace_insrt([H|T],Insrt,Acc) -> replace_insrt(T,Insrt,[H|Acc]); replace_insrt([],[],Acc) -> Acc. + +%%%----------------------------------------------------------------- +%%% Create a page with one table by delivering chunk by chunk to +%%% inets. crashdump_viewer first calls chunk_page/5 once, then +%%% chunk/3 multiple times until all data is delivered. +chunk_page(processes,SessionId,TW,{Sorted,SharedHeap},FirstChunk) -> + Columns = procs_summary_table_head(Sorted,SharedHeap), + chunk_page(SessionId, "Process Information", TW, FirstChunk, + "processes", Columns, fun procs_summary_table/1); +chunk_page(ports,SessionId,TW,_,FirstChunk) -> + chunk_page(SessionId, "Port Information", TW, FirstChunk, + "ports", port_table_head(), fun ports_table/1); +chunk_page(ets_tables,SessionId,TW,Heading,FirstChunk) -> + Columns = ["Owner", + "Slot", + "Id", + "Name", + "Type", + "Buckets", + "Objects", + "Memory (bytes)"], + chunk_page(SessionId, Heading, TW, FirstChunk, + "ets_tables", Columns, fun ets_tables_table/1); +chunk_page(timers,SessionId,TW,Heading,FirstChunk) -> + chunk_page(SessionId, Heading, TW, FirstChunk, "timers", + ["Owner","Message","Time left"], fun timers_table/1); +chunk_page(loaded_mods,SessionId,TW,{CC,OC},FirstChunk) -> + TotalsInfo = p([b("Current code: "),CC," bytes",br(), + b("Old code: "),OC," bytes"]), + Columns = ["Module","Current size (bytes)","Old size (bytes)"], + chunk_page(SessionId, "Loaded Modules Information", TW, FirstChunk, + "loaded_modules", TotalsInfo,Columns, fun loaded_mods_table/1); +chunk_page(funs,SessionId, TW, _, FirstChunk) -> + Columns = ["Module", + "Uniq", + "Index", + "Address", + "Native_address", + "Refc"], + chunk_page(SessionId, "Fun Information", TW, FirstChunk, + "funs", Columns, fun funs_table/1). + +chunk_page(SessionId,Heading,TW,FirstChunk,Type,TableColumns,TableFun) -> + chunk_page(SessionId,Heading,TW,FirstChunk,Type,[],TableColumns,TableFun). +chunk_page(SessionId,Heading,TW,done,Type,_TotalsInfo,_TableColumns,_TableFun) -> + no_info_found(SessionId,Heading,TW,Type); +chunk_page(SessionId,Heading,TW,FirstChunk,Type,TotalsInfo,TableColumns,TableFun) -> + deliver_first(SessionId,[start_html_page(Heading), + heading(Heading,Type), + warn(TW), + TotalsInfo, + start_visible_table(TableColumns)]), + chunk(SessionId,FirstChunk,TableFun), + TableFun. + +no_info_found(SessionId, Heading, TW, Type) -> + Info = ["No ", Type, " were found\n"], + deliver_first(SessionId,[start_html_page(Heading), + h1(Heading), + warn(TW), + Info, + stop_html_page()]). + +chunk(SessionId, done, _TableFun) -> + deliver(SessionId,[stop_table(),stop_html_page()]); +chunk(SessionId, Items, TableFun) -> + deliver(SessionId, [lists:map(TableFun, Items), + stop_table(), %! Will produce an empty table at the end + start_visible_table()]). % of the page :( + +%%%----------------------------------------------------------------- +%%% Deliver part of a page to inets +%%% The first part, which includes the HTTP header, must always be +%%% delivered as a string (i.e. no binaries). The rest of the page is +%%% better delivered as binaries in order to avoid data copying. +deliver_first(SessionId,String) -> + mod_esi:deliver(SessionId,String). +deliver(SessionId,IoList) -> + mod_esi:deliver(SessionId,[list_to_binary(IoList)]). + + +%%%----------------------------------------------------------------- +%%% Page specific stuff for chunk pages +procs_summary_table_head(Sorted,SharedHeap) -> + MemHeading = + if SharedHeap -> + "Stack"; + true -> + "Stack+heap" + end, + [procs_summary_table_head("pid","Pid",Sorted), + procs_summary_table_head("name_func","Name/Spawned as",Sorted), + procs_summary_table_head("state","State",Sorted), + procs_summary_table_head("reds","Reductions",Sorted), + procs_summary_table_head("mem",MemHeading,Sorted), + procs_summary_table_head("msg_q_len","MsgQ Length",Sorted)]. + +procs_summary_table_head(_,Text,no_sort) -> + Text; +procs_summary_table_head(Sorted,Text,Sorted) -> + %% Mark the sorted column (bigger and italic) + font("SIZE=\"+1\"",em(href("./sort_procs?sort="++Sorted,Text))); +procs_summary_table_head(SortOn,Text,_Sorted) -> + href("./sort_procs?sort="++SortOn,Text). + +procs_summary_table(Proc) -> + #proc{pid=Pid,name=Name,state=State, + reds=Reds,stack_heap=Mem0,msg_q_len=MsgQLen}=Proc, + Mem = case Mem0 of + -1 -> "unknown"; + _ -> integer_to_list(Mem0) + end, + tr( + [td(href(["./proc_details?pid=",Pid],Pid)), + td(Name), + td(State), + td("ALIGN=right",integer_to_list(Reds)), + td("ALIGN=right",Mem), + td("ALIGN=right",integer_to_list(MsgQLen))]). + +port_table_head() -> + ["Id","Slot","Connected","Links","Name","Monitors","Controls"]. + +ports_table(Port) -> + #port{id=Id,slot=Slot,connected=Connected,links=Links,name=Name, + monitors=Monitors,controls=Controls}=Port, + tr( + [td(Id), + td("ALIGN=right",Slot), + td(href_proc_port(Connected)), + td(href_proc_port(Links)), + td(Name), + td(href_proc_port(Monitors)), + td(Controls)]). + +ets_tables_table(EtsTable) -> + #ets_table{pid=Pid,slot=Slot,id=Id,name=Name,type=Type, + buckets=Buckets,size=Size,memory=Memory} = EtsTable, + tr( + [td(href_proc_port(Pid)), + td(Slot), + td(Id), + td(Name), + td(Type), + td("ALIGN=right",Buckets), + td("ALIGN=right",Size), + td("ALIGN=right",Memory)]). + +timers_table(Timer) -> + #timer{pid=Pid,msg=Msg,time=Time}=Timer, + tr( + [td(href_proc_port(Pid)), + td(Msg), + td("ALIGN=right",Time)]). + +loaded_mods_table(#loaded_mod{mod=Mod,current_size=CS,old_size=OS}) -> + tr([td(href(["loaded_mod_details?mod=",Mod],Mod)), + td("ALIGN=right",CS), + td("ALIGN=right",OS)]). + +funs_table(Fu) -> + #fu{module=Module,uniq=Uniq,index=Index,address=Address, + native_address=NativeAddress,refc=Refc}=Fu, + tr( + [td(Module), + td("ALIGN=right",Uniq), + td("ALIGN=right",Index), + td(Address), + td(NativeAddress), + td("ALIGN=right",Refc)]). diff --git a/lib/observer/test/Makefile b/lib/observer/test/Makefile index e15bde7346..6073e6ea00 100644 --- a/lib/observer/test/Makefile +++ b/lib/observer/test/Makefile @@ -53,7 +53,7 @@ EBIN = . make_emakefile: $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) \ - $(MODULES) >> $(EMAKEFILE) + $(MODULES) > $(EMAKEFILE) tests debug opt: make_emakefile cd $(ERL_TOP)/lib/test_server/src && \ diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl index 1a7e6f61fe..fdc4a2f1ff 100644 --- a/lib/observer/test/crashdump_viewer_SUITE.erl +++ b/lib/observer/test/crashdump_viewer_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -68,7 +68,7 @@ init_per_suite(doc) -> init_per_suite(Config) when is_list(Config) -> Dog = ?t:timetrap(?default_timeout), application:start(inets), % will be using the http client later - http:set_options([{ipv6,disabled}]), + httpc:set_options([{ipfamily,inet6fb4}]), DataDir = ?config(data_dir,Config), Rels = [R || R <- [r12b,r13b], ?t:is_release_available(R)] ++ [current], io:format("Creating crash dumps for the following releases: ~p", [Rels]), @@ -112,7 +112,7 @@ start(Config) when is_list(Config) -> undefined = whereis(crashdump_viewer_server), undefined = whereis(web_tool), Url = cdv_url(Port,"start_page"), - {error,_} = http:request(get,{Url,[]},[],[]), + {error,_} = httpc:request(Url), % exit(whereis(httpc_manager),kill), ?t:timetrap_cancel(AngryDog), ok. @@ -246,7 +246,7 @@ cdv_url(Port,Link) -> "http://localhost:" ++ Port ++ "/cdv_erl/crashdump_viewer/" ++ Link. request_sync(Method,HTTPReqCont) -> - case http:request(Method, + case httpc:request(Method, HTTPReqCont, [{timeout,30000}], [{full_result, false}]) of @@ -254,13 +254,13 @@ request_sync(Method,HTTPReqCont) -> Html; {ok,{Code,Html}} -> io:format("~s\n", [Html]), - io:format("Received ~w from http:request(...) with\nMethod=~w\n" + io:format("Received ~w from httpc:request(...) with\nMethod=~w\n" "HTTPReqCont=~p\n", [Code,Method,HTTPReqCont]), ?t:fail(); Other -> io:format( - "Received ~w from http:request(...) with\nMethod=~w\n" + "Received ~w from httpc:request(...) with\nMethod=~w\n" "HTTPReqCont=~p\n", [Other,Method,HTTPReqCont]), ?t:fail() @@ -414,16 +414,17 @@ special(Port,File) -> _ -> ok end; - ".250atoms" -> - Html1 = contents(Port,"atoms"), - NextLink1 = next_link(Html1), - "Atoms" = title(Html1), - Html2 = contents(Port,NextLink1), - NextLink2 = next_link(Html2), - "Atoms" = title(Html2), - Html3 = contents(Port,NextLink2), - "" = next_link(Html3), - "Atoms" = title(Html3); + %%! No longer needed - all atoms are shown on one page!! + %% ".250atoms" -> + %% Html1 = contents(Port,"atoms"), + %% NextLink1 = next_link(Html1), + %% "Atoms" = title(Html1), + %% Html2 = contents(Port,NextLink1), + %% NextLink2 = next_link(Html2), + %% "Atoms" = title(Html2), + %% Html3 = contents(Port,NextLink2), + %% "" = next_link(Html3), + %% "Atoms" = title(Html3); _ -> ok end, @@ -496,27 +497,27 @@ expand_binary_link(Html) -> end. -next_link(Html) -> - case Html of - "<A HREF=\"./next?pos=" ++ Rest -> - "next?pos=" ++ string:sub_word(Rest,1,$"); - [_H|T] -> - next_link(T); - [] -> - [] - end. +%% next_link(Html) -> +%% case Html of +%% "<A HREF=\"./next?pos=" ++ Rest -> +%% "next?pos=" ++ string:sub_word(Rest,1,$"); +%% [_H|T] -> +%% next_link(T); +%% [] -> +%% [] +%% end. toggle_menu(Port) -> - Html = contents(Port,"toggle?index=10"), + Html = contents(Port,"toggle?index=4"), check_toggle(Html). check_toggle(Html) -> case Html of - "<A HREF=\"./toggle?index=10\"><IMG SRC=\"/crashdump_viewer/collapsd.gif\"" ++ _ -> + "<A HREF=\"./toggle?index=4\"><IMG SRC=\"/crashdump_viewer/collapsd.gif\"" ++ _ -> collapsed; - "<A HREF=\"./toggle?index=10\"><IMG SRC=\"/crashdump_viewer/exploded.gif\"" ++ _ -> + "<A HREF=\"./toggle?index=4\"><IMG SRC=\"/crashdump_viewer/exploded.gif\"" ++ _ -> exploded; [_H|T] -> check_toggle(T) @@ -543,10 +544,10 @@ expand_link(Html) -> port_details(Port) -> - Port1 = contents(Port,"ports?port=Port<0.1>"), + Port1 = contents(Port,"port?port=Port<0.1>"), "#Port<0.1>" = title(Port1), - Port0 = contents(Port,"ports?port=Port<0.0>"), + Port0 = contents(Port,"port?port=Port<0.0>"), "Could not find port: #Port<0.0>" = title(Port0). is_truncated(File) -> @@ -668,7 +669,7 @@ rename(From,To) -> end. check_complete(File) -> - check_complete1(File,5). + check_complete1(File,10). check_complete1(_File,0) -> {error,enoent}; diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c index 077d78bfe5..d61ce940c3 100644 --- a/lib/odbc/c_src/odbcserver.c +++ b/lib/odbc/c_src/odbcserver.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2010. All Rights Reserved. + * Copyright Ericsson AB 1999-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -472,7 +472,7 @@ static db_result_msg db_connect(byte *args, db_state *state) &stringlength2ptr, SQL_DRIVER_NOPROMPT); if (!sql_success(result)) { - diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state)); + diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state)); strcat((char *)diagnos.error_msg, " Connection to database failed."); msg = encode_error_message(diagnos.error_msg); diff --git a/lib/odbc/src/odbc.appup.src b/lib/odbc/src/odbc.appup.src index f1a370d925..2a6667ccd3 100644 --- a/lib/odbc/src/odbc.appup.src +++ b/lib/odbc/src/odbc.appup.src @@ -1,8 +1,8 @@ %% -*- erlang -*- {"%VSN%", [ - {"2.10.8", [{restart_application, ssl}]} + {"2.10.9", [{restart_application, ssl}]} ], [ - {"2.10.8", [{restart_application, ssl}]} + {"2.10.9", [{restart_application, ssl}]} ]}. diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk index aacf3924db..42a51be33e 100644 --- a/lib/odbc/vsn.mk +++ b/lib/odbc/vsn.mk @@ -1 +1 @@ -ODBC_VSN = 2.10.9 +ODBC_VSN = 2.10.10 diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml index ba16682f0b..589123ef73 100644 --- a/lib/orber/doc/src/notes.xml +++ b/lib/orber/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2010</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,6 +33,22 @@ </header> <section> + <title>Orber 3.6.20</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + Eliminated Dialyzer warnings when using exit or throw.</p> + <p> + Own Id: OTP-9050 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> <title>Orber 3.6.19</title> <section> diff --git a/lib/orber/include/ifr_types.hrl b/lib/orber/include/ifr_types.hrl index 144ec7f8a1..324b32bd4f 100644 --- a/lib/orber/include/ifr_types.hrl +++ b/lib/orber/include/ifr_types.hrl @@ -1,9 +1,9 @@ %%-------------------------------------------------------------------- %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the diff --git a/lib/orber/src/corba.erl b/lib/orber/src/corba.erl index ea1363742c..ecec768544 100644 --- a/lib/orber/src/corba.erl +++ b/lib/orber/src/corba.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -620,6 +620,8 @@ get_pid(Objkey) -> %% Returns : Throws the exception. %% Description: %%---------------------------------------------------------------------- +%% To avoid dialyzer warnings due to the use of exit/throw. +-spec raise(term()) -> no_return(). raise(E) -> throw({'EXCEPTION', E}). @@ -629,6 +631,8 @@ raise(E) -> %% Returns : Throws the exception. %% Description: %%---------------------------------------------------------------------- +%% To avoid dialyzer warnings due to the use of exit/throw. +-spec raise_with_state(term(), term()) -> no_return(). raise_with_state(E, State) -> throw({reply, {'EXCEPTION', E}, State}). diff --git a/lib/orber/src/orber.app.src b/lib/orber/src/orber.app.src index fe911d65a4..88df4162b6 100644 --- a/lib/orber/src/orber.app.src +++ b/lib/orber/src/orber.app.src @@ -101,7 +101,7 @@ orber_iiop_insup, orber_init, orber_reqno, orber_objkeyserver, orber_iiop_socketsup, orber_iiop_pm, orber_env]}, - {applications, [stdlib, kernel]}, + {applications, [stdlib, kernel, mnesia]}, {env, []}, {mod, {orber, []}} ]}. diff --git a/lib/orber/src/orber.erl b/lib/orber/src/orber.erl index c3d37ad1fb..665b3cb383 100644 --- a/lib/orber/src/orber.erl +++ b/lib/orber/src/orber.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1027,12 +1027,18 @@ remove_node(Node) when is_atom(Node) -> remove_tables(Tables, Node) -> - remove_tables(Tables, Node, []). + case remove_tables(Tables, Node, []) of + ok -> + ok; + {error, Node, Failed} -> + ?EFORMAT("orber:remove_node(~p) failed. Unable to remove table(s): ~p", + [Node, Failed]) + end. -remove_tables([], _, []) -> ok; +remove_tables([], _, []) -> + ok; remove_tables([], Node, Failed) -> - ?EFORMAT("orber:remove_node(~p) failed. Unable to remove table(s): ~p", - [Node, Failed]); + {error, Node, Failed}; remove_tables([T1|Trest], Node, Failed) -> case mnesia:del_table_copy(T1, Node) of {atomic, ok} -> @@ -1041,8 +1047,6 @@ remove_tables([T1|Trest], Node, Failed) -> remove_tables(Trest, Node, [{T1, Reason}|Failed]) end. - - %%----------------------------------------------------------------- %% Internal interface functions %%----------------------------------------------------------------- diff --git a/lib/orber/src/orber_socket.erl b/lib/orber/src/orber_socket.erl index 84ed193ebb..ec2cf8f42a 100644 --- a/lib/orber/src/orber_socket.erl +++ b/lib/orber/src/orber_socket.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -37,7 +37,7 @@ %%----------------------------------------------------------------- -export([start/0, connect/4, listen/3, listen/4, accept/2, accept/3, write/3, controlling_process/3, close/2, peername/2, sockname/2, - peerdata/2, peercert/2, peercert/3, sockdata/2, setopts/3, + peerdata/2, peercert/2, sockdata/2, setopts/3, clear/2, shutdown/3, post_accept/2, post_accept/3]). %%----------------------------------------------------------------- @@ -366,14 +366,6 @@ peercert(Type, _Socket) -> [?LINE, Type], ?DEBUG_LEVEL), {error, ebadsocket}. -peercert(ssl, Socket, Opts) -> - ssl:peercert(Socket, Opts); -peercert(Type, _Socket, Opts) -> - orber:dbg("[~p] orber_socket:peercert(~p, ~p);~n" - "Only available for SSL sockets.", - [?LINE, Type, Opts], ?DEBUG_LEVEL), - {error, ebadsocket}. - %%----------------------------------------------------------------- %% Get peerdata %% diff --git a/lib/orber/test/csiv2_SUITE.erl b/lib/orber/test/csiv2_SUITE.erl index e7c79b9e84..95cd8c56b3 100644 --- a/lib/orber/test/csiv2_SUITE.erl +++ b/lib/orber/test/csiv2_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -675,8 +675,8 @@ ssl_server_peercert_api(_Config) -> {ok, Socket} = ?match({ok, _}, fake_client_ORB(ssl, ServerHost, ServerPort, SSLOptions)), {ok, _PeerCert} = ?match({ok, _}, orber_socket:peercert(ssl, Socket)), - ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [pkix, subject])), - ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [ssl, subject])), +%% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [pkix, subject])), +%% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [ssl, subject])), % ?match({ok, #'Certificate'{}}, % 'OrberCSIv2':decode('Certificate', PeerCert)), destroy_fake_ORB(ssl, Socket), @@ -715,8 +715,8 @@ ssl_client_peercert_api(_Config) -> ?match(ok, ssl:ssl_accept(Socket)), {ok, _PeerCert} = ?match({ok, _}, orber_socket:peercert(ssl, Socket)), - ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [pkix, subject])), - ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [ssl, subject])), +%% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [pkix, subject])), +%% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [ssl, subject])), % ?match({ok, #'Certificate'{}}, % 'OrberCSIv2':decode('Certificate', PeerCert)), ssl:close(Socket), diff --git a/lib/orber/test/multi_ORB_SUITE.erl b/lib/orber/test/multi_ORB_SUITE.erl index 6ac514eb77..608fb23f3e 100644 --- a/lib/orber/test/multi_ORB_SUITE.erl +++ b/lib/orber/test/multi_ORB_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1391,7 +1391,7 @@ light_orber2_api(_Config) -> LocalHost = net_adm:localhost(), {ok, Node, _Host} = ?match({ok,_,_}, orber_test_lib:js_node([], - {lightweigth, ["iiop://"++LocalHost++":"++integer_to_list(orber:iiop_port())]})), + {lightweight, ["iiop://"++LocalHost++":"++integer_to_list(orber:iiop_port())]})), ?match(ok, orber:info(io)), ?match([_], orber_test_lib:remote_apply(Node, orber_env, get_lightweight_nodes,[])), diff --git a/lib/orber/test/orber_test_lib.erl b/lib/orber/test/orber_test_lib.erl index 5053a5fddc..ffc13d0e3c 100644 --- a/lib/orber/test/orber_test_lib.erl +++ b/lib/orber/test/orber_test_lib.erl @@ -301,9 +301,11 @@ start_ssl(true, Node) -> start_ssl(_, _) -> ok. -start_orber({lightweigth, Options}, Node) -> +start_orber({lightweight, Options}, Node) -> + ok = rpc:call(Node, mnesia, start, []), ok = rpc:call(Node, orber, start_lightweight, [Options]); start_orber(lightweight, Node) -> + ok = rpc:call(Node, mnesia, start, []), ok = rpc:call(Node, orber, start_lightweight, []); start_orber(_, Node) -> ok = rpc:call(Node, orber, jump_start, []). diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk index b0c5a253a2..5f17cda229 100644 --- a/lib/orber/vsn.mk +++ b/lib/orber/vsn.mk @@ -1 +1,3 @@ -ORBER_VSN = 3.6.19 + +ORBER_VSN = 3.6.20 + diff --git a/lib/os_mon/test/disksup_SUITE.erl b/lib/os_mon/test/disksup_SUITE.erl index 6e015ef74a..a3c6c7782d 100644 --- a/lib/os_mon/test/disksup_SUITE.erl +++ b/lib/os_mon/test/disksup_SUITE.erl @@ -41,10 +41,16 @@ end_per_suite(Config) when is_list(Config) -> ?line ok = application:stop(os_mon), Config. +init_per_testcase(unavailable, Config) -> + terminate(Config), + init_per_testcase(dummy, Config); init_per_testcase(_Case, Config) -> Dog = ?t:timetrap(?default_timeout), [{watchdog,Dog} | Config]. +end_per_testcase(unavailable, Config) -> + restart(Config), + end_per_testcase(dummy, Config); end_per_testcase(_Case, Config) -> Dog = ?config(watchdog, Config), ?t:timetrap_cancel(Dog), diff --git a/lib/percept/src/egd.erl b/lib/percept/src/egd.erl index 4fb5b6c46a..63e5c30572 100644 --- a/lib/percept/src/egd.erl +++ b/lib/percept/src/egd.erl @@ -42,6 +42,7 @@ %%========================================================================== %% @type egd_image() +%% @type font() %% @type point() = {integer(), integer()} %% @type color() %% @type render_option() = {render_engine, opaque} | {render_engine, alpha} diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 91e058f74e..81aedaea56 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2008</year> - <year>2008</year> + <year>2011</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -258,7 +258,7 @@ </func> <func> - <name> pkix_decode_cert(Cert, otp|plain) -> #'Certificate'{} | #'OTPCertificate'{}</name> + <name>pkix_decode_cert(Cert, otp|plain) -> #'Certificate'{} | #'OTPCertificate'{}</name> <fsummary> Decodes an asn1 der encoded pkix x509 certificate.</fsummary> <type> <v>Cert = der_encoded()</v> diff --git a/lib/public_key/src/public_key.appup.src b/lib/public_key/src/public_key.appup.src index 6b6b76d0a5..c65ac7bc99 100644 --- a/lib/public_key/src/public_key.appup.src +++ b/lib/public_key/src/public_key.appup.src @@ -1,6 +1,13 @@ %% -*- erlang -*- {"%VSN%", [ + {"0.10", + [ + {update, public_key, soft, soft_purge, soft_purge, []}, + {update, pubkey_pem, soft, soft_purge, soft_purge, []}, + {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} + ] + }, {"0.9", [ {update, public_key, soft, soft_purge, soft_purge, []}, @@ -18,12 +25,19 @@ } ], [ - {"0.9", - [ + {"0.10", + [ + {update, public_key, soft, soft_purge, soft_purge, []}, + {update, pubkey_pem, soft, soft_purge, soft_purge, []}, + {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} + ] + }, + {"0.9", + [ {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert, soft, soft_purge, soft_purge, []} - ] - }, + {update, pubkey_cert, soft, soft_purge, soft_purge, []} + ] + }, {"0.8", [ {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []}, @@ -32,5 +46,5 @@ {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}, {update, pubkey_cert, soft, soft_purge, soft_purge, []} ] - } + } ]}. diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl index fd976cb2f3..660af4e8ab 100644 --- a/lib/public_key/test/pkits_SUITE.erl +++ b/lib/public_key/test/pkits_SUITE.erl @@ -585,10 +585,10 @@ end_per_testcase(_Func, Config) -> Config. init_per_suite(Config) -> - case application:start(crypto) of + try crypto:start() of ok -> - Config; - _ -> + Config + catch _:_ -> {skip, "Crypto did not start"} end. diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index d130196c15..6c482f9c30 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -41,10 +41,10 @@ %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> - case application:start(crypto) of + try crypto:start() of ok -> - Config; - _ -> + Config + catch _:_ -> {skip, "Crypto did not start"} end. %%-------------------------------------------------------------------- diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index 334b9d792e..c99fd6fee1 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1 +1 @@ -PUBLIC_KEY_VSN = 0.10 +PUBLIC_KEY_VSN = 0.11 diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml index 5182889710..48d7b69885 100644 --- a/lib/sasl/doc/src/appup.xml +++ b/lib/sasl/doc/src/appup.xml @@ -174,11 +174,19 @@ <c>remove</c> and <c>purge</c>.</p> <pre> {add_application, Application} +{add_application, Application, Type} Application = atom() + Type = permanent | transient | temporary | load | none </pre> <p>Adding an application means that the modules defined by the <c>modules</c> key in the <c>.app</c> file are loaded using - <c>add_module</c>, then the application is started.</p> + <c>add_module</c>.</p> + <p><c>Type</c> defaults to <c>permanent</c> and specifies the start type + of the application. If <c>Type = permanent | transient | temporary</c>, + the application will be loaded and started in the corresponding way, + see <c>application(3)</c>. If <c>Type = load</c>, the application will + only be loaded. If <c>Type = none</c>, the application will be neither + loaded nor started, although the code for its modules will be loaded.</p> <pre> {remove_application, Application} Application = atom() diff --git a/lib/sasl/src/systools_rc.erl b/lib/sasl/src/systools_rc.erl index 23d1a52b66..daadb79967 100644 --- a/lib/sasl/src/systools_rc.erl +++ b/lib/sasl/src/systools_rc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -34,7 +34,7 @@ %% {add_module, Mod, [Mod]} %% {remove_module, Mod, PrePurge, PostPurge, [Mod]} %% {restart_application, Appl} -%% {add_application, Appl} +%% {add_application, Appl, Type} %% {remove_application, Appl} %% %% Low-level @@ -109,6 +109,8 @@ expand_script([I|Script]) -> {delete_module, Mod} -> [{remove, {Mod, brutal_purge, brutal_purge}}, {purge, [Mod]}]; + {add_application, Application} -> + {add_application, Application, permanent}; _ -> I end, @@ -317,14 +319,18 @@ translate_independent_instrs(Before, After, Appls, PreAppls) -> translate_application_instrs(Script, Appls, PreAppls) -> %% io:format("Appls ~n~p~n",[Appls]), L = lists:map( - fun({add_application, Appl}) -> + fun({add_application, Appl, Type}) -> case lists:keysearch(Appl, #application.name, Appls) of {value, Application} -> Mods = remove_vsn(Application#application.modules), + ApplyL = case Type of + none -> []; + load -> [{apply, {application, load, [Appl]}}]; + _ -> [{apply, {application, start, [Appl, Type]}}] + end, [{add_module, M, []} || M <- Mods] ++ - [{apply, {application, start, - [Appl, permanent]}}]; + ApplyL; false -> throw({error, {no_such_application, Appl}}) end; @@ -750,8 +756,9 @@ check_op({remove_module, Mod, PrePurge, PostPurge, Mods}) -> lists:foreach(fun(M) -> check_mod(M) end, Mods); check_op({remove_application, Appl}) -> check_appl(Appl); -check_op({add_application, Appl}) -> - check_appl(Appl); +check_op({add_application, Appl, Type}) -> + check_appl(Appl), + check_start_type(Type); check_op({restart_application, Appl}) -> check_appl(Appl); check_op(restart) -> ok; @@ -839,6 +846,13 @@ check_node(Node) -> throw({error, {bad_node, Node}}). check_appl(Appl) when is_atom(Appl) -> ok; check_appl(Appl) -> throw({error, {bad_application, Appl}}). +check_start_type(none) -> ok; +check_start_type(load) -> ok; +check_start_type(temporary) -> ok; +check_start_type(transient) -> ok; +check_start_type(permanent) -> ok; +check_start_type(T) -> throw({error, {bad_start_type, T}}). + check_func(Func) when is_atom(Func) -> ok; check_func(Func) -> throw({error, {bad_func, Func}}). diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl index 177d50be80..71bd3ca491 100644 --- a/lib/sasl/src/systools_relup.erl +++ b/lib/sasl/src/systools_relup.erl @@ -370,10 +370,10 @@ collect_appup_scripts(_, [], _, Ws, RUs) -> {RUs, Ws}. %% ToApps = [#application] %% create_add_app_scripts(FromRel, ToRel, RU0s, W0s) -> - AddedNs = [N || {N, _V, _T} <- ToRel#release.applications, + AddedNs = [{N, T} || {N, _V, T} <- ToRel#release.applications, not lists:keymember(N, 1, FromRel#release.applications)], %% io:format("Added apps: ~p~n", [AddedNs]), - RUs = [[{add_application, N}] || N <- AddedNs], + RUs = [[{add_application, N, T}] || {N, T} <- AddedNs], {RUs ++ RU0s, W0s}. diff --git a/lib/snmp/doc/src/files.mk b/lib/snmp/doc/src/files.mk index f8462098be..c906ba0cf2 100644 --- a/lib/snmp/doc/src/files.mk +++ b/lib/snmp/doc/src/files.mk @@ -65,6 +65,9 @@ XML_MANAGER_REF3_FILES = \ snmpm_network_interface_filter.xml \ snmpm_user.xml +XML_REF1_FILES = \ + $(XML_COMP_REF1_FILES) + XML_REF3_FILES = \ $(XML_APP_REF3_FILES) \ $(XML_COMP_REF3_FILES) \ diff --git a/lib/snmp/doc/src/snmpc_cmd.xml b/lib/snmp/doc/src/snmpc_cmd.xml new file mode 100644 index 0000000000..9358382a10 --- /dev/null +++ b/lib/snmp/doc/src/snmpc_cmd.xml @@ -0,0 +1,191 @@ +<?xml version="1.0" encoding="iso-8859-1" ?> +<!DOCTYPE comref SYSTEM "comref.dtd"> + +<comref> + <header> + <copyright> + <year>2011</year><year>2011</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>snmpc</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev></rev> + <file>snmpc_cmd.xml</file> + </header> + <com>snmpc(command)</com> + <comsummary>SNMP MIB compiler frontend</comsummary> + <description> + <p>The <c><![CDATA[snmpc]]></c> program provides a way to run + the SNMP MIB compiler of the Erlang system. </p> + </description> + + <funcs> + <func> + <name>snmpc [options] file.mib | file.bin</name> + <fsummary>Compile MIBs</fsummary> + <desc> + <p><c><![CDATA[snmpc]]></c> compile a SNMP MIB file, + see <seealso marker="snmpc#compile">compile/1,2</seealso> for + more info. </p> + <p>It can also be used to generate a header file (.hrl) + with definitions of Erlang constants for the objects in + the MIB, see + <seealso marker="snmpc#mib_to_hrl">mib_to_hrl/1</seealso>. </p> + </desc> + </func> + </funcs> + + <section> + <title>Compiler options</title> + <p>The following options are supported (note that most of these relate + to the compilation of the MIB file):</p> + <taglist> + <tag>--help</tag> + <item> + <p>Prints help info.</p> + </item> + + <tag>--version</tag> + <item> + <p>Prints application and mib format version.</p> + </item> + + <tag>--verbosity <em>verbosity</em></tag> + <item> + <p>Print debug info. </p> + <p><c>verbosity</c> = <c>trace</c> | <c>debug</c> | <c>log</c> | <c>info</c> | <c>silence</c></p> + <p>Defaults to <c>silence</c>.</p> + </item> + + <tag>--warnings</tag> + <item> + <p>Print warning messages. </p> + </item> + + <tag>--o <em>directory</em></tag> + <item> + <p>The directory where the compiler should place the output files. + If not specified, output files will be placed in the current working + directory.</p> + </item> + + <tag>--i <em>Directory</em></tag> + <item> + <p>Specifies the path to search for imported (compiled) MIB files. + By default, the current working directory is always included. </p> + <p>This option can be present several times, each time specifying + <em>one</em> path. </p> + </item> + + <tag>--il <em>Directory</em></tag> + <item> + <p>This option (include_lib), specifies a list of directories to + search for imported MIBs. It assumes that the first element in + the directory name corresponds to an OTP application. The compiler + will find the current installed version. For example, the value + ["snmp/mibs/"] will be replaced by ["snmp-3.1.1/mibs/"] (or what + the current version may be in the system). The current directory + and the "snmp-home"/priv/mibs/ are always listed last in the + include path. </p> + </item> + + <tag>--sgc</tag> + <item> + <p>This option (skip group check), if present, disables the + group check of the mib compiler. + That is, should the OBJECT-GROUP and the NOTIFICATION-GROUP + macro(s) be checked for correctness or not. </p> + </item> + + <tag>--dep</tag> + <item> + <p>Keep deprecated definition(s). + If not specified the compiler will ignore deprecated definitions. </p> + </item> + + <tag>--desc</tag> + <item> + <p>The DESCRIPTION field will be included. </p> + </item> + + <tag>--ref</tag> + <item> + <p>The REFERENCE field will be included. </p> + </item> + + <tag>--imp</tag> + <item> + <p>The IMPORTS field will be included. </p> + </item> + + <tag>--mi</tag> + <item> + <p>The MODULE-IDENTITY field will be included. </p> + </item> + + <tag>--mc</tag> + <item> + <p>The MODULE-COMPLIANCE field will be included. </p> + </item> + + <tag>--ac</tag> + <item> + <p>The AGENT-CAPABILITIES field will be included. </p> + </item> + + <tag>--mod <em>module</em></tag> + <item> + <p>The module which implements all the instrumentation functions. </p> + <p>The name of all instrumentation functions must be the + same as the corresponding managed object it implements. </p> + </item> + + <tag>--nd</tag> + <item> + <p>The default instrumentation functions will <em>not</em> be + used if a managed object have no instrumentation function. + Instead this will be reported as an error, and the compilation + aborts. </p> + </item> + + <tag>--rrnac</tag> + <item> + <p>This option, if present, specifies that the row name assign check + shall not be done strictly according to the SMI (which allows only + the value 1). </p> + <p>With this option, all values greater than zero is allowed (>= 1). + This means that the error will be converted to a warning. </p> + <p>By default it is not included, but if this option is present + it will be. </p> + </item> + + </taglist> + </section> + + <section> + <title>SEE ALSO</title> + <p><seealso marker="erlc">erlc(1)</seealso>, + <seealso marker="compiler:compile">compile(3)</seealso>, + <seealso marker="snmp:snmpc">snmpc(3)</seealso></p> + </section> +</comref> + diff --git a/lib/snmp/test/snmp_app_test.erl b/lib/snmp/test/snmp_app_test.erl index 64dd638f83..27a7b4af2e 100644 --- a/lib/snmp/test/snmp_app_test.erl +++ b/lib/snmp/test/snmp_app_test.erl @@ -300,6 +300,25 @@ undef_funcs(Config) when is_list(Config) -> xref:stop(XRef), analyze_undefined_function_calls(Undefs, Mods, []). +valid_undef(crypto = CalledMod) -> + case (catch CalledMod:version()) of + Version when is_list(Version) -> + %% The called module was crypto and the version + %% function returns a valid value. + %% This means that the function is + %% actually undefined... + true; + _ -> + %% The called module was crypto but the version + %% function does *not* return a valid value. + %% This means the crypto was not actually not + %% build, which is an case snmp handles. + false + end; +valid_undef(_) -> + true. + + analyze_undefined_function_calls([], _, []) -> ok; analyze_undefined_function_calls([], _, AppUndefs) -> @@ -312,14 +331,25 @@ analyze_undefined_function_calls([{{Mod, _F, _A}, _C} = AppUndef|Undefs], {Calling,Called} = AppUndef, {Mod1,Func1,Ar1} = Calling, {Mod2,Func2,Ar2} = Called, - io:format("undefined function call: " - "~n ~w:~w/~w calls ~w:~w/~w~n", - [Mod1,Func1,Ar1,Mod2,Func2,Ar2]), - analyze_undefined_function_calls(Undefs, AppModules, - [AppUndef|AppUndefs]); + %% If the called module is crypto, then we will *not* + %% fail if crypto is not built (since crypto is actually + %% not built for all platforms) + case valid_undef(Mod2) of + true -> + io:format("undefined function call: " + "~n ~w:~w/~w calls ~w:~w/~w~n", + [Mod1,Func1,Ar1,Mod2,Func2,Ar2]), + analyze_undefined_function_calls( + Undefs, AppModules, [AppUndef|AppUndefs]); + false -> + io:format("skipping ~p (calling ~w:~w/~w)~n", + [Mod, Mod2, Func2, Ar2]), + analyze_undefined_function_calls(Undefs, + AppModules, AppUndefs) + end; false -> - io:format("dropping ~p~n", [Mod]), - analyze_undefined_function_calls(Undefs, AppModules, AppUndefs) + io:format("dropping ~p~n", [Mod]), + analyze_undefined_function_calls(Undefs, AppModules, AppUndefs) end. %% This function is used simply to avoid cut-and-paste errors later... diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl index a72dd0cc22..e38a99d413 100644 --- a/lib/snmp/test/snmp_manager_config_test.erl +++ b/lib/snmp/test/snmp_manager_config_test.erl @@ -169,36 +169,41 @@ all() -> groups() -> [{start_and_stop, [], - [simple_start_and_stop, start_without_mandatory_opts1, - start_without_mandatory_opts2, - start_with_all_valid_opts, start_with_unknown_opts, - start_with_incorrect_opts, - start_with_invalid_manager_conf_file1, - start_with_invalid_users_conf_file1, - start_with_invalid_agents_conf_file1, - start_with_invalid_usm_conf_file1]}, - {normal_op, [], - [{group, system}, {group, agents}, {group, users}, - {group, usm_users}, {group, counter}, - {group, stats_counter}]}, - {system, [], [simple_system_op]}, - {users, [], - [register_user_using_file, register_user_using_function, - register_user_failed_using_function1]}, - {agents, [], - [register_agent_using_file, - register_agent_using_function, - register_agent_failed_using_function1]}, - {usm_users, [], - [register_usm_user_using_file, - register_usm_user_using_function, - register_usm_user_failed_using_function1, - update_usm_user_info]}, - {counter, [], [create_and_increment]}, - {stats_counter, [], [stats_create_and_increment]}, - {tickets, [], [otp_7219, {group, otp_8395}]}, - {otp_8395, [], - [otp_8395_1, otp_8395_2, otp_8395_3, otp_8395_4]}]. + [simple_start_and_stop, + start_without_mandatory_opts1, + start_without_mandatory_opts2, + start_with_all_valid_opts, start_with_unknown_opts, + start_with_incorrect_opts, + start_with_invalid_manager_conf_file1, + start_with_invalid_users_conf_file1, + start_with_invalid_agents_conf_file1, + start_with_invalid_usm_conf_file1]}, + {normal_op, [], + [{group, system}, + {group, agents}, + {group, users}, + {group, usm_users}, + {group, counter}, + {group, stats_counter}]}, + {system, [], [simple_system_op]}, + {users, [], + [register_user_using_file, + register_user_using_function, + register_user_failed_using_function1]}, + {agents, [], + [register_agent_using_file, + register_agent_using_function, + register_agent_failed_using_function1]}, + {usm_users, [], + [register_usm_user_using_file, + register_usm_user_using_function, + register_usm_user_failed_using_function1, + update_usm_user_info]}, + {counter, [], [create_and_increment]}, + {stats_counter, [], [stats_create_and_increment]}, + {tickets, [], [otp_7219, {group, otp_8395}]}, + {otp_8395, [], + [otp_8395_1, otp_8395_2, otp_8395_3, otp_8395_4]}]. init_per_group(_GroupName, Config) -> Config. @@ -816,7 +821,10 @@ start_with_invalid_users_conf_file1(Conf) when is_list(Conf) -> p("start"), process_flag(trap_exit, true), ConfDir = ?config(manager_conf_dir, Conf), - DbDir = ?config(manager_db_dir, Conf), + DbDir = ?config(manager_db_dir, Conf), + + verify_dir_existing(conf, ConfDir), + verify_dir_existing(db, DbDir), Opts = [{versions, [v1]}, {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], @@ -917,7 +925,10 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> p("start"), process_flag(trap_exit, true), ConfDir = ?config(manager_conf_dir, Conf), - DbDir = ?config(manager_db_dir, Conf), + DbDir = ?config(manager_db_dir, Conf), + + verify_dir_existing(conf, ConfDir), + verify_dir_existing(db, DbDir), Opts = [{versions, [v1]}, {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], @@ -2022,7 +2033,6 @@ register_usm_user_using_file(Conf) when is_list(Conf) -> %% -- p("done"), ok. -%% ?SKIP(not_yet_implemented). %% @@ -2651,9 +2661,21 @@ write_usm_conf2(Dir, Str) -> write_conf_file(Dir, File, Str) -> - ?line {ok, Fd} = file:open(filename:join(Dir, File), write), - ?line ok = io:format(Fd, "~s", [Str]), - file:close(Fd). + case file:open(filename:join(Dir, File), write) of + {ok, Fd} -> + ?line ok = io:format(Fd, "~s", [Str]), + file:close(Fd); + {error, Reason} -> + Info = + [{dir, Dir, case (catch file:read_file_info(Dir)) of + {ok, FI} -> + FI; + _ -> + undefined + end}, + {file, File}], + exit({failed_writing_conf_file, Info, Reason}) + end. maybe_start_crypto() -> @@ -2679,6 +2701,17 @@ maybe_stop_crypto() -> %% ------ +verify_dir_existing(DirName, Dir) -> + case file:read_file_info(Dir) of + {ok, _} -> + ok; + {error, Reason} -> + exit({non_existing_dir, DirName, Dir, Reason}) + end. + + +%% ------ + str(X) -> lists:flatten(io_lib:format("~w", [X])). diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index daf7b77527..cd5c9281cd 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -269,6 +269,13 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | <p> {bad_cert, cert_expired}, {bad_cert, invalid_issuer}, {bad_cert, invalid_signature}, {bad_cert, unknown_ca}, {bad_cert, name_not_permitted}, {bad_cert, missing_basic_constraint}, {bad_cert, invalid_key_usage}</p> </item> + <tag>{hibernate_after, integer()|undefined}</tag> + <item>When an integer-value is specified, the <code>ssl_connection</code> + will go into hibernation after the specified number of milliseconds + of inactivity, thus reducing its memory footprint. When + <code>undefined</code> is specified (this is the default), the process + will never go into hibernation. + </item> </taglist> </section> diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index e6a8c557fc..d3e426f254 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,12 +1,14 @@ %% -*- erlang -*- {"%VSN%", [ + {"4.1.3", [{restart_application, ssl}]}, {"4.1.2", [{restart_application, ssl}]}, {"4.1.1", [{restart_application, ssl}]}, {"4.1", [{restart_application, ssl}]}, {"4.0.1", [{restart_application, ssl}]} ], [ + {"4.1.3", [{restart_application, ssl}]}, {"4.1.2", [{restart_application, ssl}]}, {"4.1.1", [{restart_application, ssl}]}, {"4.1", [{restart_application, ssl}]}, diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index b85188b878..3512e194bc 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -60,7 +60,7 @@ {keyfile, path()} | {password, string()} | {cacerts, [der_encoded()]} | {cacertfile, path()} | {dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | - {reuse_session, fun()}. + {reuse_session, fun()} | {hibernate_after, integer()|undefined}. -type verify_type() :: verify_none | verify_peer. -type path() :: string(). @@ -711,7 +711,8 @@ handle_options(Opts0, _Role) -> reuse_sessions = handle_option(reuse_sessions, Opts, true), secure_renegotiate = handle_option(secure_renegotiate, Opts, false), renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT), - debug = handle_option(debug, Opts, []) + debug = handle_option(debug, Opts, []), + hibernate_after = handle_option(hibernate_after, Opts, undefined) }, CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}), @@ -720,7 +721,7 @@ handle_options(Opts0, _Role) -> depth, cert, certfile, key, keyfile, password, cacerts, cacertfile, dh, dhfile, ciphers, debug, reuse_session, reuse_sessions, ssl_imp, - cb_info, renegotiate_at, secure_renegotiate], + cb_info, renegotiate_at, secure_renegotiate, hibernate_after], SockOpts = lists:foldl(fun(Key, PropList) -> proplists:delete(Key, PropList) @@ -827,6 +828,10 @@ validate_option(renegotiate_at, Value) when is_integer(Value) -> validate_option(debug, Value) when is_list(Value); Value == true -> Value; +validate_option(hibernate_after, undefined) -> + undefined; +validate_option(hibernate_after, Value) when is_integer(Value), Value >= 0 -> + Value; validate_option(Opt, Value) -> throw({error, {eoptions, {Opt, Value}}}). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 85245f4342..574e1e9468 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -289,9 +289,9 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) -> %% gen_fsm callbacks %%==================================================================== %%-------------------------------------------------------------------- --spec init(list()) -> {ok, state_name(), #state{}} | {stop, term()}. +-spec init(list()) -> {ok, state_name(), #state{}, timeout()} | {stop, term()}. %% Possible return values not used now. -%% | {ok, state_name(), #state{}, timeout()} | +%% | {ok, state_name(), #state{}} | %% ignore %% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or %% gen_fsm:start_link/3,4, this function is called by the new process to @@ -311,7 +311,7 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, session_cache = CacheRef, private_key = Key, diffie_hellman_params = DHParams}, - {ok, hello, State} + {ok, hello, State, get_timeout(State)} catch throw:Error -> {stop, Error} @@ -412,6 +412,9 @@ hello(Hello = #client_hello{client_version = ClientVersion}, {stop, normal, State} end; +hello(timeout, State) -> + { next_state, hello, State, hibernate }; + hello(Msg, State) -> handle_unexpected_message(Msg, hello, State). %%-------------------------------------------------------------------- @@ -460,6 +463,9 @@ abbreviated(#finished{verify_data = Data} = Finished, {stop, normal, State} end; +abbreviated(timeout, State) -> + { next_state, abbreviated, State, hibernate }; + abbreviated(Msg, State) -> handle_unexpected_message(Msg, abbreviated, State). @@ -582,6 +588,9 @@ certify(#client_key_exchange{exchange_keys = Keys}, {stop, normal, State} end; +certify(timeout, State) -> + { next_state, certify, State, hibernate }; + certify(Msg, State) -> handle_unexpected_message(Msg, certify, State). @@ -664,6 +673,9 @@ cipher(#finished{verify_data = Data} = Finished, {stop, normal, State} end; +cipher(timeout, State) -> + { next_state, cipher, State, hibernate }; + cipher(Msg, State) -> handle_unexpected_message(Msg, cipher, State). @@ -693,6 +705,9 @@ connection(#hello_request{}, #state{host = Host, port = Port, connection(#client_hello{} = Hello, #state{role = server} = State) -> hello(Hello, State); +connection(timeout, State) -> + {next_state, connection, State, hibernate}; + connection(Msg, State) -> handle_unexpected_message(Msg, connection, State). %%-------------------------------------------------------------------- @@ -705,7 +720,7 @@ connection(Msg, State) -> %% the event. Not currently used! %%-------------------------------------------------------------------- handle_event(_Event, StateName, State) -> - {next_state, StateName, State}. + {next_state, StateName, State, get_timeout(State)}. %%-------------------------------------------------------------------- -spec handle_sync_event(term(), from(), state_name(), #state{}) -> @@ -736,7 +751,8 @@ handle_sync_event({application_data, Data0}, From, connection, {Msgs, [], ConnectionStates} -> Result = Transport:send(Socket, Msgs), {reply, Result, - connection, State#state{connection_states = ConnectionStates}}; + connection, State#state{connection_states = ConnectionStates}, + get_timeout(State)}; {Msgs, RestData, ConnectionStates} -> if Msgs =/= [] -> @@ -749,12 +765,14 @@ handle_sync_event({application_data, Data0}, From, connection, renegotiation = {true, internal}}) end catch throw:Error -> - {reply, Error, connection, State} + {reply, Error, connection, State, get_timeout(State)} end; handle_sync_event({application_data, Data}, From, StateName, #state{send_queue = Queue} = State) -> %% In renegotiation priorities handshake, send data when handshake is finished - {next_state, StateName, State#state{send_queue = queue:in({From, Data}, Queue)}}; + {next_state, StateName, + State#state{send_queue = queue:in({From, Data}, Queue)}, + get_timeout(State)}; handle_sync_event(start, From, hello, State) -> hello(start, State#state{from = From}); @@ -768,9 +786,9 @@ handle_sync_event(start, From, hello, State) -> %% here to make sure it is the users problem and not owers if %% they upgrade a active socket. handle_sync_event(start, _, connection, State) -> - {reply, connected, connection, State}; + {reply, connected, connection, State, get_timeout(State)}; handle_sync_event(start, From, StateName, State) -> - {next_state, StateName, State#state{from = From}}; + {next_state, StateName, State#state{from = From}, get_timeout(State)}; handle_sync_event(close, _, StateName, State) -> %% Run terminate before returning @@ -796,7 +814,7 @@ handle_sync_event({shutdown, How0}, _, StateName, case Transport:shutdown(Socket, How0) of ok -> - {reply, ok, StateName, State}; + {reply, ok, StateName, State, get_timeout(State)}; Error -> {stop, normal, Error, State} end; @@ -807,30 +825,33 @@ handle_sync_event({recv, N}, From, connection = StateName, State0) -> %% Doing renegotiate wait with handling request until renegotiate is %% finished. Will be handled by next_state_connection/2. handle_sync_event({recv, N}, From, StateName, State) -> - {next_state, StateName, State#state{bytes_to_read = N, from = From, - recv_during_renegotiation = true}}; + {next_state, StateName, + State#state{bytes_to_read = N, from = From, + recv_during_renegotiation = true}, + get_timeout(State)}; handle_sync_event({new_user, User}, _From, StateName, State =#state{user_application = {OldMon, _}}) -> NewMon = erlang:monitor(process, User), erlang:demonitor(OldMon, [flush]), - {reply, ok, StateName, State#state{user_application = {NewMon,User}}}; + {reply, ok, StateName, State#state{user_application = {NewMon,User}}, + get_timeout(State)}; handle_sync_event({get_opts, OptTags}, _From, StateName, #state{socket = Socket, socket_options = SockOpts} = State) -> OptsReply = get_socket_opts(Socket, OptTags, SockOpts, []), - {reply, OptsReply, StateName, State}; + {reply, OptsReply, StateName, State, get_timeout(State)}; handle_sync_event(sockname, _From, StateName, #state{socket = Socket} = State) -> SockNameReply = inet:sockname(Socket), - {reply, SockNameReply, StateName, State}; + {reply, SockNameReply, StateName, State, get_timeout(State)}; handle_sync_event(peername, _From, StateName, #state{socket = Socket} = State) -> PeerNameReply = inet:peername(Socket), - {reply, PeerNameReply, StateName, State}; + {reply, PeerNameReply, StateName, State, get_timeout(State)}; handle_sync_event({set_opts, Opts0}, _From, StateName, #state{socket_options = Opts1, @@ -840,27 +861,27 @@ handle_sync_event({set_opts, Opts0}, _From, StateName, State1 = State0#state{socket_options = Opts}, if Opts#socket_options.active =:= false -> - {reply, ok, StateName, State1}; + {reply, ok, StateName, State1, get_timeout(State1)}; Buffer =:= <<>>, Opts1#socket_options.active =:= false -> %% Need data, set active once {Record, State2} = next_record_if_active(State1), case next_state(StateName, Record, State2) of - {next_state, StateName, State} -> - {reply, ok, StateName, State}; + {next_state, StateName, State, Timeout} -> + {reply, ok, StateName, State, Timeout}; {stop, Reason, State} -> {stop, Reason, State} end; Buffer =:= <<>> -> %% Active once already set - {reply, ok, StateName, State1}; + {reply, ok, StateName, State1, get_timeout(State1)}; true -> case application_data(<<>>, State1) of Stop = {stop,_,_} -> Stop; {Record, State2} -> case next_state(StateName, Record, State2) of - {next_state, StateName, State} -> - {reply, ok, StateName, State}; + {next_state, StateName, State, Timeout} -> + {reply, ok, StateName, State, Timeout}; {stop, Reason, State} -> {stop, Reason, State} end @@ -871,7 +892,7 @@ handle_sync_event(renegotiate, From, connection, State) -> renegotiate(State#state{renegotiation = {true, From}}); handle_sync_event(renegotiate, _, StateName, State) -> - {reply, {error, already_renegotiating}, StateName, State}; + {reply, {error, already_renegotiating}, StateName, State, get_timeout(State)}; handle_sync_event(info, _, StateName, #state{negotiated_version = Version, @@ -879,19 +900,19 @@ handle_sync_event(info, _, StateName, AtomVersion = ssl_record:protocol_version(Version), {reply, {ok, {AtomVersion, ssl_cipher:suite_definition(Suite)}}, - StateName, State}; + StateName, State, get_timeout(State)}; handle_sync_event(session_info, _, StateName, #state{session = #session{session_id = Id, cipher_suite = Suite}} = State) -> {reply, [{session_id, Id}, {cipher_suite, ssl_cipher:suite_definition(Suite)}], - StateName, State}; + StateName, State, get_timeout(State)}; handle_sync_event(peer_certificate, _, StateName, #state{session = #session{peer_certificate = Cert}} = State) -> - {reply, {ok, Cert}, StateName, State}. + {reply, {ok, Cert}, StateName, State, get_timeout(State)}. %%-------------------------------------------------------------------- -spec handle_info(msg(),state_name(), #state{}) -> @@ -955,7 +976,7 @@ handle_info({'DOWN', MonitorRef, _, _, _}, _, handle_info(Msg, StateName, State) -> Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [Msg]), error_logger:info_report(Report), - {next_state, StateName, State}. + {next_state, StateName, State, get_timeout(State)}. %%-------------------------------------------------------------------- -spec terminate(reason(), state_name(), #state{}) -> term(). @@ -1778,7 +1799,7 @@ handle_tls_handshake(Handle, StateName, #state{tls_packets = [Packet]} = State) handle_tls_handshake(Handle, StateName, #state{tls_packets = [Packet | Packets]} = State0) -> FsmReturn = {next_state, StateName, State0#state{tls_packets = Packets}}, case Handle(Packet, FsmReturn) of - {next_state, NextStateName, State} -> + {next_state, NextStateName, State, _Timeout} -> handle_tls_handshake(Handle, NextStateName, State); {stop, _,_} = Stop -> Stop @@ -1789,11 +1810,11 @@ next_state(_, #alert{} = Alert, #state{negotiated_version = Version} = State) -> {stop, normal, State}; next_state(Next, no_record, State) -> - {next_state, Next, State}; + {next_state, Next, State, get_timeout(State)}; next_state(Next, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, State) -> Alerts = decode_alerts(EncAlerts), - handle_alerts(Alerts, {next_state, Next, State}); + handle_alerts(Alerts, {next_state, Next, State, get_timeout(State)}); next_state(StateName, #ssl_tls{type = ?HANDSHAKE, fragment = Data}, State0 = #state{tls_handshake_buffer = Buf0, negotiated_version = Version}) -> @@ -2044,7 +2065,7 @@ handle_alerts([], Result) -> handle_alerts(_, {stop, _, _} = Stop) -> %% If it is a fatal alert immediately close Stop; -handle_alerts([Alert | Alerts], {next_state, StateName, State}) -> +handle_alerts([Alert | Alerts], {next_state, StateName, State, _Timeout}) -> handle_alerts(Alerts, handle_alert(Alert, StateName, State)). handle_alert(#alert{level = ?FATAL} = Alert, StateName, @@ -2225,3 +2246,8 @@ linux_workaround_transport_delivery_problems(#alert{level = ?FATAL}, Socket) -> end; linux_workaround_transport_delivery_problems(_, _) -> ok. + +get_timeout(#state{ssl_options=#ssl_options{hibernate_after=undefined}}) -> + infinity; +get_timeout(#state{ssl_options=#ssl_options{hibernate_after=HibernateAfter}}) -> + HibernateAfter. diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 715941e3ad..c28daa271e 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -98,7 +98,11 @@ reuse_sessions, % boolean() renegotiate_at, secure_renegotiate, - debug % + debug, + hibernate_after % undefined if not hibernating, + % or number of ms of inactivity + % after which ssl_connection will + % go into hibernation }). -record(socket_options, diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index 823401c863..fd3b6d06ad 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2010. All Rights Reserved. +# Copyright Ericsson AB 1999-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -60,6 +60,7 @@ ERL_FILES = $(MODULES:%=%.erl) HRL_FILES = ssl_test_MACHINE.hrl HRL_FILES_SRC = \ + ssl_int.hrl \ ssl_alert.hrl \ ssl_handshake.hrl diff --git a/lib/ssl/test/old_ssl_dist_SUITE.erl b/lib/ssl/test/old_ssl_dist_SUITE.erl index 6a072c9d98..4544fb616a 100644 --- a/lib/ssl/test/old_ssl_dist_SUITE.erl +++ b/lib/ssl/test/old_ssl_dist_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -62,9 +62,15 @@ end_per_group(_GroupName, Config) -> init_per_suite(Config) -> - add_ssl_opts_config(Config). + try crypto:start() of + ok -> + add_ssl_opts_config(Config) + catch _:_ -> + {skip, "Crypto did not start"} + end. end_per_suite(Config) -> + application:stop(crypto), Config. init_per_testcase(Case, Config) when list(Config) -> diff --git a/lib/ssl/test/old_transport_accept_SUITE.erl b/lib/ssl/test/old_transport_accept_SUITE.erl index 21ee0690b1..6f0c8e456b 100644 --- a/lib/ssl/test/old_transport_accept_SUITE.erl +++ b/lib/ssl/test/old_transport_accept_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -57,9 +57,15 @@ groups() -> []. init_per_suite(Config) -> - Config. + try crypto:start() of + ok -> + Config + catch _:_ -> + {skip, "Crypto did not start"} + end. end_per_suite(_Config) -> + application:stop(crypto), ok. init_per_group(_GroupName, Config) -> diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 87d5fc8d71..4f0907027f 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -29,6 +29,7 @@ -include_lib("public_key/include/public_key.hrl"). -include("ssl_alert.hrl"). +-include("ssl_int.hrl"). -define('24H_in_sec', 86400). -define(TIMEOUT, 60000). @@ -48,7 +49,7 @@ %%-------------------------------------------------------------------- init_per_suite(Config0) -> Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2), - case application:start(crypto) of + try crypto:start() of ok -> application:start(public_key), ssl:start(), @@ -61,8 +62,8 @@ init_per_suite(Config0) -> Config1 = ssl_test_lib:make_dsa_cert(Config0), Config = ssl_test_lib:cert_options(Config1), - [{watchdog, Dog} | Config]; - _ -> + [{watchdog, Dog} | Config] + catch _:_ -> {skip, "Crypto did not start"} end. %%-------------------------------------------------------------------- @@ -250,7 +251,9 @@ all() -> unknown_server_ca_accept_backwardscompatibilty, %%different_ca_peer_sign, no_reuses_session_server_restart_new_cert, - no_reuses_session_server_restart_new_cert_file, reuseaddr]. + no_reuses_session_server_restart_new_cert_file, reuseaddr, + hibernate + ]. groups() -> []. @@ -3319,6 +3322,45 @@ reuseaddr(Config) when is_list(Config) -> ssl_test_lib:close(Client1). %%-------------------------------------------------------------------- + +hibernate(doc) -> + ["Check that an SSL connection that is started with option " + "{hibernate_after, 1000} indeed hibernates after 1000ms of " + "inactivity"]; + +hibernate(suite) -> + []; + +hibernate(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + {Client, #sslsocket{pid=Pid}} = ssl_test_lib:start_client([return_socket, + {node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active, []}}, + {options, [{hibernate_after, 1000}|ClientOpts]}]), + + { current_function, { _M, _F, _A } } = + process_info(Pid, current_function), + + timer:sleep(1100), + + { current_function, { erlang, hibernate, 3} } = + process_info(Pid, current_function), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- send_recv_result(Socket) -> diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 1ecf55d6e8..d22d5d2954 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -53,7 +53,7 @@ %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> - case application:start(crypto) of + try crypto:start() of ok -> application:start(public_key), ssl:start(), @@ -61,8 +61,8 @@ init_per_suite(Config) -> (catch make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config))), test_server:format("Make certs ~p~n", [Result]), - ssl_test_lib:cert_options(Config); - _ -> + ssl_test_lib:cert_options(Config) + catch _:_ -> {skip, "Crypto did not start"} end. %%-------------------------------------------------------------------- diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl index f57d7fa0e8..24e86b3913 100644 --- a/lib/ssl/test/ssl_payload_SUITE.erl +++ b/lib/ssl/test/ssl_payload_SUITE.erl @@ -37,13 +37,13 @@ %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> - case application:start(crypto) of + try crypto:start() of ok -> application:start(public_key), ssl:start(), make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config)), - ssl_test_lib:cert_options(Config); - _ -> + ssl_test_lib:cert_options(Config) + catch _:_ -> {skip, "Crypto did not start"} end. %%-------------------------------------------------------------------- diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index b47efe0941..a43b9ab586 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -47,7 +47,7 @@ %%-------------------------------------------------------------------- init_per_suite(Config0) -> Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2), - case application:start(crypto) of + try crypto:start() of ok -> application:start(public_key), ssl:start(), @@ -60,8 +60,8 @@ init_per_suite(Config0) -> Config1 = ssl_test_lib:make_dsa_cert(Config0), Config = ssl_test_lib:cert_options(Config1), - [{watchdog, Dog} | Config]; - _ -> + [{watchdog, Dog} | Config] + catch _:_ -> {skip, "Crypto did not start"} end. diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index f6ccbe85e3..8c639aa312 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -128,12 +128,14 @@ remove_close_msg(ReconnectTimes) -> remove_close_msg(ReconnectTimes -1) end. - start_client(Args) -> - Result = spawn_link(?MODULE, run_client, [Args]), + Result = spawn_link(?MODULE, run_client, [lists:delete(return_socket, Args)]), receive - connected -> - Result + { connected, Socket } -> + case lists:member(return_socket, Args) of + true -> { Result, Socket }; + false -> Result + end end. run_client(Opts) -> @@ -145,7 +147,7 @@ run_client(Opts) -> test_server:format("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]), case rpc:call(Node, ssl, connect, [Host, Port, Options]) of {ok, Socket} -> - Pid ! connected, + Pid ! { connected, Socket }, test_server:format("Client: connected~n", []), %% In specail cases we want to know the client port, it will %% be indicated by sending {port, 0} in options list! diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 4ab8fe3273..64a6a9eaf8 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -50,7 +50,7 @@ init_per_suite(Config0) -> false -> {skip, "Openssl not found"}; _ -> - case application:start(crypto) of + try crypto:start() of ok -> application:start(public_key), ssl:start(), @@ -60,8 +60,8 @@ init_per_suite(Config0) -> test_server:format("Make certs ~p~n", [Result]), Config1 = ssl_test_lib:make_dsa_cert(Config0), Config = ssl_test_lib:cert_options(Config1), - [{watchdog, Dog} | Config]; - _ -> + [{watchdog, Dog} | Config] + catch _:_ -> {skip, "Crypto did not start"} end end. diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index a4be7bb889..2f1edfa186 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1,2 +1 @@ - -SSL_VSN = 4.1.3 +SSL_VSN = 4.1.4 diff --git a/lib/test_server/src/ts_install_cth.erl b/lib/test_server/src/ts_install_cth.erl index f8b4e5a4f8..d1a24525ab 100644 --- a/lib/test_server/src/ts_install_cth.erl +++ b/lib/test_server/src/ts_install_cth.erl @@ -112,7 +112,7 @@ pre_init_per_suite(_Suite,Config,State) -> catch Error:Reason -> Stack = erlang:get_stacktrace(), ct:pal("~p failed! ~p:{~p,~p}",[?MODULE,Error,Reason,Stack]), - {fail,{?MODULE,{Error,Reason, Stack}}} + {{fail,{?MODULE,{Error,Reason, Stack}}},State} end. %% @doc Called after init_per_suite. diff --git a/lib/xmerl/src/xmerl_sax_parser_utf16be.erlsrc b/lib/xmerl/src/xmerl_sax_parser_utf16be.erlsrc index fae5346e6a..5c995a5a9c 100644 --- a/lib/xmerl/src/xmerl_sax_parser_utf16be.erlsrc +++ b/lib/xmerl/src/xmerl_sax_parser_utf16be.erlsrc @@ -2,7 +2,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -35,6 +35,6 @@ %% STRING_REST and STRING_UNBOUND_REST is only different in the list case -define(STRING_UNBOUND_REST(MatchChar, Rest), <<MatchChar/big-utf16, Rest/binary>>). --define(BYTE_ORDER_MARK_1, undefined). +-define(BYTE_ORDER_MARK_1, undefined_bom1). -define(BYTE_ORDER_MARK_2, <<16#FE>>). -define(BYTE_ORDER_MARK_REST(Rest), <<16#FE, 16#FF, Rest/binary>>). diff --git a/lib/xmerl/src/xmerl_sax_parser_utf16le.erlsrc b/lib/xmerl/src/xmerl_sax_parser_utf16le.erlsrc index 5e1f0a217c..5c6ca0caba 100644 --- a/lib/xmerl/src/xmerl_sax_parser_utf16le.erlsrc +++ b/lib/xmerl/src/xmerl_sax_parser_utf16le.erlsrc @@ -2,7 +2,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -35,6 +35,6 @@ %% STRING_REST and STRING_UNBOUND_REST is only different in the list case -define(STRING_UNBOUND_REST(MatchChar, Rest), <<MatchChar/little-utf16, Rest/binary>>). --define(BYTE_ORDER_MARK_1, undefined). +-define(BYTE_ORDER_MARK_1, undefined_bom1). -define(BYTE_ORDER_MARK_2, <<16#FF>>). -define(BYTE_ORDER_MARK_REST(Rest), <<16#FF, 16#FE, Rest/binary>>). diff --git a/lib/xmerl/src/xmerl_uri.erl b/lib/xmerl/src/xmerl_uri.erl index d8edb2e6e1..a0c6f1c2a7 100644 --- a/lib/xmerl/src/xmerl_uri.erl +++ b/lib/xmerl/src/xmerl_uri.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -359,9 +359,9 @@ scan_host(C0) -> %% Hex4=<?HEX -> %% {C1,lists:reverse(lists:append(IPv6address))}; {C1,Hostname,[A|_HostF]} -> - {C1,lists:reverse(lists:append(Hostname))}; - _ -> - {error,no_host} + {C1,lists:reverse(lists:append(Hostname))} +%% _ -> +%% {error,no_host} end. scan_host2([H|C0],Acc,CurF,Host,HostF) when $0=<H,H=<$9 -> |