1dnl mmap.m4 -- Probe for mmap properties.
2dnl $Id: mmap.m4 10397 2020-11-12 20:22:51Z iulius $
3dnl
4dnl The mmap macro that comes with Autoconf doesn't do anything useful.
5dnl Define a new INN_FUNC_MMAP that probes for a working mmap that supports
6dnl shared, non-fixed maps.  This function defines HAVE_MMAP if mmap appears
7dnl to work, and takes an action if found argument that can be used to make
8dnl other probes.
9dnl
10dnl Provide INN_FUNC_MMAP_NEEDS_MSYNC, which defines MMAP_NEEDS_MSYNC if
11dnl reading from an open file doesn't see changes made to that file through
12dnl mmap without an intervening msync.
13dnl
14dnl Provide INN_FUNC_MMAP_MISSES_WRITES, which defines MMAP_MISSES_WRITES if
15dnl changes to a file made with write aren't seen in an mmaped region without
16dnl an intervening msync.
17dnl
18dnl (The above two macros together in essence probe for whether the operating
19dnl system has a unified page cache.)
20dnl
21dnl Finally, provide AC_FUNC_MSYNC_ARGS, which defines HAVE_MSYNC_3_ARGS if
22dnl msync takes three arguments (as on Solaris and Linux) rather than two
23dnl (most other operating systems).
24
25dnl Source used by INN_FUNC_MMAP.
26define([_INN_FUNC_MMAP_SOURCE],
27[AC_LANG_SOURCE([[
28#include <fcntl.h>
29#include <stdlib.h>
30#include <sys/mman.h>
31#include <sys/stat.h>
32#if HAVE_UNISTD_H
33# include <unistd.h>
34#endif
35
36int
37main()
38{
39  int *data, *data2;
40  int i, fd;
41
42  /* First, make a file with some known garbage in it.  Use something
43     larger than one page but still an odd page size. */
44  data = malloc (20000);
45  if (!data)
46    return 1;
47  for (i = 0; i < 20000 / sizeof (int); i++)
48    data[i] = rand();
49  umask (0);
50  fd = creat ("conftestmmaps", 0600);
51  if (fd < 0)
52    return 1;
53  if (write (fd, data, 20000) != 20000)
54    return 1;
55  close (fd);
56
57  /* Next, try to mmap the file and make sure we see the same garbage. */
58  fd = open ("conftestmmaps", O_RDWR);
59  if (fd < 0)
60    return 1;
61  data2 = mmap (0, 20000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
62  if (data2 == (int *) -1)
63    return 1;
64  for (i = 0; i < 20000 / sizeof (int); i++)
65    if (data[i] != data2[i])
66      return 1;
67
68  close (fd);
69  unlink ("conftestmmaps");
70  return 0;
71}
72]])])
73
74dnl This portion is similar to what AC_FUNC_MMAP does, only it tests shared,
75dnl non-fixed mmaps.
76AC_DEFUN([INN_FUNC_MMAP],
77[AC_CACHE_CHECK([for working mmap], [inn_cv_func_mmap],
78[AC_RUN_IFELSE([_INN_FUNC_MMAP_SOURCE],
79    [inn_cv_func_mmap=yes],
80    [inn_cv_func_mmap=no],
81    [inn_cv_func_mmap=no])])
82 if test $inn_cv_func_mmap = yes ; then
83    AC_DEFINE([HAVE_MMAP], 1,
84        [Define if mmap exists and works for shared, non-fixed maps.])
85    $1
86 else
87    :
88    $2
89 fi])
90
91dnl Source used by INN_FUNC_MMAP_NEEDS_MSYNC.
92define([_INN_FUNC_MMAP_NEEDS_MSYNC_SOURCE],
93[AC_LANG_SOURCE([[
94#include <fcntl.h>
95#include <stdlib.h>
96#include <sys/mman.h>
97#include <sys/stat.h>
98#include <sys/types.h>
99#if HAVE_UNISTD_H
100# include <unistd.h>
101#endif
102
103int
104main()
105{
106  int *data, *data2;
107  int i, fd;
108
109  /* First, make a file with some known garbage in it.  Use something
110     larger than one page but still an odd page size. */
111  data = malloc (20000);
112  if (!data)
113    return 1;
114  for (i = 0; i < 20000 / sizeof (int); i++)
115    data[i] = rand();
116  umask (0);
117  fd = creat ("conftestmmaps", 0600);
118  if (fd < 0)
119    return 1;
120  if (write (fd, data, 20000) != 20000)
121    return 1;
122  close (fd);
123
124  /* Next, try to mmap the file and make sure we see the same garbage. */
125  fd = open ("conftestmmaps", O_RDWR);
126  if (fd < 0)
127    return 1;
128  data2 = mmap (0, 20000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
129  if (data2 == (int *) -1)
130    return 1;
131
132  /* Finally, see if changes made to the mmaped region propagate back to
133     the file as seen by read (meaning that msync isn't needed). */
134  for (i = 0; i < 20000 / sizeof (int); i++)
135    data2[i]++;
136  if (read (fd, data, 20000) != 20000)
137    return 1;
138  for (i = 0; i < 20000 / sizeof (int); i++)
139    if (data[i] != data2[i])
140      return 1;
141
142  close (fd);
143  unlink ("conftestmmapm");
144  return 0;
145}
146]])])
147
148dnl Check whether the data read from an open file sees the changes made to an
149dnl mmaped region, or if msync has to be called for other applications to see
150dnl those changes.
151AC_DEFUN([INN_FUNC_MMAP_NEEDS_MSYNC],
152[AC_CACHE_CHECK([whether msync is needed], [inn_cv_func_mmap_need_msync],
153[AC_RUN_IFELSE([_INN_FUNC_MMAP_NEEDS_MSYNC_SOURCE],
154    [inn_cv_func_mmap_need_msync=no],
155    [inn_cv_func_mmap_need_msync=yes],
156    [inn_cv_func_mmap_need_msync=yes])])
157 if test $inn_cv_func_mmap_need_msync = yes ; then
158    AC_DEFINE([MMAP_NEEDS_MSYNC], 1,
159       [Define if you need to call msync for calls to read to see changes.])
160 fi])
161
162dnl Source used by INN_FUNC_MMAP_SEES_WRITES.
163define([_INN_FUNC_MMAP_SEES_WRITES_SOURCE],
164[AC_LANG_SOURCE([[
165#include <stdlib.h>
166#include <sys/types.h>
167#include <sys/stat.h>
168#include <fcntl.h>
169#if HAVE_UNISTD_H
170# include <unistd.h>
171#endif
172#include <sys/mman.h>
173
174/* Fractional page is probably worst case. */
175static char zbuff[1024];
176static char fname[] = "conftestw";
177
178int
179main ()
180{
181  char *map;
182  int i, fd;
183
184  fd = open (fname, O_RDWR | O_CREAT, 0660);
185  if (fd < 0)
186    return 1;
187  unlink (fname);
188  write (fd, zbuff, sizeof (zbuff));
189  lseek (fd, 0, SEEK_SET);
190  map = mmap (0, sizeof (zbuff), PROT_READ, MAP_SHARED, fd, 0);
191  if (map == (char *) -1)
192    return 2;
193  for (i = 0; fname[i]; i++)
194    {
195      if (write (fd, &fname[i], 1) != 1)
196        return 3;
197      if (map[i] != fname[i])
198        return 4;
199    }
200  return 0;
201}
202]])])
203
204dnl Check if an mmaped region will see writes made to the underlying file
205dnl without an intervening msync.
206AC_DEFUN([INN_FUNC_MMAP_SEES_WRITES],
207[AC_CACHE_CHECK([whether mmap sees writes], [inn_cv_func_mmap_sees_writes],
208[AC_RUN_IFELSE([_INN_FUNC_MMAP_SEES_WRITES_SOURCE],
209    [inn_cv_func_mmap_sees_writes=yes],
210    [inn_cv_func_mmap_sees_writes=no],
211    [inn_cv_func_mmap_sees_writes=no])])
212 if test $inn_cv_func_mmap_sees_writes = no ; then
213    AC_DEFINE([MMAP_MISSES_WRITES], 1,
214        [Define if you need to call msync after writes.])
215 fi])
216
217dnl Check whether msync takes three arguments.  (It takes three arguments on
218dnl Solaris and Linux, two arguments on BSDI.)
219AC_DEFUN([INN_FUNC_MSYNC_ARGS],
220[AC_CACHE_CHECK([how many arguments msync takes], [inn_cv_func_msync_args],
221[AC_COMPILE_IFELSE(
222[AC_LANG_PROGRAM([[
223#include <sys/types.h>
224#include <sys/mman.h>]],
225    [[char *p; int psize; msync (p, psize, MS_ASYNC);]])],
226    [inn_cv_func_msync_args=3],
227    [inn_cv_func_msync_args=2])])
228 if test $inn_cv_func_msync_args = 3 ; then
229    AC_DEFINE([HAVE_MSYNC_3_ARG], 1,
230        [Define if your msync function takes three arguments.])
231 fi])
232