Skip to content

Instantly share code, notes, and snippets.

@przhu
Last active February 27, 2023 23:59
Show Gist options
  • Save przhu/3481836 to your computer and use it in GitHub Desktop.
Save przhu/3481836 to your computer and use it in GitHub Desktop.
attachment of post: 2012-08-26-sharing-memory-using-mach-part-of-os-x.md
/*
Sample Code, (C) PrZhu 2012
Redistribution this sample code and/or modified version is permitted provided that
this notice is preserved.
*/
/*
mach_make_memory_entry, vm_map
can be used to set up shared memory, which is shared virtual memory
the memory_entry is represented in mach_port_t, you know.
(vm_inherit can share memory to child, of course)
I'm not sure what if the shared memory swap out...
*/
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <inttypes.h>
#include <servers/bootstrap.h>
/*
since vm_* are defined as long in 64bit, int in 32bit,
mach_vm_* always defined as 64bit. Use mach_vm_* is preferred
(osfmk/vm/vm_user.c)
However the suitable make_memory_entry for mach_vm_* is
mach_make_memory_entry_64 or _mach_make_memory_entry
Naming problem, you know.
At the end of <mach/mach_vm.defs>:
* The following legacy interfaces are provides as macro wrappers to the new
* interfaces. You should strive to use the new ones instead:
*
* vm_map() -
* use mach_vm_map() or vm_map_64()
* vm_region() -
* use mach_vm_region() or vm_region_64()
* mach_make_memory_entry() -
* use mach_vm_make_memory_entry() or mach_make_memory_entry_64()
mach_vm_make_memory_entry is not available yet
According to the definition of make_memory_entry() in <mach/mach_vm.defs>,
``THIS INTERFACE IS STILL EVOLVING''
*/
#define TRUE 1
#define FALSE 0
#define HANDLE_MACH_ERROR(STR, RET) \
do { \
mach_error(STR, RET); \
exit(EXIT_FAILURE); \
} while(0)
#define HANDLE_SYS_ERROR(STR) \
do {\
perror(STR);\
exit(EXIT_FAILURE); \
} while(0)
#define CHECK_SYS_RESULT(STR, RET)\
do {\
if (RET < 0) {\
HANDLE_SYS_ERROR(STR); \
}\
} while(0)
#define CHECK_MACH_RESULT(STR, RET)\
do {\
if (RET != KERN_SUCCESS) {\
HANDLE_MACH_ERROR(STR, RET); \
}\
} while(0)
int main()
{
mach_vm_address_t address = (mach_vm_address_t)main;
kern_return_t ret;
mach_vm_size_t size = 65536;
mach_vm_size_t i;
unsigned char *u;
// mem_entry_name_port_t
mach_port_t shm;
semaphore_t sem;
ret = mach_vm_allocate(mach_task_self(), &address, size, TRUE);
CHECK_MACH_RESULT("mach_vm_allocate:", ret);
fprintf(stdout, "pointer at: %#"PRIx64"\n", address);
u = (unsigned char *)address;
for (i = 0; i < size; ++i) {
u[i] = i % 128;
}
for (i = 0; i < size; ++i) {
if (u[i] != i % 128) {
fprintf(stderr, "ERROR at: %"PRIu64"\n", i);
}
}
ret = mach_make_memory_entry_64(mach_task_self(), &size, address, VM_PROT_READ|VM_PROT_WRITE,
&shm, MACH_PORT_NULL);
CHECK_MACH_RESULT("mach_make_memory_entry_64", ret);
/*
ret = mach_vm_inherit(mach_task_self(), address, size, VM_INHERIT_NONE);
CHECK_MACH_RESULT("mach_vm_inherit", ret);
*/
ret = semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, 0);
CHECK_MACH_RESULT("semaphore_create", ret);
/*
for real app, bootstrap_subset and related methods and then mach_msg()
should be employed
*/
bootstrap_register(bootstrap_port, "!XSHM", shm);
bootstrap_register(bootstrap_port, "!XSEM", sem);
ret = fork();
if (ret < 0) {
HANDLE_SYS_ERROR("fork");
}
if (ret == 0) {//child
mach_vm_address_t map_address = (mach_vm_address_t)main;
unsigned char *v;
bootstrap_look_up(bootstrap_port, "!XSHM", &shm);
bootstrap_look_up(bootstrap_port, "!XSEM", &sem);
ret = mach_vm_map(mach_task_self(), &map_address, size, 0, TRUE, shm,
0, FALSE, VM_PROT_READ|VM_PROT_WRITE, VM_PROT_READ|VM_PROT_WRITE,
VM_INHERIT_NONE);
if (ret != KERN_SUCCESS) {
semaphore_signal(sem);
HANDLE_MACH_ERROR("mach_vm_map", ret);
}
u = (unsigned char *)address;
v = (unsigned char *)map_address;
/* u, v should be the same now, u is forked, v is shared mapped */
for (i = 0; i < size; ++i) {
if (u[i] != v[i]) {
fprintf(stderr, "map verification error, first failure index: %"PRIu64"[v_i = %#x]\n", i, v[i]);
break;
}
}
/* write to v */
for (i = 0; i < size; ++i) {
v[i] = (i % 128 == 0 ? 128 : (size - i) % 128);
}
for (i = 0; i < size; ++i) {
if (u[i] + v[i] != 128) {
fprintf(stderr, "write verification error, first failure index: %"PRIu64"[v_i = %#x]\n", i, v[i]);
break;
}
}
semaphore_signal(sem);
semaphore_wait(sem);
} else {//parent
semaphore_wait(sem);
/* verify sharing semantics */
for (i = 0; i < size; ++i) {
if (u[i] + i % 128 != 128) {
fprintf(stderr, "shared verification error, first failure index: %"PRIu64"[u_i = %#x]\n", i, u[i]);
break;
}
}
fgetc(stdin);
semaphore_signal(sem);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment