Created
June 25, 2015 10:22
-
-
Save trissylegs/2b1c4849bd3a046df249 to your computer and use it in GitHub Desktop.
Demonstration of shared memory using C and Rust
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
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <unistd.h> | |
#include <sys/mman.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
void fatal(const char *msg) { | |
perror(msg); | |
exit(EXIT_FAILURE); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
// If we're the serv we write to the shm | |
bool is_serv = 0; | |
// The name of the shm. | |
const char *name = "/test_shm"; | |
// How big the shm is. | |
int mem_size; | |
printf("Attempt to open existing server.\n"); | |
int fd = shm_open(name, O_RDWR, 0); | |
if (fd == -1) { | |
// Page size. | |
mem_size = 4096; | |
if (errno != ENOENT) | |
fatal("Failed to open shared memory object"); | |
printf("Shared memory object does not exists, " | |
"making new one\n"); | |
is_serv = true; | |
fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, 0600); | |
if (fd == -1) | |
fatal("Failed to create shared memory object"); | |
// Resize the shm. | |
ftruncate(fd, mem_size); | |
} else { | |
struct stat file_stat; | |
fstat(fd, &file_stat); | |
mem_size = file_stat.st_size; | |
} | |
char *data = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, | |
MAP_SHARED, fd, 0); | |
if (data == MAP_FAILED) | |
fatal("Failed to map shm"); | |
close(fd); | |
volatile long *num = (long*) data; | |
if (is_serv) { | |
memset(data, 0, mem_size); | |
while (1) { | |
sleep(1); | |
// Server should only print even values; | |
long old_val = *num; | |
printf("current value %ld\n", old_val); | |
if (old_val % 2 == 0) | |
continue; | |
long new_val = old_val + 1; | |
if (__sync_bool_compare_and_swap(num, old_val, new_val)) | |
printf("updated to %ld\n", new_val); | |
} | |
} else { | |
while (1) { | |
sleep(1); | |
// Client should only print odd values | |
long old_val = *num; | |
if (old_val % 2 == 1) | |
continue; | |
long new_val = old_val + 1; | |
if (__sync_bool_compare_and_swap(num, old_val, new_val)) | |
printf("client: %ld\n", new_val); | |
} | |
} | |
return 0; | |
} |
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
/ / / | |
// !!NOTE!! This is out of date | |
// Some of these crates no loger exist | |
extern crate libc; | |
extern crate core; | |
extern crate native; | |
extern crate rustrt; | |
use core::atomics::{ AtomicInt, Relaxed }; | |
use libc::funcs::posix88::mman::{shm_open}; | |
// use libc::types::os::arch::posix88; | |
use libc::consts::os::posix88; | |
use libc::types::os::arch::posix88::{mode_t}; | |
use rustrt::rtio::FileStat; | |
use std::io::{ IoResult, | |
IoError }; | |
use std::os::{ MemoryMap, | |
MapReadable, | |
MapWritable, | |
MapFd, | |
MapNonStandardFlags }; | |
struct SharedMemory { | |
path: String, | |
fd: FildDesc, | |
mmap: MemoryMap, | |
unlink_on_drop: bool, | |
} | |
static mode_t USER_READ = 0o400 | |
static mode_t USER_WRITE = 0o200 | |
static mode_t USER_EXEC = 0o100 | |
static mode_t USER_ALL = 0o700 | |
static mode_t USER_READ_WRITE = USER_READ | USER_WRITE; | |
impl SharedMemory { | |
/// Open an existing POSIX shm. | |
/// | |
/// The SharedMemory object represents a memory mapping of a POSIX | |
/// shared memory object. A tmpfs is special reserved (can be | |
/// viewed in `/dev/shm` in Linux). The maping is sized to be the | |
/// full size of the memory object at creation time. | |
/// | |
/// For more information see `shm_open(3)` | |
/// | |
/// This is **blocking** operation. | |
pub fn open(name: String) -> IoResult<SharedMemory> { | |
// C library call. Use shm_open to get a fd to a shm object. | |
let fd_raw = name.with_c_str(|c_name: *const i8| { | |
unsafe { shm_open(c_name, posix88::O_RDWR, 0) } | |
}); | |
// Failure to open shm, return errno as IoError | |
if fd_raw == -1 { | |
return Err(IoError::last_error()); | |
} | |
// Oxidise the fd. | |
let mut fd = native::io::file::FileDesc::new(fd_raw, true); | |
// Get shm info. | |
let fstat = try!(fd.fstat()); | |
// mmap the shm | |
let map = try!(MemoryMap::new(fstat.size as uint, | |
[MapFd(fd.fd()), | |
MapReadable, MapWritable, | |
MapNonStandardFlags(posix88::MAP_SHARED)] | |
)); | |
// Success! | |
Ok(SharedMemory { | |
path: name, | |
fd: fd, | |
mmap: MemoryMap, | |
unlink_on_drop: false, // Client is opening an existing page. | |
}) | |
} | |
/// Create a new posix shared memory object. | |
/// | |
/// This will create a posix shared memory object with | |
pub fn create(name: String, size: uint) -> IoResult { | |
let c_name = name.to_c_str(); | |
let fd_raw = c_name.with_ref(|c_name: *const i8| { | |
unsafe { shm_open(c_name, posix88::O_RDWR | posix88::O_CREAT | posix88::O_EXCL, | |
USER_READ_WRITE) } | |
}); | |
if fd_raw == -1 { return Err(IoError::last_error()); } | |
let mut fd = nativ::io::file::FileDesc::new(fd_raw, true); | |
set_up(fd, Some(size)).map_err(|err| { | |
unsafe { shm_unlink(c_name.as_ptr); } | |
err | |
}) | |
} | |
/// Create a new shared memory object | |
pub fn name<'a>(&'a self) -> &'a str { self.name.as_slice() } | |
} | |
fn set_up(fd: FileDesc, resize: Option<uint>) -> IoResult { | |
try!(fd.truncate(size)); | |
let map = try!(MemoryMap::new(fstat.size as uint, | |
[MapFd(fd.fd()), | |
MapReadable, MapWriteable, | |
MapNonStandardFlags(posix88::MAP_SHARED)] | |
)); | |
Ok(SharedMemory { | |
path: name, | |
fd: fd, | |
mmap: MemoryMap, | |
unlink_on_drop: true, // We need to unlink it so the object is destroyed once unused. | |
}) | |
} | |
impl Drop for SharedMemory { | |
fn drop(&mut self) { | |
if self.unlink_on_drop { | |
self.name.to_c_str().with_ref(|c_name: *const i8| { | |
if unsafe { shm_unlink(c_name) < 0 } { | |
fail!("shared memory unlink failed: {}", IoError::last_error()); | |
} | |
}) | |
} | |
} | |
} | |
fn get_size<F: std::rt::rtio::RtioFileStream>(fd: &mut F) -> u64 { | |
match fd.fstat() { | |
Err(err) => fail!("Failed to fstat: {}", err), | |
Ok(stat) => stat.size, | |
} | |
} | |
// Link the Posix runtime library. | |
#[link(name = "rt")] | |
extern {} | |
fn main() { | |
print!("Enter shm name: "); | |
let line = io::stdin.read_line().unwrap(); | |
chomp(line); | |
let shm = match SharedMemory::open(line) { | |
Ok(shm) => shm, | |
Err(err) if err.kind == FileNotFound => SharedMemory::create(line).unwrap(), | |
Err(err) => fail!("Failed to open shm: {}", err), | |
} | |
// let atomic_data : &AtomicInt; | |
// unsafe { | |
// let data: *int = map.data as *int; | |
// atomic_data = std::mem::transmute(data); | |
// } | |
// let mut timer = std::io::timer::Timer::new().unwrap(); | |
// let periodic = timer.periodic(1000); | |
// loop { | |
// periodic.recv(); | |
// let old_val = atomic_data.load(Relaxed); | |
// println!("current value = {}", old_val); | |
// if old_val % 2 != 1 { | |
// let new_val = old_val + 1; | |
// atomic_data.compare_and_swap(old_val, new_val, | |
// Relaxed); | |
// } | |
// } | |
} | |
fn chomp<'a>(str: &'a mut String) { | |
while match str.pop_char() { | |
None => false, | |
Some(ch) if !ch.is_whitespace() => { str.push_char(ch); false } | |
Some(..) => { str.push_char(ch), true } | |
} | |
{ /* do while loop */ } | |
} | |
fn sys_fatal(msg: &str) -> ! { | |
let err = std::io::IoError::last_error(); | |
fail!("{}: {}", msg, err); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment