After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 148218 - wrap mmap()
wrap mmap()
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: general
unspecified
Other Linux
: Normal enhancement
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks: 306801
 
 
Reported: 2004-07-22 22:57 UTC by David Schleef
Modified: 2011-02-18 16:11 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
patch (2.67 KB, patch)
2004-07-22 22:58 UTC, David Schleef
needs-work Details | Review
Initial code for review (7.59 KB, text/plain)
2005-06-16 22:50 UTC, Behdad Esfahbod
  Details
gmappedfile.h (1.42 KB, text/x-chdr)
2005-06-23 20:07 UTC, Matthias Clasen
  Details
gmappedfile.c (5.56 KB, text/x-csrc)
2005-06-23 20:09 UTC, Matthias Clasen
  Details
a test (7.14 KB, text/x-csrc)
2005-06-24 16:24 UTC, Matthias Clasen
  Details
simplified version (5.39 KB, text/x-csrc)
2005-06-24 17:50 UTC, Matthias Clasen
  Details
simplified header (1.39 KB, text/x-chdr)
2005-06-24 17:51 UTC, Matthias Clasen
  Details
simplified test (5.01 KB, text/x-csrc)
2005-06-24 17:52 UTC, Matthias Clasen
  Details
win32 file mappping test program for writable/non-shared (1.13 KB, text/plain)
2005-06-24 20:36 UTC, Tor Lillqvist
  Details

Description David Schleef 2004-07-22 22:57:13 UTC
Inspired by Jim Getty's comment at DDC about obvious optimizations like
mmap()ing instead of read()ing file contents that are intended to be read-only,
I created a glib patch to do exactly that.

It need better API naming and the code should be documented and be made
portable, but this code is good and fast, and roughly comparable to
g_file_get_contents().  One difference is that data is not guaranteed to be
nul-terminated, but if that's important, that can be fixed.
Comment 1 David Schleef 2004-07-22 22:58:48 UTC
Created attachment 29808 [details] [review]
patch
Comment 2 Robert Love 2005-03-05 01:01:02 UTC
Hey, this looks really good to me!

I don't see any problems, system call wise.
Comment 3 Morten Welinder 2005-03-05 01:49:31 UTC
* gsize for length, not int.
* check for mmap, not all systems have it.
* win32 has a different function for it.
* MMAP_FAILED not present on all systems.
* Think about the empty-file case.
* g_open, not open, I think.
* mmap is not a win for small files.
* Have a look at gsf_input_mmap_new in libgsf which does exactly what you need.
Comment 4 Ben Maurer 2005-03-05 21:31:46 UTC
For systems that don't have a mmap, the caller might want to specify if the file
should be loaded at all. There are many cases where a cahce would be horrible if
the mmap failed and we were loading it with malloc.

About the naming -- I think this would work:

g_file_mapping_new
g_file_mapping_length
g_file_mapping_contents
g_file_mapping_free
Comment 5 Robert Love 2005-03-07 04:22:26 UTC
POSIX dictates mmap() and MMAP_FAILED.    What systems have one but not the other?
Comment 6 Robert Love 2005-03-07 04:25:23 UTC
s/MMAP_FAILED/MAP_FILED/
Comment 7 Matthias Clasen 2005-03-07 13:44:12 UTC
Is there a way to add zero-termination without copying the data ?
Comment 8 Ben Maurer 2005-03-07 14:54:10 UTC
From the man page "The system shall always zero-fill any partial page at the 
end of an object."

That should help out...
Comment 9 Matthias Clasen 2005-03-07 15:11:54 UTC
Unless the file ends on a page boundary...
Comment 10 Ben Maurer 2005-03-07 15:58:58 UTC
Good point ;-). Is the zero termination *really* needed?
Comment 11 Robert Love 2005-03-07 16:08:04 UTC
I cannot think of any useful way to add the zero termination without copying. 
And if we have to copy, there is no point in the mmap(), obviously.

