mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 05:42:29 +00:00
Fix msync() flags on FreeBSD
This commit is contained in:
parent
ebf784d4f5
commit
fffcd98b0e
7 changed files with 95 additions and 15 deletions
|
@ -25,6 +25,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Synchronize memory mapping changes to disk.
|
||||
|
@ -37,20 +38,61 @@
|
|||
* @return 0 on success or -1 w/ errno
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if we needed to block and a signal was delivered instead
|
||||
* @raise EINVAL if `MS_SYNC` and `MS_ASYNC` were both specified
|
||||
* @raise EINVAL if unknown `flags` were passed
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int msync(void *addr, size_t size, int flags) {
|
||||
int rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
unassert(((flags & MS_SYNC) ^ (flags & MS_ASYNC)) || !(MS_SYNC && MS_ASYNC));
|
||||
if (!IsWindows()) {
|
||||
rc = sys_msync(addr, size, flags);
|
||||
} else {
|
||||
rc = sys_msync_nt(addr, size, flags);
|
||||
if ((flags & ~(MS_SYNC | MS_ASYNC | MS_INVALIDATE)) ||
|
||||
(flags & (MS_SYNC | MS_ASYNC)) == (MS_SYNC | MS_ASYNC)) {
|
||||
rc = einval();
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// According to POSIX, either MS_SYNC or MS_ASYNC must be specified
|
||||
// in flags, and indeed failure to include one of these flags will
|
||||
// cause msync() to fail on some systems. However, Linux permits a
|
||||
// call to msync() that specifies neither of these flags, with
|
||||
// semantics that are (currently) equivalent to specifying MS_ASYNC.
|
||||
// ──Quoth msync(2) of Linux Programmer's Manual
|
||||
int sysflags = flags;
|
||||
sysflags = flags;
|
||||
if (flags & MS_ASYNC) {
|
||||
sysflags = MS_ASYNC;
|
||||
} else if (flags & MS_SYNC) {
|
||||
sysflags = MS_SYNC;
|
||||
} else {
|
||||
sysflags = MS_ASYNC;
|
||||
}
|
||||
if (flags & MS_INVALIDATE) {
|
||||
sysflags |= MS_INVALIDATE;
|
||||
}
|
||||
|
||||
// FreeBSD's manual says "The flags argument was both MS_ASYNC and
|
||||
// MS_INVALIDATE. Only one of these flags is allowed." which makes
|
||||
// following the POSIX recommendation somewhat difficult.
|
||||
if (IsFreebsd()) {
|
||||
if (sysflags == (MS_ASYNC | MS_INVALIDATE)) {
|
||||
sysflags = MS_INVALIDATE;
|
||||
}
|
||||
}
|
||||
|
||||
// FreeBSD specifies MS_SYNC as 0 so we shift the Cosmo constants
|
||||
if (IsFreebsd()) {
|
||||
sysflags >>= 1;
|
||||
}
|
||||
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_msync(addr, size, sysflags);
|
||||
} else {
|
||||
rc = sys_msync_nt(addr, size, sysflags);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
|
||||
Finished:
|
||||
STRACE("msync(%p, %'zu, %#x) → %d% m", addr, size, flags, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue