Commit graph

103 commits

Author SHA1 Message Date
Daniel Eklöf
299186a654
render: when double-buffering, pre-apply previous frame's damage early
Foot likes it when compositor releases buffer immediately, as that
means we only have to re-render the cells that have changed since the
last frame.

For various reasons, not all compositors do this. In this case, foot
is typically forced to switch between two buffers, i.e. double-buffer.

In this case, each frame starts with copying over the damage from the
previous frame, to the new frame. Then we start rendering the updated
cells.

Bringing over the previous frame's damage can be slow, if the changed
area was large (e.g. when scrolling one or a few lines, or on full
screen updates). It's also done single-threaded. Thus it not only
slows down frame rendering, but pauses everything else (i.e. input
processing). All in all, it reduces performance and increases input
latency.

But we don't have to wait until it's time to render a frame to copy
over the previous frame's damage. We can do that as soon as the
compositor has released the buffer (for the frame _before_ the
previous frame). And we can do this in a thread.

This frees up foot to continue processing input, and reduces frame
rendering time since we can now start rendering the modified cells
immediately, without first doing a large memcpy(3).

In worst case scenarios (or perhaps we should consider them best case
scenarios...), I've seen up to a 10x performance increase in frame
rendering times (this obviously does *not* include the time it takes
to copy over the previous frame's damage, since that doesn't affect
neither input processing nor frame rendering).

Implemented by adding a callback mechanism to the shm abstraction
layer. Use it for the grid buffers, and kick off a thread that copies
the previous frame's damage, and resets the buffers age to 0 (so that
foot understands it can start render to it immediately when it later
needs to render a frame).

Since we have certain way of knowing if a compositor releases buffers
immediately or not, use a bit of heuristics; if we see 10 consecutive
non-immediate releases (that is, we reset the counter as soon as we do
see an immediate release), this new "pre-apply damage" logic is
enabled. It can be force-disabled with tweak.pre-apply-damage=no.

We also need to take care to wait for the thread before resetting the
render's "last_buf" pointer (or we'll SEGFAULT in the thread...).

We must also ensure we wait for the thread to finish before we start
rendering a new frame. Under normal circumstances, the wait time is
always 0, the thread has almost always finished long before we need to
render the next frame. But it _can_ happen.

Closes #2188
2025-10-10 10:23:17 +02:00
Daniel Eklöf
bd994eda1c
shm: page-align the memfd size (also needed for GPU direct import) 2025-10-05 09:40:51 +02:00
Daniel Eklöf
fac3994154
config: add tweak.min-stride-alignment
This allows the user to configure the value by which a surface
buffer's stride must be an even multiple of.

This can be used to ensure the stride meets the GPU driver's
requirements for direct import.

Defaults to 256. Set to 0 to disable.

Closes #2182
2025-10-05 09:40:20 +02:00
Daniel Eklöf
7ab43ebf74
shm: don't set pixman_fmt_without_alpha twice
When selecting 16-bit surfaces, we set pixman_fmt_without_alpha twice,
and never set pixman_fmt_with_alpha.

This caused 10-bit surfaces to be used instead, since it checks if
pixman_fmt_with_alpha has been overridden or not.
2025-07-21 13:49:57 +02:00
Daniel Eklöf
970e13db8d
config: tweak.surface-bit-depth: add support for 16-bit surfaces
This adds supports for 16-bit surfaces, using the new
PIXMAN_a16b16g16r16 buffer format. This maps to
WL_SHM_FORMAT_ABGR16161616 (little-endian).

Use the new 16-bit surfaces by default, when
gamma-correct-blending=yes.
2025-05-03 09:04:15 +02:00
Daniel Eklöf
e5a0755451
config: tweak.surface-bit-depth now defaults to 'auto'
When set to 'auto', use 10-bit surfaces if gamma-correct blending is
enabled, and 8-bit surfaces otherwise.