I don't really get the point of the delimiter, though, since the file itself can
contain a NULL, the ->length is always needed.  I say ditch it.
Comment 12 Matthias Clasen 2005-03-07 16:11:14 UTC
It is not really needed, but it would certainly make the api much more
convenient to use for text files. If we can't make this more convenient than
mmap(), why bother with adding a wrapper ?
Comment 13 Ben Maurer 2005-03-07 16:15:50 UTC
re comment 12: because that way people don't need to do the win32 api, and 
mmap, etc and support all the different paths. Generally, it is more useful to 
map binary stuff than it is to do text files, i'd think.
Comment 14 Manish Singh 2005-03-07 18:06:18 UTC
If that's the point, I think we should wrap mmap functionality more generically,
so glib provides a full portable abstraction.
Comment 15 Sven Neumann 2005-03-10 13:00:57 UTC
A wrapper for mmap() and munmap() that it easy to use, works for the general use
cases and provides an implementation for all supported platforms, would be a
very much welcomed addition to glib. See for example bug #169792 which would be
a lot easier if glib provided the abstraction and GIMP wouldn't have to deal
with all those #ifdefs.
Comment 16 Matthias Clasen 2005-05-18 13:29:39 UTC
Retitling for clarity. We need an new API proposal/patch.
Comment 17 Robert Love 2005-05-18 20:23:26 UTC
Hey, BenM.  Do you know what Win32's file-memory-mapping API looks like?  Is the
consensus that we just want a generic mmap() wrapper and not a more specific
map-readonly thing?
Comment 18 Tor Lillqvist 2005-05-18 20:43:00 UTC
Win32's file memory file-memory-mapping API has more or less the same
functionality as traditional BSD mmap or SysV shared memory. I.e. as long as we
don't use exotic stuff that isn't even portable across Unixes, it should be easy
to implement it also on Windows. For details, google for CreateFileMapping and
MapViewOfFile. One difference that I recall right now is that while on Unix, at
least System V shared memory segments stay around even if the process dies
(which can be a PITA), on Windows file mappings go away if no process has a
handle open to them. (It might be possible to override this behaviour somehow.)
Comment 19 Robert Love 2005-05-18 20:46:59 UTC
Hey, Tor.  Yah, the SysV shared memory stuff is insane odd.  We'd just wrap
mmap(), which unmaps when the process exits.
Comment 20 Philip Van Hoof 2005-06-07 19:50:47 UTC
+const gchar *
+g_readfile_get_contents (GReadFile *readfile)
+{
+  return readfile->contents;
+}

Shouldn't that be a "const guchar" - pointer? Negative bytes are rather strange,
no? Or just a "void *" (gpointer)?
Comment 21 Robert Love 2005-06-07 20:22:40 UTC
It should be a "void *" because the returned value isn't necessarily a
null-delimited string; indeed it might be a binary blob.

Otherwise, I'd say go with "char *" since it would be a string.
Comment 22 Soren Sandmann Pedersen 2005-06-08 14:21:26 UTC
Traditionally, glib has used "guchar *" for pointers to binary data, because it
is more convenient - you can dereference them, for one.

My API suggestion:

     guchar *g_map_file (const char  *filename,
                         gsize       *length,
                         GError     **err);
     void g_unmap_file (guchar *address);

Notes:

   - Files are always mapped both readable, writable and executable.

   - All files are mapped MAP_PRIVATE

   - You can't map a file partially

   - The size of the file is returned thought gsize *length

   - Implementing this API will require an internal table mapping addresses
     to lengths.

Generally the philosophy is that applications needing the full power of
mmap() should just use mmap() directly.
Comment 23 Tor Lillqvist 2005-06-08 14:58:47 UTC
The internal table doesn't sound like a good idea, adds complexity to the
implementation. Why not have some struct (opaque to the user) that contains any
necessary bookkeeping information?

typedef struct _GFileMapping GFileMapping;

GFileMapping *g_file_mapping_open (const char *filename,
                                   GError    **error);
void          g_file_mapping_close (GFileMapping *mapping);

guchar       *g_file_mapping_get_data (GFileMapping *mapping);
gsize        *g_file_mapping_get_length (GFileMapping *mapping);

