ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/RdataShareMap.cpp
Revision: 2.1
Committed: Tue Oct 29 00:36:54 2024 UTC (6 months ago) by greg
Branch: MAIN
Log Message:
feat(rxcontrib): First compiled version of rxcontrib tool to test new C++ classes

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
4 /*
5 * RdataShareMap.cpp
6 *
7 * Shared data using memory-mapped file
8 *
9 * Created by Greg Ward on 10/14/2024
10 */
11
12 #include "rtio.h"
13 #include "rterror.h"
14 #include "RdataShare.h"
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #include <sys/mman.h>
18
19 // Create memory-mapped file object
20 RdataShareMap::RdataShareMap(const char *name, int flags, size_t siz)
21 {
22 mmorg = NULL;
23 bufCount = 0;
24
25 if (!(flags & (RDSread|RDSwrite))) {
26 error(CONSISTENCY, "RdataShareMap() flags must include RDSread or RDSwrite");
27 return;
28 }
29 if (name && !*name) name = NULL;
30 if (!name && !siz | ((flags & (RDSextend|RDSread|RDSwrite)) !=
31 (RDSextend|RDSread|RDSwrite))) {
32 error(CONSISTENCY, "anonymous memory map must be read/write");
33 return;
34 }
35 if ((flags & (RDSextend|RDSwrite)) == RDSextend) {
36 error(CONSISTENCY, "bad RDSextend in RdataShareMap()");
37 return;
38 }
39 int mmprot = PROT_NONE;
40 int oflags = 0;
41 switch (flags & (RDSread|RDSwrite)) {
42 case RDSread|RDSwrite:
43 mmprot |= PROT_READ|PROT_WRITE;
44 oflags |= O_RDWR;
45 break;
46 case RDSread:
47 mmprot |= PROT_READ;
48 oflags |= O_RDONLY;
49 break;
50 case RDSwrite:
51 mmprot |= PROT_WRITE;
52 oflags |= O_WRONLY;
53 break;
54 }
55 int fd = -1;
56 if (name) { // opening a shared file
57 if (flags & RDSexcl) oflags |= O_CREAT|O_EXCL;
58 else if (flags & RDSextend && !siz) oflags |= O_TRUNC;
59 fd = open(name, oflags, 0666);
60 if (fd < 0) {
61 sprintf(errmsg, "cannot open '%s'", name);
62 error(SYSTEM, errmsg);
63 return;
64 }
65 if (!(flags & RDSextend)) {
66 struct stat sbuf;
67 if (flags & RDSexcl)
68 siz = 0;
69 else if (fstat(fd, &sbuf) >= 0)
70 siz = sbuf.st_size;
71 else {
72 sprintf(errmsg, "cannot stat '%s'", chName);
73 error(SYSTEM, errmsg);
74 close(fd);
75 return;
76 }
77 } else if (siz && ftruncate(fd, siz) < 0) {
78 sprintf(errmsg, "cannot resize '%s'", name);
79 error(SYSTEM, errmsg);
80 close(fd);
81 return;
82 }
83 }
84 mmorg = (void *)mmap(NULL, siz, mmprot,
85 MAP_SHARED|(name ? MAP_FILE : MAP_ANON), fd, 0);
86 close(fd);
87 if (mmorg == MAP_FAILED) {
88 if (name)
89 sprintf(errmsg, "cannot map '%s' to memory", name);
90 else
91 sprintf(errmsg, "cannot map anonymous map of %ld KBytes",
92 long(siz/1024));
93 error(SYSTEM, errmsg);
94 mmorg = NULL;
95 return;
96 }
97 osiz = siz;
98 if (name) chName = savqstr(name);
99 mode = flags;
100 }
101
102 RdataShareMap::~RdataShareMap()
103 {
104 if (mmorg) munmap(mmorg, osiz);
105 }
106
107 // Attempt to extend or shrink object (adjust if 0)
108 size_t
109 RdataShareMap::Resize(size_t new_siz)
110 {
111 if (!mmorg)
112 return 0;
113 if (new_siz > 0) {
114 if (new_siz == osiz)
115 return osiz;
116 if (!(mode & RDSwrite)) {
117 error(CONSISTENCY, "cannot resize read-only map");
118 return 0;
119 }
120 }
121 if (bufCount > 0) {
122 error(INTERNAL, "cannot resize while memory is checked out");
123 return 0;
124 }
125 if (!chName) {
126 if (!new_siz) // XXX should issue warning?
127 return osiz;
128 if (new_siz > osiz) {
129 error(INTERNAL, "cannot grow anonymous map");
130 return 0;
131 }
132 return osiz = new_siz; // just pretend we shrank
133 }
134 if (!new_siz) { // sync to current file length?
135 struct stat sbuf;
136 if (stat(chName, &sbuf) < 0) {
137 sprintf(errmsg, "cannot stat '%s'", chName);
138 error(SYSTEM, errmsg);
139 return 0;
140 }
141 if (sbuf.st_size <= osiz)
142 return osiz = sbuf.st_size;
143
144 new_siz = sbuf.st_size;
145 }
146 if (new_siz > osiz) { // need to extend & remap
147 int fd = open(chName, mode&RDSread ? O_RDWR : O_WRONLY);
148 if (fd < 0) {
149 sprintf(errmsg, "cannot reopen '%s'", chName);
150 error(SYSTEM, errmsg);
151 return 0;
152 }
153 if (ftruncate(fd, new_siz) < 0) {
154 sprintf(errmsg, "cannot grow '%s'", chName);
155 error(SYSTEM, errmsg);
156 close(fd);
157 return 0;
158 }
159 munmap(mmorg, osiz);
160 mmorg = mmap(NULL, new_siz,
161 mode&RDSread ? PROT_READ|PROT_WRITE : PROT_WRITE,
162 MAP_SHARED|MAP_FILE, fd, 0);
163 close(fd);
164 if (mmorg == MAP_FAILED) {
165 sprintf(errmsg, "mmap() failed on '%s'", chName);
166 error(SYSTEM, errmsg);
167 mmorg = NULL;
168 return osiz = 0;
169 }
170 } else if (truncate(chName, new_siz) < 0) {
171 sprintf(errmsg, "cannot truncate '%s'", chName);
172 return 0;
173 }
174 return osiz = new_siz;
175 }
176
177 // Get data buffer
178 void *
179 RdataShareMap::GetMemory(size_t offs, size_t len, int fl)
180 {
181 if (chName && fl & RDSextend) { // resize/extend?
182 if (offs + len > osiz ? !Resize(offs + len) : !Resize())
183 return NULL;
184 }
185 if (offs + len > osiz) {
186 if (chName)
187 sprintf(errmsg, "requested block of %lu bytes outside map '%s'",
188 (unsigned long)len, chName);
189 else
190 sprintf(errmsg, "requested block of %lu bytes outside %lu byte map",
191 (unsigned long)len, (unsigned long)osiz);
192 error(CONSISTENCY, errmsg);
193 return NULL;
194 }
195 ++bufCount;
196 return (char *)mmorg + offs;
197 }
198
199 // Return data buffer
200 bool
201 RdataShareMap::ReleaseMemory(void *dp, int fl)
202 {
203 if ((dp < mmorg) | ((char *)dp >= (char *)mmorg + osiz)) {
204 if (chName)
205 sprintf(errmsg, "returned block outside map '%s'", chName);
206 else
207 sprintf(errmsg, "returned block outside %lu byte map",
208 (unsigned long)osiz);
209 error(CONSISTENCY, errmsg);
210 return false;
211 }
212 bufCount -= (bufCount > 0);
213 return true;
214 }