Note that we may still fallback to 8-bit surfaces (without disabling
gamma-correct blending) if the compositor does not support 10-bit
surfaces.

Closes #2082
2025-05-01 08:54:30 +02:00
Daniel Eklöf
ccf625b991
render: gamma-correct blending
This implements gamma-correct blending, which mainly affects font
rendering.

The implementation requires compile-time availability of the new
color-management protocol (available in wayland-protocols >= 1.41),
and run-time support for the same in the compositor (specifically, the
EXT_LINEAR TF function and sRGB primaries).

How it works: all colors are decoded from sRGB to linear (using a
lookup table, generated in the exact same way pixman generates it's
internal conversion tables) before being used by pixman. The resulting
image buffer is thus in decoded/linear format. We use the
color-management protocol to inform the compositor of this, by tagging
the wayland surfaces with the 'ext_linear' image attribute.

Sixes: all colors are sRGB internally, and decoded to linear before
being used in any sixels. Thus, the image buffers will contain linear
colors. This is important, since otherwise there would be a
decode/encode penalty every time a sixel is blended to the grid.

Emojis: we require fcft >= 3.2, which adds support for sRGB decoding
color glyphs. Meaning, the emoji pixman surfaces can be blended
directly to the grid, just like sixels.

Gamma-correct blending is enabled by default *when the compositor
supports it*. There's a new option to explicitly enable/disable it:
gamma-correct-blending=no|yes. If set to 'yes', and the compositor
does not implement the required color-management features, warning
logs are emitted.

There's a loss of precision when storing linear pixels in 8-bit
channels. For this reason, this patch also adds supports for 10-bit
surfaces. For now, this is disabled by default since such surfaces
only have 2 bits for alpha. It can be enabled with
tweak.surface-bit-depth=10-bit.

Perhaps, in the future, we can enable it by default if:

* gamma-correct blending is enabled
* the user has not enabled a transparent background
2025-03-05 18:45:01 +01:00
Daniel Eklöf
5e65f3f07e
shm: codespell: re-using -> reusing 2025-01-22 08:04:17 +01:00
Daniel Eklöf
046d959657
shm: fix compilation when FORCED_DOUBLE_BUFFERING is enabled 2024-09-21 09:11:07 +02:00
Daniel Eklöf
0a5ba708e4
notify: don't close FD 0
This fixes a regression where closing a terminal instance, or hard- or
soft-resetting a terminal caused FD 0 to be closed.

This meant it became re-usable. Usually, by memfd_create() when
allocating a new surface buffer. So far nothing _really_ bad has
happened.

But what if FD 0 is now used by a memfd, and we close _another_
terminal instance?

This causes our memfd to be closed. And then, when e.g. trying to
scroll the terminal content: fallocate() fails with bad FD.
2024-07-30 16:33:19 +02:00
Daniel Eklöf
795e39de1a
shm: discard shm buffers with mis-matching alpha-setting 2024-06-24 20:09:37 +02:00
Daniel Eklöf
f64cc04fe6
shm: minor optimization
Don't retry memfd_create() without MFD_NOEXEC_SEAL is 0.

The overall logic is this:

* Try memfd_create() with MFD_NOEXEC_SEAL
* If that fails (which it does, on older kernels), try without the flag

If compiling against an older kernel, or on a system that doesn't
support the noexec seal, MFD_NOEXEC_SEAL is 0.

In this case, there's little point in retrying memfd_create a second
time, with the exact same set of flags.
2024-05-22 14:06:15 +02:00
Daniel Eklöf
67f97cbca1
shm: use XRGB surfaces when we know we wont be using transparency 2024-02-21 16:29:10 +01:00
Daniel Eklöf
7999975016
Don't use fancy Unicode quotes, stick to ASCII 2024-02-06 12:36:45 +01:00
Craig Barnes
91b22ae21a Replace unchecked allocations with calls to xmalloc.h functions 2024-01-25 07:03:50 +00:00
Daniel Eklöf
c006ac3a07
shm: memfd_create: fallback to not using MFD_NOEXEC_SEAL
MFD_NOEXEC_SEAL was introduced in linux 6.3. Kernels before that
will *reject* memfd_create() calls that set it.

This caused foot to exit (i.e. not start at all), when compiled on
linux >= 6.3, but run on linux < 6.3.

We _do_ want to use MFD_NOEXEC_SEAL, since a) our memory mapped really
shouldn't be executable, and b) to silence a warning on linux >= 6.3.

To handle all cases, first try *with* MFD_NOEXEC_SEAL. If that fails
with EINVAL, retry *without* it.

Closes #1514
2023-10-12 16:16:11 +02:00
Daniel Eklöf
c50b1f9900
render: more fine-grained wayland surface damage tracking
Before this patch. Wayland surface damage tracking was done on a
per-row basis. That is, even if just one cell was updated, the entire
row was "damaged".

Now, damage is per cell. This hopefully results in lower latencies in
many use cases, and especially on high DPI monitors.
2023-10-10 07:56:27 +02:00
Daniel Eklöf
e41555fe0f
shm: move definition of FOOT_MFD_FLAGS to the top 2023-10-08 11:03:13 +02:00
6t8k
61eb56dfda
shm: if defined, set MFD_NOEXEC_SEAL flag for memfd_create
Effective from Linux 6.3.0 onward, this creates the memfd without
execute permissions and prevents that setting from ever being changed.

This is a defense-in-depth security measure and prevents a respective
kernel warning from being emitted.

See https://lwn.net/Articles/918106/ for more information.
2023-10-05 12:33:05 +02:00
Daniel Eklöf
5e1d73f3cd
Codespell fixes 2023-10-03 14:12:58 +02:00
Daniel Eklöf
58d967b2f3
Codespell fixes 2023-10-03 14:11:55 +02:00
Daniel Eklöf
4340f8a3b4
render: fix application of old scroll damage when double buffering
On compositors that forces us to double buffer, we need to re-apply
the last frame’s damage to the current frame (which uses the buffer
from the next-to-last frame).

General cell updates are handled by simply copying from the last
frame’s pixman buffer to the current frame’s.

In an attempt to improve performance, scroll damage were up until now
handled by re-playing the last frame’s scroll damage (on the current
frame’s buffer). This does not work, and resulted in glitches when
scrolling in the scrollback.

This patch does the following:

* grid_render_scroll{,_reverse}() now update the buffer’s "dirty"
  region. This means the generic copy-old-frames-buffer handles the
  scroll damage (albeit in, potentially, a less efficient way).

* Tracking of, and re-applying old scroll damage is completely
  removed.

Closes #1173
2022-09-23 20:33:02 +02:00
Daniel Eklöf
abbdd3bae8
shm: add shm_did_not_use_buffer()
This allows a caller to return a buffer (obtained with
shm_get_buffer()) to the pool,

The buffer must not have been used. I.e. it must not have been
attached and committed to a wayland surface.
2022-04-16 17:47:56 +02:00
Pranjal Kole
0da19a81bc replace gettimeofday with clock_gettime
POSIX.1-2008 has marked gettimeofday(2) as obsolete, recommending the
use of clock_gettime(2) instead.

CLOCK_MONOTONIC has been used instead of CLOCK_REALTIME because it is
unaffected by manual changes in the system clock. This makes it better
for our purposes, namely, measuring the difference between two points in
time.

tv_sec has been casted to long in most places since POSIX does not
define the actual type of time_t.
2022-01-15 21:35:45 +05:30
Daniel Eklöf
fc6533c920
shm: get_buffer(): make sure buffer->busy is set
When going through the cached buffers, we only set buffer->busy on
the *first* re-usable buffer we found.

In some cases, we will find more than one re-usable buffer. In this
case, we select the “youngest” one (i.e the one most recently used, in
the hopes that we can use damage tracking instead of re-rendering the
entire buffer).