Hmm.

It would also be great if the GLib shared memory API would be slightly more
powerful, to cover the relatively simple use case in GIMP. I.e. it should be
possible to also create new shared memory objects that don't correspond to any
actual file, a'la shm_open(O_CREAT)+ftruncate()+mmap(), or the corresponding
System V shm*() calls, or Win32's CreateFileMapping(INVALID_HANDLE_VALUE). 

Maybe:

GFileMapping *g_file_mapping_new (gsize   length,
                                  GError **error);

and something like:

const gchar *g_file_mapping_get_identifier (GFileMapping *mapping);

to get a string (with unspecified opaque contents, typically just an integer)
that can be passed to other processes (or just descendant processes?), which
then can access it with:

GFileMapping *g_file_mapping_open_inherited (const gchar *identifier,
                                             GError     **error);

Perhaps GFileMapping would then not be a good name, as such an object wouldn't
necessarily correspond to a file. 
Comment 24 Robert Love 2005-06-08 15:09:22 UTC
I agree that we should not expose mmap() sharing semantics, but why not allow
the user to pick a read-only versus r/w mapping?
Comment 25 Matthias Clasen 2005-06-08 16:03:07 UTC
hmm, it would certainly be nice if we could use the wrapper for the one common
use of mmap in the current code: mmap'ed caches, which are mapped readonly+shared
Comment 26 Behdad Esfahbod 2005-06-08 21:41:26 UTC
What about doing private maps?  It's quite like reading the file in a buffer,
but the memory is shared as long as the buffer is not written to.

For null-termination, the manual doesn't make it clear, but doesn't mmap()ing
(filesize+1) bytes work?
Comment 27 Robert Love 2005-06-08 21:42:46 UTC
Behdad, filesize+1 only works if the size != PAGE_SIZE-1.
Comment 28 Behdad Esfahbod 2005-06-08 23:35:32 UTC
Is it really a good idea to mmap text files anyway?  Text files are typically
edited, and it is unspecified whether changes made to the file after the mmap
call are visible in the mapped region.
Comment 29 Soren Sandmann Pedersen 2005-06-09 03:07:07 UTC
Matthias, Robert, isn't the difference just that mapping read-only gives you
a segmentation fault on writing, where a read/write mapping would make a copy
of the page? If so, mapping read/write isn't really harmful for the mmap()
caches.

Getting a segfault is a nice touch for debugging, but I don't really think it's 
worth an extra API parameter.

On the other hand a writable (COW) mapping would be useful for mapping
uncompressed pixbufs: the application can legally write to the pixbuf data, but
as long as it doesn't, the memory is shared. If it does write, it just gets a
copy of the page in question which is the exact semantics we are looking for.

Tor, the GFileMapping opaque struct does look better to me.

I am not sure that shared anonymous memory belongs in the same API though. It
seems to me like two unrelated concepts that just happen to be implemented
somewhat similarly.
Comment 30 Matthias Clasen 2005-06-09 03:26:43 UTC
That may be the case for Linux+glibc. I don't think the SUSv2 specification of
MAP_PRIVATE talks about copy-on-write, but then SUSv2 also does not talk about
sharing the mapping for MAP_SHARED either. It only specifies the effect of 
these flags in terms of who sees changes which are made to the mapped region.

So you are probably right that using MAP_PRIVATE + rwx would work just as well 
for mmap caches.
Comment 31 Robert Love 2005-06-09 14:29:20 UTC
Behdad: Unless you explicitly care about the sharing semantics, it doesn't
really matter.  And we aren't looking to make a shared memory abstraction; we
want to make an alternative to g_file_get_contents().

Søren: I concur with Matthias.  I think MAP_SHARED makes more sense, but
MAP_PRIVATE will work fine.  But do we want to make it +w?
Comment 32 Behdad Esfahbod 2005-06-09 16:32:06 UTC
Robert:  I understand that we aren't looking to make a shared memory
abstraction.  But I'm worried about the case that the applications maps the text
file, and reads it, and then the file is edited, and the map contents may be
changed without the application noticing.  But I think it's not that important
really.  Why should somebody keep a text file around in the memory anyway.
Comment 33 Behdad Esfahbod 2005-06-09 18:36:41 UTC
What about this design:


