Last active
February 27, 2023 23:59
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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