If the “current” buffer is younger than the previously detected,
re-usable, buffer, then we unref:ed the previously selected buffer,
and replaced it with the current one.

But, we did not sanitize it. That is, we did not:

* set buffer->busy
* clear its dirty region
* clear its scroll damage

That buffer would eventually get rendered to, and committed to the
compositor. Later, the compositor would free it. And there, in our
buffer_release() callback, we’d assert that buffer->busy was
set. And fail.

Closes #844
2021-12-18 14:26:26 +01:00
feeptr
304aacdb7a fix crashes when resizing after CSD enabled at runtime with csd.size = 0 2021-10-04 18:14:58 -04:00
Daniel Eklöf
5b6a2b0eaf
shm: get_many(): allow “NULL” buffers - buffers where width or height is 0
When a zero-sized buffer is requested, simply return a NULL buffer,
instead of crashing with a Wayland protocol error.

This makes it easier to request many buffers, where some may be
zero-sized, without having to pack the width/height and bufs arrays.
2021-07-18 16:44:49 +02:00
Daniel Eklöf
6657146a20
shm: chain_free: BUG() if there are buffers remaining after purge
There may be buffers left, if their destruction has been
deferred. However, they should be on the 'deferred' list, not the
chain's buffer list.

If there are buffers left on the chain's list, that means someone
forgot to call shm_unref().
2021-07-17 19:14:42 +02:00
Daniel Eklöf
0751172b92
shm: get_buffer: purge mismatching buffers in first buffer iteration
There's no longer any need to defer purging of mismatching buffer
(i.e. buffers whose width/height doesn't match the requested ones) to
after the cache lookup loop.
2021-07-17 19:14:42 +02:00
Daniel Eklöf
53851e13ec
shm: refactor: move away from a single, global, buffer list
Up until now, *all* buffers have been tracked in a single, global
buffer list. We've used 'cookies' to separate buffers from different
contexts (so that shm_get_buffer() doesn't try to re-use e.g. a
search-box buffer for the main grid).

This patch refactors this, and completely removes the global
list.

Instead of cookies, we now use 'chains'. A chain tracks both the
properties to apply to newly created buffers (scrollable, number of
pixman instances to instantiate etc), as well as the instantiated
buffers themselves.

This means there's strictly speaking not much use for shm_fini()
anymore, since its up to the chain owner to call shm_chain_free(),
which will also purge all buffers.

However, since purging a buffer may be deferred, if the buffer is
owned by the compositor at the time of the call to shm_purge() or
shm_chain_free(), we still keep a global 'deferred' list, on to which
deferred buffers are pushed. shm_fini() iterates this list and
destroys the buffers _even_ if they are still owned by the
compositor. This only happens at program termination, and not when
destroying a terminal instance. I.e. closing a window in a “foot
--server” does *not* trigger this.

Each terminal instatiates a number of chains, and these chains are
destroyed when the terminal instance is destroyed. Note that some
buffers may be put on the deferred list, as mentioned above.
2021-07-17 19:14:42 +02:00
Daniel Eklöf
4efb34927e
shm: remove deferred buffers from main list immediately
When unref:ing a "busy" buffer, destruction is (still) deferred to the
buffer release event.

However, we now move the buffer off the buffer list immediately, and
instead push it to a 'deferred' list. This prevents buffer re-use of
buffers scheduled for destruction.

It also means less buffers to iterate through when trying to find a
re-usable buffer in shm_get_buffer(), since we no longer have to wade
through a potentially long list of to-be-deleted buffers.
2021-07-17 19:14:42 +02:00
Daniel Eklöf
232fb20269
shm: replace 'locked' attribute with a ref-counter
The initial ref-count is either 1 or 0, depending on whether the
buffer is supposed to be released "immeidately" (meaning, as soon as
the compositor releases it).

Two new user facing functions have been added: shm_addref() and
shm_unref().

Our renderer now uses these two functions instead of manually setting
and clearing the 'locked' attribute.

shm_unref() will decrement the ref-counter, and destroy the buffer
when the counter reaches zero. Except if the buffer is currently
"busy" (compositor owned), in which case destruction is deferred to
the release event. The buffer is still removed from the list though.
2021-07-17 19:14:42 +02:00
Daniel Eklöf
69260dd960
shm: we may exit with busy buffers remaining (seen on KDE) 2021-07-17 19:14:41 +02:00
Daniel Eklöf
99ea47c97a
shm: move ‘size’ to the private buffer struct 2021-07-17 19:14:41 +02:00
Daniel Eklöf
9b6cee825b
shm: rename buffer.mmapped to buffer.data 2021-07-17 19:14:41 +02:00
Daniel Eklöf
75f7f21a48
shm: split up buffer struct into internal/private and public parts 2021-07-17 19:14:41 +02:00
Daniel Eklöf
931595bda5
shm: codespell 2021-07-15 19:40:15 +02:00
Daniel Eklöf
a486851bdd
shm: auto-purge when we have multiple buffers eligible for re-use
It may happen that we end up with multiple non-busy, same-sized
buffers for the same cookie (context), and thus eligible for re-use.

Before this patch, we would keep all those buffers around. This is
completely unnecessary. Under normal circumstances, we’ll either be
re-using a single buffer, or swap between two. In the second case, the
“other” buffer is always busy, and thus not eligible for re-use.

So, if we _do_ detect multiple, re-usable buffers, pick the one with
the lowest “age” (increasing the chance of applying damage tracking,
instead of re-drawing everything), and mark the other one for purging.
2021-07-15 19:19:31 +02:00
Daniel Eklöf
7533684d8f
shm: add shm_get_many() - allows buffers to share a single pool
shm_get_many() always returns new buffers (i.e. never old, cached
ones). The newly allocated buffers are also marked for immediate
purging, meaning they’ll be destroyed on the next call to either
shm_get_buffer(), or shm_get_many().

Furthermore, we add a new attribute, ‘locked’, to the buffer
struct. When auto purging buffers, look at this instead of comparing
cookies.

Buffer consumers are expected to set ‘locked’ while they hold a
reference to it, and don’t want it destroyed behind their back.
2021-07-15 18:39:23 +02:00
Daniel Eklöf
22651ed221
shm: reset buffer pool FD when we close it
This fixes an issue where we ended up "double closing" buffer FDs.

In many cases (especially on compositors with SSDs) this was pretty
rare. And even when it did happen, the FD was normally unused, and
thus nothing bad happened.

However, by quickly resizing the window while using CSDs, it was
fairly easy to trigger this. We sometimes ended up closing the
TIOCSWINCH timer FD while thinking it was a buffer FD, but most of the
times we just ended up closing _another_ buffer’s pool FD, leading to
an immediate disconnect by the compositor.
2021-07-14 20:51:42 +02:00
Daniel Eklöf
107cbb1015
shm: close pool FD if buffer doesn’t support SHM scrolling
The only reason to keep the pool FD open is if we’re going to SHM
scroll the buffer; we need the FD for fallocate(FALLOC_FL_PUNCH_HOLE).

In all other cases, there’s absolutely no need to keep the FD
open. Thus, close it as soon as we’ve instantiated the buffer. This
frees up FDs, and help keep foot from FD ulimit.
2021-07-11 10:22:47 +02:00
Daniel Eklöf
945a346596
shm: clear buffer’s dirty region before returning a cached buffer
A non-busy buffer should always have an empty dirty region
2021-05-12 20:06:15 +02:00
Daniel Eklöf
37bbf44f6d
shm: set ‘age’ in newly allocated buffers to something large
This ensures we don’t try to do a partial update of fresh buffer.
2021-05-12 20:06:15 +02:00
Daniel Eklöf
0433ba8477
shm: free scroll damage before returning cached buffer 2021-05-12 20:06:15 +02:00
Daniel Eklöf
34becf0df0
render: code cleanup, log double buffering time
* Break out cursor cell dirtying to separate functions
* Break out handling of double buffering
* Handle buffers with age > 1 (we’re swapping between more than 2
  buffers)
* Detect full screen repaints, and skip re-applying old frame’s damage
* Use an allocated array insted of a tll list for old frame’s scroll damage
* When logging frame rendering time, including the amount used for
  double buffering.
2021-05-12 20:06:15 +02:00
Daniel Eklöf
434c9c3a34
shm: add damage tracking to buffer 2021-05-12 20:06:15 +02:00
Daniel Eklöf
c8b342ae51
shm: track busy buffers’ age, and add compile-time option to force double buffering
By default, age all matching buffers that are busy (i.e. in use by the
compositor).

This allows us to detect whether we can apply the current frame’s
damage directly, or if we need to prepare the buffer first (e.g. copy
old buffer, or re-apply last frame’s damage etc).
2021-05-12 20:06:04 +02:00
Daniel Eklöf
0d07ee03f5
shm: don’t check for __i386__ and __x86_64__ - there are other architectures out there
Instead, check for __SIZEOF_POINTER__ == 8, since what we’re really
interested in is whether we have enough virtual address space or not.
2021-01-23 09:52:42 +01:00
Jan Beich
db9dc7e908
shm: unbreak build without memfd_create
New FreeBSD versions have memfd_create but other BSDs don't.

pgo/pgo.c:260:22: error: implicit declaration of function 'memfd_create' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
        int mem_fd = memfd_create("foot-pgo-ptmx", MFD_CLOEXEC);
                     ^
pgo/pgo.c:260:52: error: use of undeclared identifier 'MFD_CLOEXEC'
        int mem_fd = memfd_create("foot-pgo-ptmx", MFD_CLOEXEC);
                                                   ^
shm.c:13:10: fatal error: 'linux/mman.h' file not found
 #include <linux/mman.h>
          ^~~~~~~~~~~~~~
shm.c:277:15: error: implicit declaration of function 'memfd_create' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING);
              ^