GReadFile *g_readfile_open (const gchar *filename,
                            gsize       maxlen,
                            const char  *mode,
                            GError      **error);

int g_readfile_get_length (GReadFile *readfile);

guchar *g_readfile_get_contents (GReadFile *readfile);

void g_readfile_close (GReadFile *);



The last three are pretty much the same as in the patch, but g_readfile_open
does this:

============================================================================

- stats file and will return null if the file doesn't exists or is not a
  regular file.

- set len = min(filesize, maxlen)

- set nullterminate if character 't' (for text) is found in the mode argument.

- If no mmap available and on win32, try win32 tricks to implement the same
  semantics as of the following mmap case.  Jump to readfallback if mapping fails.

- If no mmap available, jump to readfallback.

- Build mmap protection based on whether the characters 'r', 'w', and 'x'
  appear in mode argument.

- Try mmap MAP_PRIVATE with the built protection and len bytes.  Jump to
  readfallback if mapping fails.  Let buffer be the address returned.

- If nullterminate and len is a multiple of PAGE_SIZE, try to mmap
  MAP_ANONYMOUS a PAGE_SIZE with the same built protection, MAP_FIXED, at
  address buffer+len.  If this fails, munmap the previous map and jump to
  readfallback.

- Jump to out.

readfallback:

- If the character 'm' (for "map") appears in the mode argument, return null.

- Otherwise, malloc len+(nullterminate?1:0) bytes and read len bytes into it.
  Zero the last byte if nullterminate.   Return null if something fails.
  Let buffer be the malloced address otherwise.

out:

- Finally, return the pointer to the GReadFile struct that includes the
  buffer pointer, len, and other housekeeping information.

============================================================================

So what do you think?  The interface is intuitive and extensible IMO.  Text
files can become default and a 'b' char can be used to signal binary.  That
would catch a few bugs probably.

If this is fine, I can implement it in an hour.
Comment 34 Tor Lillqvist 2005-06-10 16:32:41 UTC
Re: Søren's comment #29, you're right, the fact that anonymous shared memory and
memory-mapped-files use partially the same system API is not something that need
to show through in  GLib. Anyway, does anybody else think such functionality
would belong in GLib? I can't immediately think of any other GTK+ application
that would use such functionality than GIMP, so maybe the need for it isn't that
large. On the other hand, I see a risk that people start using the file-mapping
API to map /dev/null and effectively get anonymous shared memory? Should GLib
explicitly restrict the file-mapping API to regular files?

Re: Behdad's comment #33, a minor issue with your suggested API is that no other
GLib API uses an fopen()-style mode string. Flag bitmasks are more or less the norm.
Comment 35 Behdad Esfahbod 2005-06-10 16:40:13 UTC
About fopen()-style mode string, right.  That's my personal preference. 
Bitmasks are definitely more efficient and common, but then, they are a huge
pain to use.  I still do 'man 2 open' every single time I want to use open(2).

Anyway, after chatting on IRC, seems like the more practical way is to start
with a MAP_PRIVATE+rw api (why on earth rwx?).  One minor problem with that (as
opposed to read-only maps) is that the Linux+glibc, according to the manual,
reserves swap space for the mapping, such that copy-on-write never fails.  That
may be less than optimal on low-memory systems.
Comment 36 Matthias Clasen 2005-06-10 17:49:21 UTC
Looks reasonable in general, but I agree with Tor that for GLib, a flags
enumeration would be more appropriate than a string.  

What is the relevance of max_size ?

get_length should probably return gsize, not int

Does close free the structure ?
Comment 37 Soren Sandmann Pedersen 2005-06-10 17:51:03 UTC
> (why on earth rwx?).

Basically because of a sick idea I had for something quite different :-). Just
ignore it.

