next up previous
Next: Using reserved 'raw'-memory Up: Sharing Memory betweeen kerne, Previous: Simple mmap driver

Using /dev/mem

The POSIX way of sharing memory is via /dev/mem - you can pass it an offset of 0 and let the kernel select where to place the shared buffer, or you can allocate a buffer and pass the address and size to the user-space side and then use /dev/mem to mmap it to the user-space application. In the given example we simply pass 0 and let the kernel take care of it.

The declarations needed, our rt-thread a shared memory object. Offset here is 0 passed as MEMORY_OFFSET.


pthread_t thread;

struct shared_mem_struct
{
  int some_int;
  char ready;
};

int memfd;
#define MEMORY_OFFSET 0
struct shared_mem_struct* shared_mem;

This is a sample cleanup handler - kind of useless in this form, but intended as an example - on rmmod of this module you get the printk message in the kernels ring buffer.


void
cleanup(void *arg)
{
  printk("Cleanup handler called\n");
}

Nothing special about the rt-thread in this case - its simply a periodic thread that will printk the shared object. Note the cleanup handler called on exit of the while loop, this section of code is never reached - but cleanup handler push/pops must be balanced otherwise gcc is not happy. The cleanup handler is not called by the pthread_cleanup_pop though but by pthread_delete_np which checks for available cleanup handlers. The cleanup handler does nothing here - but it is an important means to make sure that a rt-thread can exit safely without any synchronization object held in an inappropriate state - so if you shared object was in use for synchronization make sure the cleanup handler puts it in a state where any other threads/processes can continue safely.


void * start_routine(void *arg)
{
  struct sched_param p;
  p . sched_priority = 1;
  pthread_setschedparam (
    pthread_self(), 
    SCHED_FIFO,
    &p);

  pthread_make_periodic_np (
    pthread_self(),
    gethrtime(), 
    500000000);
  pthread_cleanup_push(cleanup,0);

  while (1) {
    pthread_wait_np ();
    rtl_printf("shared mem=%d\n",
      shared_mem->some_int);
  }
  pthread_cleanup_pop(0);
  return 0;
}

Init module opens /dev/mem and then mmaps the shared memory object, if the mmap fails we must close the file descriptor explicitly (all resources you requested in init_module need to be released by you).


int 
init_module(void) 
{
  int ret;

  memfd = open("/dev/mem", O_RDWR);
  if (memfd){
    shared_mem = (struct \
      shared_mem_struct*) mmap(0,
      sizeof(struct shared_mem_struct),
      PROT_READ | PROT_WRITE, 
      MAP_FILE | MAP_SHARED, 
      memfd, 
      MEMORY_OFFSET);
    if(shared_mem != NULL){    
      printk("Dev mem available\n");
    }
    else{
      printk("Failed to map memory\n");
      close (memfd);
      return -1;
    }
  }
  else{
    printk("rt-shm - open failed\n");
    return -1;
  }
  ret=pthread_create (&thread,
    NULL,
    start_routine,
    0);
  return ret;
}

Cleanup is only deleting the rt-thread and closing the device.


void cleanup_module(void) {
  pthread_delete_np (thread);
  close(memfd);
}

The user space application is not fundamentally different as with any other device mmapped. Open /dev/mem, mmap it, casting it to the shared object, write to it and it shows up in the printk of the periodic thread. Note that this method of using offset 0 is quite restricted as all mmaps of offset 0 see the same region - but for many problems this is sufficient.


int main()
{
  char input[40];
  char stop=0;

  memfd = open("/dev/mem", O_RDWR);
  if (memfd){
    shared_mem = (struct 
      shared_mem_struct*) mmap(0,
        sizeof(struct shared_mem_struct),
        PROT_READ | PROT_WRITE, 
      MAP_FILE | MAP_SHARED, 
      memfd, 
      MEMORY_OFFSET);
    if(shared_mem != NULL){
      printf("enter # or <quit>\n");
      do{
        scanf("%s", input);
        shared_mem->some_int = atoi(
          input);
        shared_mem->ready = 1;
      }while (strcmp("quit",input));
    }
    else{
      printf("Failed to map memory\n");
      close (memfd);
      exit(-1);
    }
  }
  else{
    printf("Failed to open /dev/mem\n");
    exit(-1);
  }
   munmap(shared_mem);
  close(memfd);
  return 0;
}


next up previous
Next: Using reserved 'raw'-memory Up: Sharing Memory betweeen kerne, Previous: Simple mmap driver
Der Herr Hofrat
2003-01-06