Skip to content
This repository
Browse code

Use file:sendfile/5 if available

Due to a bug in file:sendfile/5 in R15B, the yaws configure script enables
the use of file:sendfile/5 only for versions R15B01 or greater.
  • Loading branch information...
commit 2150708dc8abd02b91807c3ab704148ce7ae61cb 1 parent ad390f7
Tuncer Ayaz authored December 29, 2011 vinoski committed March 31, 2012
2  c_src/Makefile
@@ -12,7 +12,7 @@ else
12 12
 	PRIV_FILES= ../priv/lib/setuid_drv.$(DLL)  $(EPAM)
13 13
 endif
14 14
 
15  
-ifeq ($(HAVE_SENDFILE),true)
  15
+ifeq ($(HAVE_YAWS_SENDFILE),true)
16 16
 	PRIV_FILES += ../priv/lib/yaws_sendfile_drv.$(DLL)
17 17
 endif
18 18
 
4  c_src/yaws_sendfile_drv.c
@@ -2,7 +2,7 @@
2 2
 /* author: vinoski@ieee.org                                  */
3 3
 /* Created : 09 Nov 2008 by Steve Vinoski <vinoski@ieee.org> */
4 4
 
5  
-#ifdef HAVE_SENDFILE
  5
+#ifdef HAVE_YAWS_SENDFILE
6 6
 
7 7
 #include <errno.h>
8 8
 #include <stdint.h>
@@ -328,4 +328,4 @@ DRIVER_INIT(yaws_sendfile_drv)
328 328
 
329 329
 #error "yaws_sendfile_drv not supported on this platform"
330 330
 
331  
-#endif /* HAVE_SENDFILE */
  331
+#endif /* HAVE_YAWS_SENDFILE */
18  configure.in
@@ -213,7 +213,7 @@ dnl in /usr/include/pam... I'm too sick of M4 at this very moment to write
213 213
 dnl a test that searches for the files, so hard coded for now...
214 214
 dnl or use --with-extrainclude=....
215 215
 CFLAGS="$CFLAGS -I/usr/include/security"
216  
-HAVE_SENDFILE=false
  216
+HAVE_YAWS_SENDFILE=false
217 217
 
218 218
 case "$host_os" in
219 219
         *linux*)
@@ -242,7 +242,7 @@ case "$host_os" in
242 242
            AC_SUBST(LD_SHARED)
243 243
            FPIC=-fpic
244 244
            AC_SUBST(FPIC)
245  
-           HAVE_SENDFILE=true
  245
+           HAVE_YAWS_SENDFILE=true
246 246
            ;;
247 247
 
248 248
         *solaris*)
@@ -259,7 +259,7 @@ case "$host_os" in
259 259
            AC_DEFINE(BSD)
260 260
            case "$host_os" in
261 261
                 freebsd*)
262  
-                    HAVE_SENDFILE=true
  262
+                    HAVE_YAWS_SENDFILE=true
263 263
                     ;;
264 264
                 bsdi*)
265 265
                     BSDI=bsdi
@@ -274,7 +274,7 @@ case "$host_os" in
274 274
            ;;
275 275
          *darwin*)
276 276
            AC_LANG(C)
277  
-           AC_CHECK_LIB([c],[sendfile],[HAVE_SENDFILE=true])
  277
+           AC_CHECK_LIB([c],[sendfile],[HAVE_YAWS_SENDFILE=true])
278 278
            case "$host_os" in
279 279
                darwin1?*)
280 280
                    AC_LANG(Erlang)
@@ -316,8 +316,14 @@ case "$host_os" in
316 316
 esac
317 317
 
318 318
 AC_ARG_ENABLE(sendfile, AS_HELP_STRING([--disable-sendfile], [disables use of sendfile system call]),
319  
-                        [ test "$enableval" = no && HAVE_SENDFILE=false ])
320  
-AC_SUBST(HAVE_SENDFILE)
  319
+                        [ test "$enableval" = no && HAVE_YAWS_SENDFILE=false ])
  320
+file_sendfile=`"${ERL}" -noshell -eval 'io:format("~p~n",[[erlang:function_exported(file, sendfile, 5)]]), erlang:halt().' | tail -1`
  321
+if test "$file_sendfile" = true -a '(' $ERTS_MAJOR -gt 5 -o '(' $ERTS_MAJOR -eq 5 -a $ERTS_MINOR -gt 9 ')' ')' ; then
  322
+   HAVE_YAWS_SENDFILE=false
  323
+   AC_MSG_NOTICE(found file:sendfile/5)
  324
+fi
  325
+AC_SUBST(HAVE_YAWS_SENDFILE)
  326
+
321 327
 YTOP=`pwd`
322 328
 AC_SUBST(YTOP)
323 329
 AC_OUTPUT(include.mk)
6  include.mk.in
@@ -22,7 +22,7 @@ DEFAULT_CHARSET=@DEFAULT_CHARSET@
22 22
 EPAM = @EPAM@