> One minor problem with that (as opposed to read-only maps) is that the
> Linux+glibc, according to the manual, reserves swap space for the mapping,
> such that copy-on-write never fails.  That may be less than optimal on
> low-memory systems.

I guess a single "gboolean writable" parameter might not be that bad. The swap
point is a good one; the system would have to reserve swap space for the mapping
for every appliation mapping the file.
Comment 38 Behdad Esfahbod 2005-06-10 17:53:31 UTC
max_size if definitely useless.  Will drop.  I will use flags enumeration.  Yes,
close frees the structure, unmaps, etc.

So I will send a draft patch later.  I need some help with Windows stuff, but
Tor is willing to help I think.
Comment 39 Matthias Clasen 2005-06-10 17:58:04 UTC
You should be able to see the necessary win32 apis in gkticoncache.c
Comment 40 Behdad Esfahbod 2005-06-16 22:50:59 UTC
Created attachment 47878 [details]
Initial code for review

Here is an standalone program with new implementation and test cases.  No WIN32
tricks yet.  Unfortunately I get weird segfaults.  Any idea?  The mystery
should be in the anonymous null-termination page...  Is it just too scary to
bother and we better straightly go allocate memory if nulltermination is asked
for and filesize is a multiple of pagesize?
Comment 41 Tor Lillqvist 2005-06-17 12:24:43 UTC
I think the reason for the segfault is that the anynymous page your code wants
to allocate at the fixed address in the zero-termination case happens to be
already allocated by the C runtime startup, the dynamic loader, or something,
for its own purposes. (Also with MAP_PRIVATE and MAP_ANONYMOUS.) In that case
mmap() happily reuses that mapping. Then your code unmaps that page, which
understandably causes trouble for the C runtime as a page that it uses for
something internally gets ripped out from under its feet, and you get a crash
when main() returns. 

I guess the code could first use mprotect() to check whether the page in
question already is mapped. But that opens up a race condition, another thread
might happen to allocate that same page for some other reason between the
mprotect() and mmap(). Hmm, why doesn't mmap() have a MAP_FRESH (or whatever)
flag that would mean "I wan't a freshly allocated page or nothing at all, dammit"?

Run the program under gdb, set a breakpoint at main. When it stops there, run
pmap on the process. In my case it shows:

5918:   /home/tml/47878
08048000      8K r-x--  /47878
0804a000      4K rw---  /47878
b7e33000      4K rw---    [ anon ]
b7e34000   1160K r-x--  /libc-2.3.2.so
b7f56000     36K rw---  /libc-2.3.2.so
b7f5f000      8K rw---    [ anon ]
b7f61000    492K r-x--  /libglib-2.0.so.0.600.3
b7fdc000      4K rw---  /libglib-2.0.so.0.600.3
b7fe9000      8K rw---    [ anon ]                <== note this
b7feb000     84K r-x--  /ld-2.3.2.so
b8000000      4K rw---  /ld-2.3.2.so
bffeb000     84K rw---    [ stack ]
ffffe000      4K -----    [ anon ]

Then set a breakpoint at the mmap call where the program allocates the
null-termination page. Check what page it is trying to allocate. Verify with
pmap that the address in question is already allocated. Single-step over the
mmap call, and note the return value. Yup, it uses the existing mapping.
Comment 42 Robert Love 2005-06-17 14:41:54 UTC
We really should not use MAP_FIXED, at all.
Comment 43 Soren Sandmann Pedersen 2005-06-17 17:59:10 UTC
I would suggest 

   - Nul termination cannot be done safely. Just don't try at all.

   - Drop the flags, and have a single "gboolean writable"

   - Never try to fread() the file. If mmap() fails, just report the error.
     People who want the fallback can easily get it with g_file_get_contents().

   - I would call the struct something like GMappedFile.

Random thing I noticed:

   - if g_open() fails, the patch returns NULL without setting *error.
Comment 44 Matthias Clasen 2005-06-17 18:13:07 UTC
Agreed. And don't use MAP_COPY, it isn't Posix, and we don't want the
semantics of our APIs to depend on the presence or absence of nonstandard
extensions.
Comment 45 Behdad Esfahbod 2005-06-18 05:04:42 UTC
Tor: Ah, thanks a lot for debugging.

