1

I was looking for a method of allocating memories on Linux which similar VirtualAlloc on Windows. Requirements are:

  1. Size of memories block to allocate is 2^16.
  2. Address of memories block is larger than 0x0000ffff
  3. Address of memories block must have last 16 bits are zero.

On Windows because lower limit of application address (lpMinimumApplicationAddress) we have (2) obvious right. From (1), (2) and system rules we also achieved (3).

Thanks for helping.

Giang
  • 51
  • 5
  • @Ignacio: Typically for DMA. This is (indirectly) the reason that direct I/O functions often require aligned buffers. – Ben Voigt May 22 '11 at 03:43
  • What is user code doing allocating memory for DMA? – Ignacio Vazquez-Abrams May 22 '11 at 03:46
  • @Ignacio: I just told you: direct (unbuffered) I/O. On Windows that would be `FILE_FLAG_NO_BUFFERING`. Not sure exactly how it's done on Linux, but the kernel just locks the buffer you provide and uses it for DMA, instead of copying from a DMA bounce buffer. "Zero-copy I/O" is in high demand. – Ben Voigt May 22 '11 at 03:53
  • @Ignacio: For #3, I'm trying to implement memory pooling. I can get address to the chunk by (blockPtr & 0xffff0000). This is useful when deallocate a block. – Giang May 22 '11 at 03:57

3 Answers3

1

Try mmap(..., MAP_ANONYMOUS, ...)

You'll get an address which is aligned to a page boundary. For more stringent alignment than that, you probably need to allocate extra and pick an address inside your larger block than is correctly aligned.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Thanks but how to obtain (2) and (3) with this?. – Giang May 22 '11 at 03:49
  • 1
    @Giang: #2 happens, the OS reserves the first few pages of memory to help detect NULL pointers. For #3, if you allocate 2**17 bytes, you are guaranteed to have a block of 2**16 starting on a 2**16 boundary somewhere in the allocated region. Or, as @sherpya says, you can request an address that meets your requirements. If it's not already in use, you'll get the exact address you requested. – Ben Voigt May 22 '11 at 03:54
  • Thanks but do so seems like too waste. Can we tell mmap the lower limit of memory address we want?. – Giang May 22 '11 at 04:03
  • @Giang: Have you read the man page for `mmap`? It's actually quite descriptive. – Ben Voigt May 22 '11 at 04:05
  • Yes, I read it even before asking this question. Hint params not really is a lower limit. – Giang May 22 '11 at 04:15
  • @Giang: Allocating twice as much as you need doesn't waste anything, because you can use the aligned block and give the other portions back with `munmap`. – Ben Voigt May 22 '11 at 04:31
  • @Ben Voigt: I tried mmap(0, 65536 * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0). Sadly it return an address which have last 12 bits zero, not 16 bits. What wrong?. – Giang May 22 '11 at 08:09
  • @Giang: Nothing's wrong, now you need to get the subset of that large block that IS aligned. Like [this](http://ideone.com/Bxzm7). – Ben Voigt May 22 '11 at 09:46
0

you can ask a specific address to mmap, it may fail for some specific addresses, but generally it works

sherpya
  • 4,890
  • 2
  • 34
  • 50
0

You want posix_memalign():

void *ptr;
int memalign_err = posix_memalign(&ptr, 1UL << 16, 1UL << 16);

if (memalign_err) {
    fprintf(stderr, "posix_memalign: %s\n", strerror(memalign_err));
} else {
    /* ptr is valid */
}

The first 1UL << 16 is the alignment, and the second is the size.

When you're done with the block you pass it to free().

caf
  • 233,326
  • 40
  • 323
  • 462