]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/mem/Segment.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ipc / mem / Segment.cc
1 /*
2 * $Id$
3 *
4 * DEBUG: section 54 Interprocess Communication
5 *
6 */
7
8 #include "config.h"
9 #include "base/TextException.h"
10 #include "compat/shm.h"
11 #include "ipc/mem/Segment.h"
12 #include "protos.h"
13
14 #include <fcntl.h>
15 #include <sys/mman.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19
20 Ipc::Mem::Segment::Segment(const char *const id):
21 theName(GenerateName(id)), theFD(-1), theMem(NULL),
22 theSize(0), theReserved(0), doUnlink(false)
23 {
24 }
25
26 Ipc::Mem::Segment::~Segment()
27 {
28 if (theFD >= 0) {
29 detach();
30 if (close(theFD) != 0)
31 debugs(54, 5, HERE << "close " << theName << ": " << xstrerror());
32 }
33 if (doUnlink)
34 unlink();
35 }
36
37 bool
38 Ipc::Mem::Segment::Enabled()
39 {
40 #if HAVE_SHM
41 return true;
42 #else
43 return false;
44 #endif
45 }
46
47 void
48 Ipc::Mem::Segment::create(const off_t aSize)
49 {
50 assert(aSize > 0);
51 assert(theFD < 0);
52
53 theFD = shm_open(theName.termedBuf(), O_CREAT | O_RDWR | O_TRUNC,
54 S_IRUSR | S_IWUSR);
55 if (theFD < 0) {
56 debugs(54, 5, HERE << "shm_open " << theName << ": " << xstrerror());
57 fatal("Ipc::Mem::Segment::create failed to shm_open");
58 }
59
60 if (ftruncate(theFD, aSize)) {
61 debugs(54, 5, HERE << "ftruncate " << theName << ": " << xstrerror());
62 fatal("Ipc::Mem::Segment::create failed to ftruncate");
63 }
64
65 assert(statSize("Ipc::Mem::Segment::create") == aSize); // paranoid
66
67 theSize = aSize;
68 theReserved = 0;
69 doUnlink = true;
70
71 debugs(54, 3, HERE << "created " << theName << " segment: " << theSize);
72
73 attach();
74 }
75
76 void
77 Ipc::Mem::Segment::open()
78 {
79 assert(theFD < 0);
80
81 theFD = shm_open(theName.termedBuf(), O_RDWR, 0);
82 if (theFD < 0) {
83 debugs(54, 5, HERE << "shm_open " << theName << ": " << xstrerror());
84 String s = "Ipc::Mem::Segment::open failed to shm_open ";
85 s.append(theName);
86 fatal(s.termedBuf());
87 }
88
89 theSize = statSize("Ipc::Mem::Segment::open");
90
91 debugs(54, 3, HERE << "opened " << theName << " segment: " << theSize);
92
93 attach();
94 }
95
96 /// Map the shared memory segment to the process memory space.
97 void
98 Ipc::Mem::Segment::attach()
99 {
100 assert(theFD >= 0);
101 assert(!theMem);
102
103 // mmap() accepts size_t for the size; we give it off_t which might
104 // be bigger; assert overflows until we support multiple mmap()s?
105 assert(theSize == static_cast<off_t>(static_cast<size_t>(theSize)));
106
107 void *const p =
108 mmap(NULL, theSize, PROT_READ | PROT_WRITE, MAP_SHARED, theFD, 0);
109 if (p == MAP_FAILED) {
110 debugs(54, 5, HERE << "mmap " << theName << ": " << xstrerror());
111 fatal("Ipc::Mem::Segment::attach failed to mmap");
112 }
113 theMem = p;
114 }
115
116 /// Unmap the shared memory segment from the process memory space.
117 void
118 Ipc::Mem::Segment::detach()
119 {
120 if (!theMem)
121 return;
122
123 if (munmap(theMem, theSize)) {
124 debugs(54, 5, HERE << "munmap " << theName << ": " << xstrerror());
125 fatal("Ipc::Mem::Segment::detach failed to munmap");
126 }
127 theMem = 0;
128 }
129
130 void
131 Ipc::Mem::Segment::unlink()
132 {
133 if (shm_unlink(theName.termedBuf()) != 0)
134 debugs(54, 5, HERE << "shm_unlink(" << theName << "): " << xstrerror());
135 else
136 debugs(54, 3, HERE << "unlinked " << theName << " segment");
137 }
138
139 void *
140 Ipc::Mem::Segment::reserve(size_t chunkSize)
141 {
142 Must(theMem);
143 // check for overflows
144 // chunkSize >= 0 may result in warnings on systems where off_t is unsigned
145 assert(!chunkSize || static_cast<off_t>(chunkSize) > 0);
146 assert(static_cast<off_t>(chunkSize) <= theSize);
147 assert(theReserved <= theSize - static_cast<off_t>(chunkSize));
148 void *result = reinterpret_cast<char*>(theMem) + theReserved;
149 theReserved += chunkSize;
150 return result;
151 }
152
153 /// determines the size of the underlying "file"
154 off_t
155 Ipc::Mem::Segment::statSize(const char *context) const
156 {
157 Must(theFD >= 0);
158
159 struct stat s;
160 memset(&s, 0, sizeof(s));
161
162 if (fstat(theFD, &s) != 0) {
163 debugs(54, 5, HERE << "fstat " << theName << ": " << xstrerror());
164 String s = context;
165 s.append("failed to fstat(2) ");
166 s.append(theName);
167 fatal(s.termedBuf());
168 }
169
170 return s.st_size;
171 }
172
173 /// Generate name for shared memory segment. Replaces all slashes with dots.
174 String
175 Ipc::Mem::Segment::GenerateName(const char *id)
176 {
177 String name("/squid-");
178 for (const char *slash = strchr(id, '/'); slash; slash = strchr(id, '/')) {
179 if (id != slash) {
180 name.append(id, slash - id);
181 name.append('.');
182 }
183 id = slash + 1;
184 }
185 name.append(id);
186 return name;
187 }