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