Files
n8n-openai-adapter/lib/elixir/lib/kernel/parallel_require.ex
T
José Valim 56f15d9f4e Do not add spaces after { and before }
This makes the source code consistent with the result
returned by inspect/2.
2014-04-21 19:06:35 +02:00

81 lines
2.5 KiB
Elixir

defmodule Kernel.ParallelRequire do
@moduledoc """
A module responsible for requiring files in parallel.
"""
defmacrop default_callback, do: quote(do: fn x -> x end)
@doc """
Requires the given files.
A callback that is invoked every time a file is required
can be optionally given as argument.
Returns the modules generated by each required file.
"""
def files(files, callback \\ default_callback) do
schedulers = max(:erlang.system_info(:schedulers_online), 2)
spawn_requires(files, [], callback, schedulers, [])
end
defp spawn_requires([], [], _callback, _schedulers, result), do: result
defp spawn_requires([], waiting, callback, schedulers, result) do
wait_for_messages([], waiting, callback, schedulers, result)
end
defp spawn_requires(files, waiting, callback, schedulers, result) when length(waiting) >= schedulers do
wait_for_messages(files, waiting, callback, schedulers, result)
end
defp spawn_requires([h|t], waiting, callback, schedulers, result) do
parent = self
compiler_pid = :erlang.get(:elixir_compiler_pid)
ensure_compiled = :erlang.get(:elixir_ensure_compiled)
{:error_handler, handler} = :erlang.process_info(parent, :error_handler)
{pid, ref} = :erlang.spawn_monitor fn ->
if compiler_pid != :undefined do
:erlang.put(:elixir_compiler_pid, compiler_pid)
end
if ensure_compiled != :undefined do
:erlang.put(:elixir_ensure_compiled, ensure_compiled)
end
:erlang.process_flag(:error_handler, handler)
exit(try do
new = Code.require_file(h) || []
{:required, Enum.map(new, &elem(&1, 0)), h}
catch
kind, reason ->
{:failure, kind, reason, System.stacktrace}
end)
end
spawn_requires(t, [{pid, ref}|waiting], callback, schedulers, result)
end
defp wait_for_messages(files, waiting, callback, schedulers, result) do
receive do
{:DOWN, ref, :process, pid, status} ->
tuple = {pid, ref}
if tuple in waiting do
case status do
{:required, mods, file} ->
callback.(file)
result = mods ++ result
waiting = List.delete(waiting, tuple)
{:failure, kind, reason, stacktrace} ->
:erlang.raise(kind, reason, stacktrace)
other ->
:erlang.raise(:exit, other, [])
end
end
spawn_requires(files, waiting, callback, schedulers, result)
end
end
end