23 23
 EXTRAINCLUDE = @EXTRAINCLUDE@
24 24
 ERLBINDIR = @ERLBINDIR@
25  
-HAVE_SENDFILE = @HAVE_SENDFILE@
  25
+HAVE_YAWS_SENDFILE = @HAVE_YAWS_SENDFILE@
26 26
 BITS_SUPPORT = @BITS_SUPPORT@
27 27
 
28 28
 ifdef debug
@@ -43,8 +43,8 @@ endif
43 43
 
44 44
 CC=@CC@
45 45
 CFLAGS=@CFLAGS@
46  
-ifeq ($(HAVE_SENDFILE),true)
47  
-CFLAGS += -DHAVE_SENDFILE
  46
+ifeq ($(HAVE_YAWS_SENDFILE),true)
  47
+CFLAGS += -DHAVE_YAWS_SENDFILE
48 48
 endif
49 49
 LINKER=@LINKER@
50 50
 LDFLAGS=@LDFLAGS@
13  rebar.config
@@ -3,19 +3,22 @@
3 3
 {plugins, [rebar_reltool_link]}.
4 4
 {sub_dirs, ["rel"]}.
5 5
 
6  
-{erl_opts, [{platform_define,
7  
-             "(linux|freebsd|darwin)", 'HAVE_SENDFILE'},
  6
+{erl_opts, [%% OTP R11 - R15A -> yaws_sendfile_drv or compat_send
  7
+            {platform_define,
  8
+             "R1([1-4]|5A).*(linux|freebsd|darwin)", 'HAVE_YAWS_SENDFILE'},
  9
+            {platform_define, "R1([1-4]|5A).*", 'NO_FILE_SENDFILE'},
8 10
             no_debug_info,
9 11
             {src_dirs, ["src", "examples/src"]},
10 12
             warnings_as_errors]}.
11 13
 
12 14
 {port_envs, [{"CFLAGS", "$CFLAGS -g -O3 -Wall -I/usr/include/security"},
13  
-             {"(linux|freebsd|dragonfly|solaris|darwin)",
14  
-              "DRV_CFLAGS", "$DRV_CFLAGS -DHAVE_SENDFILE"}]}.
  15
+             {"R1([1-4]|5A).*(linux|freebsd|darwin)",
  16
+              "DRV_CFLAGS", "$DRV_CFLAGS -DHAVE_YAWS_SENDFILE"}]}.
15 17
 