shm.c:277:60: error: use of undeclared identifier 'MFD_CLOEXEC'
    pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING);
                                                           ^
shm.c:277:74: error: use of undeclared identifier 'MFD_ALLOW_SEALING'
    pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING);
                                                                         ^
shm.c:339:15: error: use of undeclared identifier 'F_SEAL_GROW'
              F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0)
              ^
shm.c:339:29: error: use of undeclared identifier 'F_SEAL_SHRINK'
              F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0)
                            ^
shm.c:339:71: error: use of undeclared identifier 'F_SEAL_SEAL'
              F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0)
                                                                      ^
shm.c:338:24: error: use of undeclared identifier 'F_ADD_SEALS'
    if (fcntl(pool_fd, F_ADD_SEALS,
                       ^
2021-01-23 09:52:40 +01:00
Jan Beich
013e3c2d80
shm: disable fallocate optimization if not supported
shm.c:301:26: error: implicit declaration of function 'fallocate' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
        can_punch_hole = fallocate(
                         ^
shm.c:302:22: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
            pool_fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1) == 0;
                     ^
shm.c:302:45: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
            pool_fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1) == 0;
                                            ^
shm.c:432:9: error: implicit declaration of function 'fallocate' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    if (fallocate(
        ^
shm.c:434:13: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
            ^
shm.c:434:36: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                                   ^
shm.c:501:9: error: implicit declaration of function 'fallocate' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    if (fallocate(
        ^
shm.c:503:13: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
            ^
shm.c:503:36: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                                   ^
shm.c:597:9: error: implicit declaration of function 'fallocate' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    if (fallocate(
        ^
shm.c:599:13: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
            ^
shm.c:599:36: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                                   ^
2021-01-23 09:52:40 +01:00