aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/src')
-rw-r--r--lib/kernel/src/disk_log.erl51
-rw-r--r--lib/kernel/src/file.erl139
-rw-r--r--lib/kernel/src/gen_tcp.erl4
-rw-r--r--lib/kernel/src/inet.erl15
-rw-r--r--lib/kernel/src/inet_int.hrl2
-rw-r--r--lib/kernel/src/user_sup.erl6
6 files changed, 189 insertions, 28 deletions
diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl
index d6bc23be6d..6fb5b6e2ad 100644
--- a/lib/kernel/src/disk_log.erl
+++ b/lib/kernel/src/disk_log.erl
@@ -64,7 +64,7 @@
%%-define(PROFILE(C), C).
-define(PROFILE(C), void).
--compile({inline,[{log_loop,4},{log_end_sync,2},{replies,2},{rflat,1}]}).
+-compile({inline,[{log_loop,5},{log_end_sync,2},{replies,2},{rflat,1}]}).
%%%----------------------------------------------------------------------
%%% Contract type specifications
@@ -685,7 +685,7 @@ handle({From, {log, B}}, S) ->
L when L#log.mode =:= read_only ->
reply(From, {error, {read_only_mode, L#log.name}}, S);
L when L#log.status =:= ok, L#log.format =:= internal ->
- log_loop(S, From, [B], []);
+ log_loop(S, From, [B], [], iolist_size(B));
L when L#log.status =:= ok, L#log.format =:= external ->
reply(From, {error, {format_external, L#log.name}}, S);
L when L#log.status =:= {blocked, false} ->
@@ -700,7 +700,7 @@ handle({From, {blog, B}}, S) ->
L when L#log.mode =:= read_only ->
reply(From, {error, {read_only_mode, L#log.name}}, S);
L when L#log.status =:= ok ->
- log_loop(S, From, [B], []);
+ log_loop(S, From, [B], [], iolist_size(B));
L when L#log.status =:= {blocked, false} ->
reply(From, {error, {blocked_log, L#log.name}}, S);
L when L#log.blocked_by =:= From ->
@@ -714,7 +714,7 @@ handle({alog, B}, S) ->
notify_owners({read_only,B}),
loop(S);
L when L#log.status =:= ok, L#log.format =:= internal ->
- log_loop(S, [], [B], []);
+ log_loop(S, [], [B], [], iolist_size(B));
L when L#log.status =:= ok ->
notify_owners({format_external, B}),
loop(S);
@@ -730,7 +730,7 @@ handle({balog, B}, S) ->
notify_owners({read_only,B}),
loop(S);
L when L#log.status =:= ok ->
- log_loop(S, [], [B], []);
+ log_loop(S, [], [B], [], iolist_size(B));
L when L#log.status =:= {blocked, false} ->
notify_owners({blocked_log, B}),
loop(S);
@@ -1029,38 +1029,43 @@ handle(_, S) ->
loop(S).
sync_loop(From, S) ->
- log_loop(S, [], [], From).
+ log_loop(S, [], [], From, 0).
+
+-define(MAX_LOOK_AHEAD, 64*1024).
%% Inlined.
-log_loop(S, Pids, _Bins, _Sync) when S#state.cache_error =/= ok ->
+log_loop(S, Pids, _Bins, _Sync, _Sz) when S#state.cache_error =/= ok ->
loop(cache_error(S, Pids));
-log_loop(S, Pids, Bins, Sync) when S#state.messages =:= [] ->
+log_loop(#state{messages = []}=S, Pids, Bins, Sync, Sz)
+ when Sz > ?MAX_LOOK_AHEAD ->
+erlang:display({rad,12}),
+ loop(log_end(S, Pids, Bins, Sync));
+log_loop(#state{messages = []}=S, Pids, Bins, Sync, Sz) ->
receive
Message ->
- log_loop(Message, Pids, Bins, Sync, S, get(log))
+ log_loop(Message, Pids, Bins, Sync, Sz, S, get(log))
after 0 ->
loop(log_end(S, Pids, Bins, Sync))
end;
-log_loop(S, Pids, Bins, Sync) ->
+log_loop(S, Pids, Bins, Sync, Sz) ->
[M | Ms] = S#state.messages,
S1 = S#state{messages = Ms},
- log_loop(M, Pids, Bins, Sync, S1, get(log)).
+ log_loop(M, Pids, Bins, Sync, Sz, S1, get(log)).
%% Items logged after the last sync request found are sync:ed as well.
-log_loop({alog,B}, Pids, Bins, Sync, S, L) when L#log.format =:= internal ->
+log_loop({alog,B}, Pids, Bins, Sync, Sz, S, #log{format = internal}) ->
%% {alog, _} allowed for the internal format only.
- log_loop(S, Pids, [B | Bins], Sync);
-log_loop({balog, B}, Pids, Bins, Sync, S, _L) ->
- log_loop(S, Pids, [B | Bins], Sync);
-log_loop({From, {log, B}}, Pids, Bins, Sync, S, L)
- when L#log.format =:= internal ->
+ log_loop(S, Pids, [B | Bins], Sync, Sz+iolist_size(B));
+log_loop({balog, B}, Pids, Bins, Sync, Sz, S, _L) ->
+ log_loop(S, Pids, [B | Bins], Sync, Sz+iolist_size(B));
+log_loop({From, {log, B}}, Pids, Bins, Sync, Sz, S, #log{format = internal}) ->
%% {log, _} allowed for the internal format only.
- log_loop(S, [From | Pids], [B | Bins], Sync);
-log_loop({From, {blog, B}}, Pids, Bins, Sync, S, _L) ->
- log_loop(S, [From | Pids], [B | Bins], Sync);
-log_loop({From, sync}, Pids, Bins, Sync, S, _L) ->
- log_loop(S, Pids, Bins, [From | Sync]);
-log_loop(Message, Pids, Bins, Sync, S, _L) ->
+ log_loop(S, [From | Pids], [B | Bins], Sync, Sz+iolist_size(B));
+log_loop({From, {blog, B}}, Pids, Bins, Sync, Sz, S, _L) ->
+ log_loop(S, [From | Pids], [B | Bins], Sync, Sz+iolist_size(B));
+log_loop({From, sync}, Pids, Bins, Sync, Sz, S, _L) ->
+ log_loop(S, Pids, Bins, [From | Sync], Sz);
+log_loop(Message, Pids, Bins, Sync, _Sz, S, _L) ->
NS = log_end(S, Pids, Bins, Sync),
handle(Message, NS).
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 706c60caaf..0b0f91d86a 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -51,6 +51,9 @@
-export([pid2name/1]).
+%% Sendfile functions
+-export([sendfile/2,sendfile/5]).
+
%%% Obsolete exported functions
-export([raw_read_file_info/1, raw_write_file_info/2]).
@@ -103,7 +106,7 @@
-type date_time() :: calendar:datetime().
-type posix_file_advise() :: 'normal' | 'sequential' | 'random'
| 'no_reuse' | 'will_need' | 'dont_need'.
-
+-type sendfile_option() :: {chunk_size, non_neg_integer()}.
%%%-----------------------------------------------------------------
%%% General functions
@@ -1114,6 +1117,140 @@ change_time(Name, Atime, Mtime)
when is_tuple(Atime), is_tuple(Mtime) ->
write_file_info(Name, #file_info{atime=Atime, mtime=Mtime}).
+%%
+%% Send data using sendfile
+%%
+
+-define(MAX_CHUNK_SIZE, (1 bsl 20)*20). %% 20 MB, has to fit in primary memory
+
+-spec sendfile(RawFile, Socket, Offset, Bytes, Opts) ->
+ {'ok', non_neg_integer()} | {'error', inet:posix() | badarg | not_owner} when
+ RawFile :: file:fd(),
+ Socket :: inet:socket(),
+ Offset :: non_neg_integer(),
+ Bytes :: non_neg_integer(),
+ Opts :: [sendfile_option()].
+sendfile(File, _Sock, _Offet, _Bytes, _Opts) when is_pid(File) ->
+ {error, badarg};
+sendfile(File, Sock, Offset, Bytes, []) ->
+ sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, [], [],
+ false, false, false);
+sendfile(File, Sock, Offset, Bytes, Opts) ->
+ ChunkSize0 = proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE),
+ ChunkSize = if ChunkSize0 > ?MAX_CHUNK_SIZE ->
+ ?MAX_CHUNK_SIZE;
+ true -> ChunkSize0
+ end,
+ %% Support for headers, trailers and options has been removed because the
+ %% Darwin and BSD API for using it does not play nice with
+ %% non-blocking sockets. See unix_efile.c for more info.
+ sendfile(File, Sock, Offset, Bytes, ChunkSize, [], [],
+ false,false,false).
+
+%% sendfile/2
+-spec sendfile(Filename, Socket) ->
+ {'ok', non_neg_integer()} | {'error', inet:posix() | badarg | not_owner}
+ when Filename :: file:name(),
+ Socket :: inet:socket().
+sendfile(Filename, Sock) ->
+ case file:open(Filename, [read, raw, binary]) of
+ {error, Reason} ->
+ {error, Reason};
+ {ok, Fd} ->
+ Res = sendfile(Fd, Sock, 0, 0, []),
+ file:close(Fd),
+ Res
+ end.
+
+%% Internal sendfile functions
+sendfile(#file_descriptor{ module = Mod } = Fd, Sock, Offset, Bytes,
+ ChunkSize, Headers, Trailers, Nodiskio, MNowait, Sync)
+ when is_port(Sock) ->
+ case Mod:sendfile(Fd, Sock, Offset, Bytes, ChunkSize, Headers, Trailers,
+ Nodiskio, MNowait, Sync) of
+ {error, enotsup} ->
+ sendfile_fallback(Fd, Sock, Offset, Bytes, ChunkSize,
+ Headers, Trailers);
+ Else ->
+ Else
+ end;
+sendfile(_,_,_,_,_,_,_,_,_,_) ->
+ {error, badarg}.
+
+%%%
+%% Sendfile Fallback
+%%%
+sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize,
+ Headers, Trailers)
+ when Headers == []; is_integer(Headers) ->
+ case sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) of
+ {ok, BytesSent} when is_list(Trailers),
+ Trailers =/= [],
+ is_integer(Headers) ->
+ sendfile_send(Sock, Trailers, BytesSent+Headers);
+ {ok, BytesSent} when is_list(Trailers), Trailers =/= [] ->
+ sendfile_send(Sock, Trailers, BytesSent);
+ {ok, BytesSent} when is_integer(Headers) ->
+ {ok, BytesSent + Headers};
+ Else ->
+ Else
+ end;
+sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, Headers, Trailers) ->
+ case sendfile_send(Sock, Headers, 0) of
+ {ok, BytesSent} ->
+ sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, BytesSent,
+ Trailers);
+ Else ->
+ Else
+ end.
+
+
+sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) ->
+ {ok, CurrPos} = file:position(File, {cur, 0}),
+ {ok, _NewPos} = file:position(File, {bof, Offset}),
+ Res = sendfile_fallback_int(File, Sock, Bytes, ChunkSize, 0),
+ file:position(File, {bof, CurrPos}),
+ Res.
+
+
+sendfile_fallback_int(File, Sock, Bytes, ChunkSize, BytesSent)
+ when Bytes > BytesSent; Bytes == 0 ->
+ Size = if Bytes == 0 ->
+ ChunkSize;
+ (Bytes - BytesSent + ChunkSize) > 0 ->
+ Bytes - BytesSent;
+ true ->
+ ChunkSize
+ end,
+ case file:read(File, Size) of
+ {ok, Data} ->
+ case sendfile_send(Sock, Data, BytesSent) of
+ {ok,NewBytesSent} ->
+ sendfile_fallback_int(
+ File, Sock, Bytes, ChunkSize,
+ NewBytesSent);
+ Error ->
+ Error
+ end;
+ eof ->
+ {ok, BytesSent};
+ Error ->
+ Error
+ end;
+sendfile_fallback_int(_File, _Sock, BytesSent, _ChunkSize, BytesSent) ->
+ {ok, BytesSent}.
+
+sendfile_send(Sock, Data, Old) ->
+ Len = iolist_size(Data),
+ case gen_tcp:send(Sock, Data) of
+ ok ->
+ {ok, Len+Old};
+ Else ->
+ Else
+ end.
+
+
+
%%%-----------------------------------------------------------------
%%% Helpers
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index 8ab18c01b4..4d6c7f5f1d 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -27,6 +27,7 @@
-export([fdopen/2]).
-include("inet_int.hrl").
+-include("file.hrl").
-type option() ::
{active, true | false | once} |
@@ -302,7 +303,7 @@ unrecv(S, Data) when is_port(S) ->
Mod:unrecv(S, Data);
Error ->
Error
- end.
+ end.
%%
%% Set controlling process
@@ -354,3 +355,4 @@ mod([_|Opts], Address) ->
mod(Opts, Address);
mod([], Address) ->
mod(Address).
+
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index b60c68e3a1..49f64a9236 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -40,6 +40,10 @@
-export([tcp_controlling_process/2, udp_controlling_process/2,
tcp_close/1, udp_close/1]).
+
+%% used by sendfile
+-export([lock_socket/2]).
+
%% used by socks5
-export([setsockname/2, setpeername/2]).
@@ -1353,3 +1357,14 @@ stop_timer(Timer) ->
end;
T -> T
end.
+
+
+lock_socket(S,Val) ->
+ case erlang:port_info(S, connected) of
+ {connected, Pid} when Pid =/= self() ->
+ {error, not_owner};
+ undefined ->
+ {error, einval};
+ _ ->
+ prim_inet:ignorefd(S,Val)
+ end.
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index f8984b13fe..cf893c73eb 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -85,6 +85,8 @@
-define(INET_REQ_GETIFADDRS, 25).
-define(INET_REQ_ACCEPT, 26).
-define(INET_REQ_LISTEN, 27).
+-define(INET_REQ_IGNOREFD, 28).
+
%% TCP requests
%%-define(TCP_REQ_ACCEPT, 40). MOVED
%%-define(TCP_REQ_LISTEN, 41). MERGED
diff --git a/lib/kernel/src/user_sup.erl b/lib/kernel/src/user_sup.erl
index 35b7ff0cfe..7c97da189a 100644
--- a/lib/kernel/src/user_sup.erl
+++ b/lib/kernel/src/user_sup.erl
@@ -45,7 +45,7 @@ init([]) ->
Pid = start_slave(Master),
{ok, Pid, Pid};
{M, F, A} ->
- case start_user({M, F}, A) of
+ case start_user(M, F, A) of
{ok, Pid} ->
{ok, Pid, Pid};
Error ->
@@ -95,8 +95,8 @@ terminate(_Reason, UserPid) ->
%% is guaranteed that the user is started.
%%-----------------------------------------------------------------
-start_user(Func,A) ->
- apply(Func, A),
+start_user(Mod, Func, A) ->
+ apply(Mod, Func, A),
wait_for_user_p(100).
wait_for_user_p(0) ->