16 18
 {port_specs, [{"priv/lib/epam.so", ["c_src/epam.c"]},
17 19
               {"priv/lib/setuid_drv.so", ["c_src/setuid_drv.c"]},
18  
-              {"priv/lib/yaws_sendfile_drv.so",
  20
+              {"R1([1-4]|5A).*(linux|freebsd|darwin)",
  21
+               "priv/lib/yaws_sendfile_drv.so",
19 22
                ["c_src/yaws_sendfile_drv.c", "c_src/hashtable.c"]}]}.
20 23
 
21 24
 {pre_hooks, [{compile, "./scripts/rebar-pre-script"},
3  scripts/rebar-pre-script
@@ -51,7 +51,8 @@ if [ -n "$need_mime" ]; then
51 51
 fi
52 52
 
53 53
 if [ ! -f yaws_configure.hrl ]; then
54  
-    echo '%% rebar sets HAVE_SENDFILE in erlc command line' > yaws_configure.hrl
  54
+    echo '%% rebar sets HAVE_YAWS_SENDFILE in erlc command line' \
  55
+        > yaws_configure.hrl
55 56
     [ $? -eq 0 ] || fail
56 57
 fi
57 58
 tmpgen=`mktemp /tmp/${script}.XXXXXX` || fail
4  src/Makefile
@@ -82,8 +82,8 @@ yaws_generated.erl:	yaws_generated.template ../vsn.mk
82 82
 	    ../scripts/gen-yaws-generated true > yaws_generated.erl
83 83
 
84 84
 yaws_configure.hrl:	 ../vsn.mk ../include.mk
85  
-	if [  $(HAVE_SENDFILE) = "true" ]; then \
86  
-		echo "-define(HAVE_SENDFILE, true)." > yaws_configure.hrl; \
  85
+	if [  $(HAVE_YAWS_SENDFILE) = "true" ]; then \
  86
+		echo "-define(HAVE_YAWS_SENDFILE, true)." > yaws_configure.hrl; \
87 87
 	else touch yaws_configure.hrl; fi
88 88
 
89 89
 
85  src/yaws_sendfile.erl
@@ -11,15 +11,19 @@
11 11
 
12 12
 -include("yaws_configure.hrl").
13 13
 -include("../include/yaws.hrl").
  14
+-include_lib("kernel/include/file.hrl").
14 15
 
15  
--ifdef(HAVE_SENDFILE).
  16
+-ifndef(HAVE_YAWS_SENDFILE).
  17
+-ifndef(NO_FILE_SENDFILE).
  18
+-define(HAVE_FILE_SENDFILE, 1).
  19
+-endif.
  20
+-endif.
16 21
 
  22
+
  23
+-ifdef(HAVE_YAWS_SENDFILE).
17 24
 -behavior(gen_server).
18 25
 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
19 26
          code_change/3]).
20  
-
21  
--include_lib("kernel/include/file.hrl").
22  
-
23 27
 -endif.
24 28
 
25 29
 send(Out, Filename) ->
@@ -27,7 +31,50 @@ send(Out, Filename) ->
27 31
 send(Out, Filename, Offset) ->
28 32
     send(Out, Filename, Offset, all).
29 33
 
30  
--ifdef(HAVE_SENDFILE).
  34
+bytes_to_transfer(Filename, Offset, Count) ->
  35
+    case Count of
  36
+        all ->
  37
+            case file:read_file_info(Filename) of
  38
+                {ok, #file_info{size = Size}} ->
  39
+                    Size - Offset;
  40
+                Error ->
  41
+                    Error
  42
+            end;
  43
+        Count when is_integer(Count) ->
  44
+            Count;
  45
+        _ ->
  46
+            {error, badarg}
  47
+    end.
  48
+
  49
+-ifdef(HAVE_FILE_SENDFILE). %% OTP >= R15B; use file:sendfile/5
  50
+
  51
+enabled() ->
  52
+    true.
  53
+send(Out, Filename, Offset, Count) ->
  54
+    Count1 = bytes_to_transfer(Filename, Offset, Count),
  55
+    case Count1 of
  56
+        {error, _}=Error1 ->
  57
+            Error1;
  58
+        _ ->
  59
+            case file:open(Filename, [raw, read, binary]) of
  60
+                {ok, RawFile} ->
  61
+                    Res = file:sendfile(RawFile, Out, Offset, Count1, []),
  62
+                    ok = file:close(RawFile),
  63
+                    Res;
  64
+                Error2 ->
  65
+                    Error2
  66
+            end
  67
+    end.
  68
+start_link() ->
  69
+    ignore.
  70
+start() ->
  71
+    ignore.
  72
+stop() ->
  73
+    ok.
  74
+
  75
+-else.
  76
+
  77
+-ifdef(HAVE_YAWS_SENDFILE).
31 78
 
32 79
 start_link() ->
33 80
     gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
@@ -39,28 +86,16 @@ enabled() ->
39 86
     true.
40 87
 
41 88
 send(Out, Filename, Offset, Count) ->
42  
-    Count1 = case Count of
43  
-                 all ->
44  
-                     case file:read_file_info(Filename) of
45  
-                         {ok, #file_info{size = Size}} ->
46  
-                             Size - Offset;
47  
-                         Error ->
48  
-                             Error
49  
-                     end;
50  
-                 Count when is_integer(Count) ->
51  
-                     Count;
52  
-                 _ ->
53  
-                     {error, badarg}
54  
-             end,
  89
+    Count1 = bytes_to_transfer(Filename, Offset, Count),
55 90
     case Count1 of
56  
-        {error, _}=Error2 ->
57  
-            Error2;
  91
+        {error, _}=Error ->
  92
+            Error;
58 93
         _ ->
59 94
             case prim_inet:getfd(Out) of
60 95
                 {ok, SocketFd} ->
61 96
                     do_send(Out, SocketFd, Filename, Offset, Count1);
62  
-                Error3 ->
63  
-                    Error3
  97
+                Error2 ->
  98
+                    Error2
64 99
             end
65 100
     end.
66 101
 
@@ -149,14 +184,14 @@ do_send(Out, SocketFd, Filename, Offset, Count) ->
149 184
 
150 185
 enabled() ->
151 186
     false.
  187
+send(Out, Filename, Offset, Count) ->
  188
+    compat_send(Out, Filename, Offset, Count).
152 189
 start_link() ->
153 190
     ignore.
154 191
 start() ->
155 192
     ignore.
156 193
 stop() ->
157 194
     ok.
158  
-send(Out, Filename, Offset, Count) ->
159  
-    compat_send(Out, Filename, Offset, Count).
160 195
 
161 196
 -endif.
162 197
 
@@ -203,3 +238,5 @@ loop_send(Fd, ChunkSize, {ok, Bin}, Out, Count) ->
203 238
     end;
204 239
 loop_send(_Fd, _, Err, _,_) ->
205 240
     Err.
  241
+
  242
+-endif.
2  win32/include.mk
@@ -22,7 +22,7 @@ DEFAULT_CHARSET=
22 22
 EPAM = ../priv/epam
23 23
 EXTRAINCLUDE =
24 24
 ERLBINDIR = /usr/lib/erlang/bin
25  
-HAVE_SENDFILE = true
  25
+HAVE_YAWS_SENDFILE = true
26 26
 
27 27
 ifdef debug
28 28
   ERLC_FLAGS+=-Ddebug

0 notes on commit 2150708

Please sign in to comment.
Something went wrong with that request. Please try again.