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, 1 week ago) by greg
Branch: MAIN
Log Message:
feat(rxcontrib): First compiled version of rxcontrib tool to test new C++ classes

File Contents

# User Rev Content
1 greg 2.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     }