1 /*
2 * shmem.h
3 *
4 * Created on: Aug 13, 2009
5 * Author: Ben Langmead
6 */
7
8 #ifndef SHMEM_H_
9 #define SHMEM_H_
10
11 #ifdef BOWTIE_SHARED_MEM
12
13 #include <iostream>
14 #include <string>
15 #include <sys/shm.h>
16 #include <unistd.h>
17 #include <sys/shm.h>
18 #include <errno.h>
19 #include <stdint.h>
20 #include <stdexcept>
21 #include "str_util.h"
22 #include "btypes.h"
23
24 extern void notifySharedMem(void *mem, size_t len);
25
26 extern void waitSharedMem(void *mem, size_t len);
27
28 #define ALLOC_SHARED_U allocSharedMem<TIndexOffU>
29 #define ALLOC_SHARED_U8 allocSharedMem<uint8_t>
30 #define ALLOC_SHARED_U32 allocSharedMem<uint32_t>
31 #define FREE_SHARED shmdt
32 #define NOTIFY_SHARED notifySharedMem
33 #define WAIT_SHARED waitSharedMem
34
35 #define SHMEM_UNINIT 0xafba4242
36 #define SHMEM_INIT 0xffaa6161
37
38 /**
39 * Tries to allocate a shared-memory chunk for a given file of a given size.
40 */
41 template <typename T>
allocSharedMem(std::string fname,size_t len,T ** dst,const char * memName,bool verbose)42 bool allocSharedMem(std::string fname,
43 size_t len,
44 T ** dst,
45 const char *memName,
46 bool verbose)
47 {
48 using namespace std;
49 int shmid = -1;
50 // Calculate key given string
51 key_t key = (key_t)hash_string(fname);
52 shmid_ds ds;
53 int ret;
54 // Reserve 4 bytes at the end for silly synchronization
55 size_t shmemLen = len + 4;
56 if(verbose) {
57 cerr << "Reading " << len << "+4 bytes into shared memory for " << memName << endl;
58 }
59 T *ptr = NULL;
60 while(true) {
61 // Create the shrared-memory block
62 if((shmid = shmget(key, shmemLen, IPC_CREAT | 0666)) < 0) {
63 if(errno == ENOMEM) {
64 cerr << "Out of memory allocating shared area " << memName << endl;
65 } else if(errno == EACCES) {
66 cerr << "EACCES" << endl;
67 } else if(errno == EEXIST) {
68 cerr << "EEXIST" << endl;
69 } else if(errno == EINVAL) {
70 cerr << "Warning: shared-memory chunk's segment size doesn't match expected size (" << (shmemLen) << ")" << endl
71 << "Deleting old shared memory block and trying again." << endl;
72 shmid = shmget(key, 0, 0);
73 if((ret = shmctl(shmid, IPC_RMID, &ds)) < 0) {
74 cerr << "shmctl returned " << ret
75 << " for IPC_RMID, errno is " << errno
76 << ", shmid is " << shmid << endl;
77 throw 1;
78 } else {
79 cerr << "Deleted shared mem chunk with shmid " << shmid << endl;
80 }
81 continue;
82 } else if(errno == ENOENT) {
83 cerr << "ENOENT" << endl;
84 } else if(errno == ENOSPC) {
85 cerr << "ENOSPC" << endl;
86 } else {
87 cerr << "shmget returned " << shmid << " for and errno is " << errno << endl;
88 }
89 throw 1;
90 }
91 ptr = (T*)shmat(shmid, 0, 0);
92 if(ptr == (void*)-1) {
93 cerr << "Failed to attach " << memName << " to shared memory with shmat()." << endl;
94 throw 1;
95 }
96 if(ptr == NULL) {
97 cerr << memName << " pointer returned by shmat() was NULL." << endl;
98 throw 1;
99 }
100 // Did I create it, or did I just attach to one created by
101 // another process?
102 if((ret = shmctl(shmid, IPC_STAT, &ds)) < 0) {
103 cerr << "shmctl returned " << ret << " for IPC_STAT and errno is " << errno << endl;
104 throw 1;
105 }
106 if((size_t)ds.shm_segsz != shmemLen) {
107 cerr << "Warning: shared-memory chunk's segment size (" << ds.shm_segsz
108 << ") doesn't match expected size (" << shmemLen << ")" << endl
109 << "Deleting old shared memory block and trying again." << endl;
110 if((ret = shmctl(shmid, IPC_RMID, &ds)) < 0) {
111 cerr << "shmctl returned " << ret << " for IPC_RMID and errno is " << errno << endl;
112 throw 1;
113 }
114 } else {
115 break;
116 }
117 } // while(true)
118 *dst = ptr;
119 bool initid = (((volatile uint32_t*)((char*)ptr + len))[0] == SHMEM_INIT);
120 if(ds.shm_cpid == getpid() && !initid) {
121 if(verbose) {
122 cerr << " I (pid = " << getpid() << ") created the "
123 << "shared memory for " << memName << endl;
124 }
125 // Set this value just off the end of the chunk to
126 // indicate that the data hasn't been read yet.
127 ((volatile uint32_t*)((char*)ptr + len))[0] = SHMEM_UNINIT;
128 return true;
129 } else {
130 if(verbose) {
131 cerr << " I (pid = " << getpid()
132 << ") did not create the shared memory for "
133 << memName << ". Pid " << ds.shm_cpid << " did." << endl;
134 }
135 return false;
136 }
137 }
138
139 #else
140
141 #define ALLOC_SHARED_U(...) 0
142 #define ALLOC_SHARED_U8(...) 0
143 #define ALLOC_SHARED_U32(...) 0
144 #define FREE_SHARED(...)
145 #define NOTIFY_SHARED(...)
146 #define WAIT_SHARED(...)
147
148 #endif /*BOWTIE_SHARED_MEM*/
149
150 #endif /* SHMEM_H_ */
151