Double mapping of memory regions on Unix

Sometimes it makes sense to double map the same physical memory onto different locations in address space of process, for example in 64-bit systems have some parts of your address space to be accessible using 16-bit or 32-bit addresses. In this example I'll show how to make part of the memory visible through "window" located at virtual address 0x80000. This method isn't as good, as could be just direct manipulation of page tables, as creation of file mapping of existing memory location effectively clears data in it and also may lead to write into backing store (file), but still could be sometimes useful in low level optmizations.

One example of such optimizations - if you have frequently used data in JVM heap, and want to access them quickly, while want to avoid chunked heap, you may double map part of your heap at predefined address, and in fast accessors use low addresses, while in GC code use regular addresses of exactly same data. Not sure, if such approach wouldn't lead to cache coherency problem on CPUs with virtually indexed caches.

If you have ideas how to make double mapping non-overriding, and not using backing storage - please let me know.

#define _GNU_SOURCE 1

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

char\* window = (char\*)0x80000;
int window_size = 4096;

int make_window(char\* where) {
  char wname[128];
  char \*win1, \*win2;
  int fd;
  
  sprintf(wname, "/tmp/__window%x", getpid()); 
  
  unlink(wname);
  fd = open(wname, O_CREAT | O_RDWR);
  if (fd < 0) {
    perror("open");
    return 0;
  }
  if (ftruncate(fd, (off_t)window_size) < 0) {
    perror("ftruncate");
    return 0;
  } 

  win1 = (char\*)mmap(where, window_size, 
                     PROT_READ | PROT_WRITE, 
                     MAP_SHARED | MAP_FIXED,
                     fd, 0);
  if (win1 == (char\*)-1) {
    perror("mmap1");
    return 0;
  }
  
  win2 = (char\*)mmap((void\*)0x80000, window_size, PROT_READ | PROT_WRITE, 
                     MAP_SHARED | MAP_FIXED,
                     fd, 0);
  if (win2 == (char\*)-1) {
    perror("mmap2");
    return 1;
  }
  
  if (close(fd) < 0) {
    perror("close");
  }
  if (unlink(wname) < 0) {
    perror("unlink");
  }
  return 1;
}

int main() {
  char \*heap;
  int heap_size = 4096\*4096;
 
  heap = (char\*)mmap(NULL, heap_size, PROT_READ | PROT_WRITE, 
                     MAP_ANONYMOUS | MAP_PRIVATE,
                     -1, 0);
  if (heap == (char\*)-1) {
    perror("mmap heap");
    return 1;
  }

  printf("heap at %p\\n", heap);
  
  if (!make_window(heap+8192)) {
    return 1;
  }

  window[0] = 0x1f;
  printf("window at %p: in heap=%x in window=%x\\n", 
         window, heap[8192], window[0]);
  
  return 0;
}
  
Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

nike

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today