We surely do not need this to fread the file?  The problem with not freading is
that the application should remember which method was successful (mapping or
reading) to use the correct cleanup routine, and that's not optimal IMO.

One more thing:  Now that we are dropping all the extra flags and features:

  - Should we drop the struct and use return the buffer and set *length, like
g_file_get_contents is?  The problem is that to free the map we need that the
user passes the length.

  - Instead of having a writable flag, should we use two different functions,
one returning gchar *, another const gchar *?  That enforces some type checking
that can avoid weird segfaults later.
Comment 46 Matthias Clasen 2005-06-18 06:34:53 UTC
No, keep the struct.

One more thing that occured to me is that it might be nice to have something
like g_mapped_file_is_stale() which would check if the file has changed since
the mapping was established. That is a common operation for all the "mmap-cache"
use cases.

I think we should also start to think about docs for the new function. The docs 
should mention that modifications of the underlying file may affect the contents
of the GMappedFile, and recomment that GMappedFile should only be used for files
which are

a) never modified during normal operation
or
b) atomically replaced 
or 
c) locked

Comment 47 Gustavo Carneiro 2005-06-19 20:52:33 UTC
I would just like to point out APR's mmap abstraction:
http://svn.apache.org/repos/asf/apr/apr/trunk/mmap/
Documentation here: http://apr.apache.org/docs/apr/group__apr__mmap.html
Comment 48 Matthias Clasen 2005-06-23 17:00:12 UTC
To answer the question in comment #5, Irix 5.3 seems to be an example
of mmap() without MAP_FAILED, see bug 308449
Comment 49 Matthias Clasen 2005-06-23 20:05:58 UTC
Here is my own proposal for a very direct mmap wrapper. 
Does this look 
 a) agreeable 
 b) correct, documentation-wise 
 c) implementable on Windows ?
Comment 50 Matthias Clasen 2005-06-23 20:07:51 UTC
Created attachment 48234 [details]
gmappedfile.h
Comment 51 Matthias Clasen 2005-06-23 20:09:00 UTC
Created attachment 48235 [details]
gmappedfile.c
Comment 52 Tor Lillqvist 2005-06-24 01:20:55 UTC
Re c), as far as I can see (and understand the Win32 API documentation), yes.
But only experimentation will tell whether writable/non-shared will actually work.

The documentation for g_mapped_file_new() uses "they may not be written back".
Would it be clearer to say "they MIGHT not be written back"?
Comment 53 Behdad Esfahbod 2005-06-24 01:44:49 UTC
Looks fine to me.

  - You later add a modification time field to the struct to implement
g_mapped_file_is_stale(), right?

  - What about wrapping msync, is it needed?

Picky stuff:

  - In docs, you don't mean "wether", do you? ;)

  - Typo: MA_PRIVATE -> MAP_PRIVATE
Comment 54 Matthias Clasen 2005-06-24 13:23:02 UTC
Tor, could you do a quick experiment to see if writable/non-shared will work ?
If not, we will be better off without those flags. I'll try to write a little 
test for checking if writable/shared work later today.

Behdad, I'm not so sure about the is_stale() idea anymore. First of all,
the gtk icon cache doesn't actually do that check, and if you think about it,
it is not trivial to omplement. You can not simply unmap the cache which is in
heavy use by GTK+. Instead, you have to properly replace all references to the
old cache by references to the new cache. Now, we do have that in place, for 
icon theme changes, but you have to make sure that changing from a theme to
itself actually works to reopen the cache.

Also the semantics of is_stale() are not totally obvious. Do you keep the
filename around and stat that, or do you keep the file descriptor around and
fstat that ? I believe that will give different results, if the underlying
file has been atomically replaced. Also, the mmap specs seem to indicate
that not all changes in the shared buffer are necessarily reflected in
mtime changes of the underlying file.

