6

Currently I use shm_open to get a file descriptor and then use ftruncate and mmap whenever I want to add a new buffer to the shared memory. Each buffer is used individually for its own purposes.

Now what I need to do is arbitrarily resize buffers. And also munmap buffers and reuse the free space again later.

The only solution I can come up with for the first problem is: ftuncate(file_size + old_buffer_size + extra_size), mmap, copy data accross into the new buffer and then munmap the original data. This looks very expensive to me and there is probably a better way. It also entails removing the original buffer every time.

For the second problem I don't even have a bad solution, I clearly can't move memory around everytime a buffer is removed. And if I keep track of free memory and use it whenever possible it will slow down allocation process as well as leave me with bits and pieces in between that are unused.

I hope this is not too confusing. Thanks

user2936306
  • 236
  • 2
  • 8
  • Question: do you know how many buffers you will need and a max size for each? I'm thinking predefined size with predefined number of buffers. How else would you manage these "buffers used individually for it's own purpose"? Predefined buffer sizes means no fragmentation after all... – pedwards Jun 03 '15 at 21:05
  • The number and size of buffers comes from outside the program, so there is not way I can predict what they will be. – user2936306 Jun 03 '15 at 21:11
  • Sounds like an initialization thing... delay until you know and save yourself a lot of headaches. – pedwards Jun 03 '15 at 21:15
  • No, the buffers are added/removed and resized any number of times throughout runtime. – user2936306 Jun 03 '15 at 21:17
  • And you don't know the worst case scenario? If you do, you should build for that. – pedwards Jun 03 '15 at 21:25
  • Yes I could set a maximum size for each buffer and a maximum number of buffers and set them as limits. However that would be a last resort solution, I hope I wont have to do that. – user2936306 Jun 03 '15 at 21:28
  • I don't understand why you are doing all this copying stuff. You could just do `unmap`, `ftruncate` and then `mmap` again, no? – Jens Gustedt Jun 03 '15 at 21:53
  • Yes, so long as I don't need the original content anymore. Which in some cases I don't, otherwise I would have to refill the entire buffer again instead of just the new part. – user2936306 Jun 03 '15 at 21:58

2 Answers2

4

As best as I understand you need to grow (or shrink) the existing memory mapping. Under linux shared memory implemented as a file, located in /dev/shm memory filesystem. All operations in this file is the same as on the regular files (and file descriptors).

if you want to grow the existing mapping first expand the file size with ftruncate (as you wrote) then use mremap to expand the mapping to the requested size.

If you store pointers points to this region you maybe have to update these, but first try to call with 0 flag. In this case the system tries to grow the existing mapping to the requested size (if there is no collision with other preserved memory region) and pointers remains valid.

If previous option not available use MREMAP_MAYMOVE flag. In this case the system remaps to another locations, but mostly it's done effectively (no copy applied by the system.) then update the pointers.

Shrinking is the same but the reverse order.

Dankó Dávid
  • 302
  • 3
  • 17
4

I wrote an open source library for just this purpose: rszshm - resizable pointer-safe shared memory

To quote from the description page:

To accommodate resizing, rszshm first maps a large, private, noreserve map. This serves to claim a span of addresses. The shared file mapping then overlays the beginning of the span. Later calls to extend the mapping overlay more of the span. Attempts to extend beyond the end of the span return an error.

I extend a mapping by calling mmap with MAP_FIXED at the original address, and with the new size.

Community
  • 1
  • 1
dan4thewin
  • 1,134
  • 7
  • 10
  • The solution does not make sense, since from the beginning the lib takes larger memory space than required. The resize is simply return the pre occupied memory – FaceBro Aug 21 '17 at 00:55
  • The larger span does not allocate the memory but merely claims the addresses. – dan4thewin Aug 21 '17 at 00:59
  • by claiming the memory, the claimed memory cannot be used for other purpose, Right? In this sense, it has the same effect of allocating the reserved memory. – FaceBro Aug 21 '17 at 01:03
  • 1
    Claiming addresses is not the same as allocating memory. – dan4thewin Aug 21 '17 at 01:05
  • Good to know, let me do some research to educate myself first before making more comments. Thanks – FaceBro Aug 21 '17 at 01:06
  • Just for folks primarily interested in *shrinkable* shared mem, note that it appears rszshm doesn't shrink, it only grows. – Whilom Chime Jul 23 '19 at 13:11