Skip to content

Instantly share code, notes, and snippets.

@trissylegs
Created June 25, 2015 10:22
Show Gist options
  • Save trissylegs/2b1c4849bd3a046df249 to your computer and use it in GitHub Desktop.
Save trissylegs/2b1c4849bd3a046df249 to your computer and use it in GitHub Desktop.
Demonstration of shared memory using C and Rust
#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;
}
/ / /
// !!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