Skip to content

Commit c4582e0

Browse files
author
José Valim
committed
Clarify attributes and exit signals in the language
1 parent c80d215 commit c4582e0

File tree

2 files changed

+86
-39
lines changed

2 files changed

+86
-39
lines changed

lib/elixir/lib/kernel.ex

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,56 @@ defmodule Kernel do
183183
184184
## Examples
185185
186+
When a process reaches its end, by default it exits with
187+
reason `:normal`. You can also call it explicitly if you
188+
want to terminate a process but not signal any failure:
189+
186190
exit(:normal)
191+
192+
In case something goes wrong, you can also use `exit/1` with
193+
a different reason:
194+
187195
exit(:seems_bad)
188196
197+
If the reason is not `:normal`, all linked process to the
198+
exited process will crash (unless they are trapping exits).
199+
200+
## OTP exits
201+
202+
Exits are used by OTP to determine if a process exited abnormally
203+
or not. The following exits are considered "normal":
204+
205+
* `exit(:normal)`
206+
* `exit(:shutdown)`
207+
* `exit({:shutdown, term})`
208+
209+
Exiting with any other reason is considered abnormal and treated
210+
as a crash. This means the default supervisor behaviour kicks in,
211+
error reports are emitted, etc.
212+
213+
This behaviour is relied on in many different places. For example,
214+
`ExUnit` uses `exit(:shutdown)` when exiting the test process to
215+
signal linked processes, supervision trees and so on to politely
216+
shutdown too.
217+
218+
## CLI exits
219+
220+
Building on top of the exit signals mentioned above, if the
221+
process started by the command line exits with any of the three
222+
reasons above, its exit is considered normal and the Operating
223+
System process will exit with status 0.
224+
225+
It is, however, possible to customize the Operating System exit
226+
signal by invoking:
227+
228+
exit({:shutdown, integer})
229+
230+
This will cause the OS process to exit with the status given by
231+
`integer` while signaling all linked OTP processes to politely
232+
shutdown.
233+
234+
Any other exit reason will cause the OS process to exit with
235+
status `1` and linked OTP processes to crash.
189236
"""
190237
@spec exit(term) :: no_return
191238
def exit(reason) do

lib/elixir/lib/module.ex

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -766,15 +766,9 @@ defmodule Module do
766766
767767
@foo
768768
769-
Expands to:
769+
Expands close to:
770770
771-
Module.get_attribute(__MODULE__, :foo, [{Module, :func, 0, [file: "module.ex", line: 1]}])
772-
773-
Notice the third argument may be given to indicate a stacktrace
774-
to be emitted when the attribute was not previously defined.
775-
The default value for `warn` is nil for direct calls but the `@foo`
776-
macro sets it to the proper stacktrace automatically, warning
777-
every time `@foo` is used but not set previously.
771+
Module.get_attribute(__MODULE__, :foo)
778772
779773
## Examples
780774
@@ -788,37 +782,9 @@ defmodule Module do
788782
end
789783
790784
"""
791-
@spec get_attribute(module, atom, warn :: nil | [tuple]) :: term
792-
def get_attribute(module, key, warn \\ nil) when
793-
is_atom(key) and (is_list(warn) or nil?(warn)) do
794-
assert_not_compiled!(:get_attribute, module)
795-
table = data_table_for(module)
796-
797-
case :ets.lookup(table, key) do
798-
[{^key, val}] -> val
799-
[] ->
800-
acc = :ets.lookup_element(table, :__acc_attributes, 2)
801-
802-
cond do
803-
:lists.member(key, acc) ->
804-
[]
805-
is_list(warn) ->
806-
:elixir_errors.warn warn_info(warn), "undefined module attribute @#{key}, " <>
807-
"please remove access to @#{key} or explicitly set it to nil before access"
808-
nil
809-
true ->
810-
nil
811-
end
812-
end
813-
end
814-
815-
defp warn_info([entry|_]) do
816-
opts = elem(entry, tuple_size(entry) - 1)
817-
Exception.format_file_line(Keyword.get(opts, :file), Keyword.get(opts, :line)) <> " "
818-
end
819-
820-
defp warn_info([]) do
821-
""
785+
@spec get_attribute(atom, atom) :: term
786+
def get_attribute(module, key) do
787+
get_attribute(module, key, nil)
822788
end
823789

824790
@doc """
@@ -832,10 +798,12 @@ defmodule Module do
832798
end
833799
834800
"""
801+
@spec delete_attribute(atom, atom) :: :ok
835802
def delete_attribute(module, key) when is_atom(key) do
836803
assert_not_compiled!(:delete_attribute, module)
837804
table = data_table_for(module)
838805
:ets.delete(table, key)
806+
:ok
839807
end
840808

841809
@doc """
@@ -935,6 +903,38 @@ defmodule Module do
935903
:ets.insert(table, {key, new})
936904
end
937905

906+
@doc false
907+
def get_attribute(module, key, warn) when is_atom(key) and (is_list(warn) or nil?(warn)) do
908+
assert_not_compiled!(:get_attribute, module)
909+
table = data_table_for(module)
910+
911+
case :ets.lookup(table, key) do
912+
[{^key, val}] -> val
913+
[] ->
914+
acc = :ets.lookup_element(table, :__acc_attributes, 2)
915+
916+
cond do
917+
:lists.member(key, acc) ->
918+
[]
919+
is_list(warn) ->
920+
:elixir_errors.warn warn_info(warn), "undefined module attribute @#{key}, " <>
921+
"please remove access to @#{key} or explicitly set it to nil before access"
922+
nil
923+
true ->
924+
nil
925+
end
926+
end
927+
end
928+
929+
defp warn_info([entry|_]) do
930+
opts = elem(entry, tuple_size(entry) - 1)
931+
Exception.format_file_line(Keyword.get(opts, :file), Keyword.get(opts, :line)) <> " "
932+
end
933+
934+
defp warn_info([]) do
935+
""
936+
end
937+
938938
## Helpers
939939

940940
defp normalize_attribute(:on_load, atom) when is_atom(atom) do

0 commit comments

Comments
 (0)