diff --git a/file-intro/pstack.c b/file-intro/pstack.c index b8e4f58..8aafb08 100644 --- a/file-intro/pstack.c +++ b/file-intro/pstack.c @@ -1,70 +1,74 @@ -// Persistent stack example of how mmap() naturally creates a software abstraction of persistent memory. -// Author: Terence Kelly - -// Note: Use 'dd' to make the initial (empty) image, e.g., -// dd if=/dev/zero of=ps.img bs=32 count=1 -// makes a 32-byte empty file (the first integer being the size of the stack, -// the remaining integers being values) - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int open_or_die(const char *path, int oflag) { - int fd = open(path, oflag); - assert(fd > 0); - return fd; -} - -int fstat_or_die(int fildes, struct stat *buf) { - int rc = fstat(fildes, buf); - assert(rc == 0); - return rc; -} - -void *mmap_or_die(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { - void *p = mmap(addr, len, prot, flags, fd, offset); - assert(p != MAP_FAILED); - return p; -} - -typedef struct { - size_t n; - int stack[]; // zero-length per C99 -} pstack_t; - -int main(int argc, char *argv[]) { - int fd, rc; - struct stat s; - size_t file_size; - pstack_t *p; - - fd = open_or_die("ps.img", O_RDWR); - rc = fstat_or_die(fd, &s); - - file_size = (size_t) s.st_size; - assert(file_size % sizeof(int) == 0); - - p = mmap_or_die(NULL, file_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - - for (int i = 1; i < argc; i++) - if (strcmp(argv[i], "pop") == 0) { - if (p->n > 0) // stack not empty - printf("%d\n", p->stack[--p->n]); - else - printf("stack empty\n"); - } else - if (sizeof(pstack_t) + p->n * sizeof(int) < file_size) // stack not full - p->stack[p->n++] = atoi(argv[i]); - else - printf("stack full: %d not added\n", atoi(argv[i])); - - close(fd); - return 0; -} +// Persistent stack example of how mmap() naturally creates a software abstraction of persistent memory. +// Author: Terence Kelly +// tpkelly @ { acm.org, cs.princeton.edu, eecs.umich.edu } + +// Note: Use 'truncate' to make the initial (empty) backing file, +// whose size should be a multiple of the system page size: +// +// prompt> getconf PAGESIZE +// 4096 +// prompt> truncate -s 4096 ps.img +// +// makes a 4096-byte empty file. The first sizeof(size_t) bytes will +// be interprted as the number of items on the stack; the remainder +// of the file will contain the integers contained in the stack. +// Now you can run the program: +// +// prompt> ./pstack 7 13 47 pop +// 47 +// prompt> ./pstack pop pop 99 +// 13 +// 7 +// prompt> ./pstack pop +// 99 +// +// Notice that items push'd in one invocation of the program persist +// until the next invocation: The stack is persistent. +// +// You can use hexdump to examine the contents of the backing file: +// +// prompt> hexdump ps.img + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + size_t n; + int stack[]; // zero-length per C99 +} pstack_t; + +int main(int argc, char *argv[]) { + int fd, rc; + struct stat s; + size_t file_size; + pstack_t *p; + + fd = open("ps.img", O_RDWR); + assert(fd > -1); + rc = fstat(fd, &s); + assert(rc == 0); + + file_size = (size_t) s.st_size; + assert(file_size >= sizeof(pstack_t) && file_size % sizeof(int) == 0); + + p = (pstack_t *) mmap(NULL, file_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + assert(p != MAP_FAILED); + + for (int i = 1; i < argc; i++) + if (strcmp(argv[i], "pop") == 0) { + if (p->n > 0) // stack not empty + printf("%d\n", p->stack[--p->n]); + } else { // pop + if (sizeof(pstack_t) + (1 + p->n) * sizeof(int) <= file_size) // stack not full + p->stack[p->n++] = atoi(argv[i]); + } + (void) close(fd); + return 0; +}