So this may need some more thought.
Comment 55 Soren Sandmann Pedersen 2005-06-24 14:43:51 UTC
The implementation looks correct to me, but I don't really see the use for the
"shared" flag though. For readable mappings it doesn't make any difference, and
writable/shared mappings are not that much used in practice. Also, two adjacent
booleans in the interface makes it much easier to get them mixed up: "Does
writable come before shared or is it the other way around"?

I agree that if writable/non-shared doesn't work on Windows, then writable
shouldn't be supported at all.

I also agree that the is_stale() method is probably a bad idea.

Tiny thing about the implementation: maybe check the error location with

    g_return_val_if_fail (!err || *err == NULL, NULL)
Comment 56 Matthias Clasen 2005-06-24 16:24:45 UTC
Created attachment 48280 [details]
a test

Here are some tests
Comment 57 Matthias Clasen 2005-06-24 16:32:16 UTC
Soeren, your proposal is to

a) do away with the shared parameter, always MAP_PRIVATE
b) verify that writable/non-shared mappings can actually be
   implemented on Windows, if not, drop writable from the api as well ?
Comment 58 Soren Sandmann Pedersen 2005-06-24 17:23:56 UTC
Yes, that is my proposal

Comment 59 Matthias Clasen 2005-06-24 17:50:35 UTC
Created attachment 48283 [details]
simplified version
Comment 60 Matthias Clasen 2005-06-24 17:51:54 UTC
Created attachment 48284 [details]
simplified header
Comment 61 Matthias Clasen 2005-06-24 17:52:43 UTC
Created attachment 48285 [details]
simplified test
Comment 62 Tor Lillqvist 2005-06-24 20:36:25 UTC
Created attachment 48301 [details]
win32 file mappping test program for writable/non-shared

A small test program that verifies that writable/non-shared works on Windows,
too. (Using PAGE_WRITECOPY for the protection of the file view in the
CreateFileMapping() call, and then using FILE_MAP_COPY for the access to the
mappded pages in the MapViewOfFil() call.)
Comment 63 Tor Lillqvist 2005-06-24 20:44:29 UTC
And once I corrected the fopen mode to "r+b", and added the possibility to
select writable/shared with a command line option, that too indeed works. Then
one uses PAGE_READWRITE in the CreateFileMapping() and FILE_MAP_WRITE in the
MapViewOfFile().
Comment 64 Matthias Clasen 2005-06-25 03:39:56 UTC
Thanks for testing Tor. Lets do without sharing for now, even if it
works on win32. If it turns out to be an important feature, we can
always add a g_mapped_file_new_shared().

2005-06-24  Matthias Clasen  <mclasen@redhat.com>

	Add an mmap() wrapper called GMappedFile. (#148218,
	David Schleef, Behdad Esfahbod)
	
	* glib/gmappedfile.[hc]: New files.

	* configure.in: Check for mmap.
	
	* glib/Makefile.am: Add new files.
	
	* glib/glib.symbols: Add new functions.

	* glib/glib.h: Include gmappedfile.h

	* tests/mapping-test.c: Tests for GMappedFile.

	* tests/Makefile.am: Add new file.
Comment 65 Behdad Esfahbod 2005-06-25 06:58:34 UTC
Nice to see this commited.

I don't know about the glib standards for this, but I think we can change the
API in this way:

gsize        g_mapped_file_get_length   (const GMappedFile  *file) G_GNUC_CONST;
gchar       *g_mapped_file_get_contents (const GMappedFile  *file) G_GNUC_CONST;

This way it's both clear to the user and to the compiler that these two
functions are cheap and simply return a precomputed value.
Comment 66 Behdad Esfahbod 2005-06-25 12:43:47 UTC
Oops, that should read G_GNUC_PURE, not G_GNUC_CONST.

About is_staled, all agreed, but to faciliate stale checking for applications,
and since we already are stat'ing the file, what about having a
g_mapped_file_get_mtime() that returns the modification time of the file at the
time of mapping?


And finally, seems like this:

  g_return_val_if_fail (!error || *error == NULL, NULL)

is typically written this way:

  g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);

:)