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;
}