ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/RdataShareFile.cpp
Revision: 2.2
Committed: Wed Oct 30 01:38:21 2024 UTC (6 months ago) by greg
Branch: MAIN
Changes since 2.1: +6 -6 lines
Log Message:
fix(rxcontrib): Fixes in file loading & process management

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: RdataShareFile.cpp,v 2.1 2024/10/29 00:36:54 greg Exp $";
3 #endif
4 /*
5 * RdataShareFile.cpp
6 *
7 * Shared data using a regular 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 <stdlib.h>
16 #include <unistd.h>
17 #include <sys/stat.h>
18
19 const char RDSnoname[] = "<unnamed_channel>";
20
21 RdataShare::~RdataShare()
22 {
23 freeqstr(chName);
24 }
25
26 // Struct needed for tracking allocated buffers
27 struct RDSbuffer {
28 RDSbuffer * next; // next in list
29 char * buf; // allocated buffer
30 size_t len; // buffer length
31 off_t pos; // offset in file
32
33 RDSbuffer(size_t nb, RDSbuffer *nxt = NULL);
34 ~RDSbuffer() {
35 delete next;
36 if (len > 0) free(buf);
37 }
38 /// Find buffer matching pointer
39 RDSbuffer * Find(void *p) {
40 RDSbuffer * bp = this;
41 while (p != (void *)bp->buf &&
42 (bp = bp->next) != NULL)
43 ;
44 return bp;
45 }
46 };
47
48 // Allocate an i/o buffer
49 RDSbuffer::RDSbuffer(size_t nb, RDSbuffer *nxt)
50 {
51 next = nxt;
52 buf = NULL;
53 pos = -1;
54 if ((len = nb) > 0) {
55 buf = (char *)malloc(nb);
56 if (!buf) {
57 sprintf(errmsg, "cannot allocate %lu-byte buffer",
58 (unsigned long)nb);
59 error(SYSTEM, errmsg);
60 len = 0;
61 return;
62 }
63 }
64 }
65
66 // Create memory-mapped file object
67 RdataShareFile::RdataShareFile(const char *name, int flags, size_t siz)
68 {
69 fd = -1;
70 blist = NULL;
71
72 if (!name || !*name) {
73 error(CONSISTENCY, "missing file name in RdataShareFile()");
74 return;
75 }
76 if (!(flags & (RDSread|RDSwrite))) {
77 error(CONSISTENCY, "RdataShareFile() flags must include RDSread or RDSwrite");
78 return;
79 }
80 if ((flags & (RDSextend|RDSwrite)) == RDSextend) {
81 error(CONSISTENCY, "bad RDSextend in RdataShareFile()");
82 return;
83 }
84 int oflags = O_CLOEXEC;
85 switch (flags & (RDSread|RDSwrite)) {
86 case RDSread|RDSwrite:
87 oflags |= O_RDWR|O_CREAT;
88 break;
89 case RDSwrite:
90 oflags |= O_WRONLY|O_CREAT;
91 break;
92 case RDSread:
93 oflags |= O_RDONLY;
94 break;
95 }
96 if (flags & RDSexcl) oflags |= O_EXCL;
97 else if (flags & RDSextend && !siz) oflags |= O_TRUNC;
98 fd = open(name, oflags, 0666);
99 if (fd < 0) {
100 sprintf(errmsg, "cannot open '%s'", name);
101 error(SYSTEM, errmsg);
102 return;
103 }
104 if (!(flags & RDSextend)) {
105 struct stat sbuf;
106 if (flags & RDSexcl)
107 siz = 0;
108 else if (fstat(fd, &sbuf) >= 0)
109 siz = sbuf.st_size;
110 else {
111 sprintf(errmsg, "cannot stat '%s'", chName);
112 error(SYSTEM, errmsg);
113 close(fd); fd = -1;
114 return;
115 }
116 } else if (siz && ftruncate(fd, siz) < 0) {
117 sprintf(errmsg, "cannot resize '%s'", name);
118 error(SYSTEM, errmsg);
119 close(fd); fd = -1;
120 return;
121 }
122 osiz = siz;
123 chName = savqstr(name);
124 mode = flags;
125 }
126
127 RdataShareFile::~RdataShareFile()
128 {
129 if (fd >= 0) close(fd);
130 delete blist;
131 }
132
133 // Attempt to extend or shrink object (adjust if 0)
134 size_t
135 RdataShareFile::Resize(size_t new_siz)
136 {
137 if (fd < 0)
138 return 0;
139 if (new_siz > 0) {
140 if (new_siz == osiz)
141 return osiz;
142 if (!(mode & RDSwrite)) {
143 error(CONSISTENCY, "cannot resize read-only file");
144 return 0;
145 }
146 } else { // sync to current file length
147 struct stat sbuf;
148 if (fstat(fd, &sbuf) < 0) {
149 sprintf(errmsg, "cannot stat '%s'", chName);
150 error(SYSTEM, errmsg);
151 return 0;
152 }
153 return osiz = sbuf.st_size;
154 } // else attempt to resize file
155 if (ftruncate(fd, new_siz) < 0) {
156 sprintf(errmsg, "cannot truncate '%s'", chName);
157 return 0;
158 }
159 return osiz = new_siz;
160 }
161
162 // Get data buffer
163 void *
164 RdataShareFile::GetMemory(size_t offs, size_t len, int fl)
165 {
166 if (fd < 0)
167 return NULL;
168 if (fl & RDSextend && !Resize()) // sync to file length, first?
169 return NULL;
170 if (fl & mode & RDSread && offs + len > osiz) {
171 if (fl & RDSextend) { // resize if requested
172 if (!Resize(offs + len))
173 return NULL;
174 } else {
175 sprintf(errmsg, "requested block of %lu bytes past EOF in '%s'",
176 (unsigned long)len, chName);
177 error(CONSISTENCY, errmsg);
178 return NULL;
179 }
180 } // XXX should check for buffer overlap?
181 blist = new RDSbuffer(len, blist);
182 blist->pos = offs;
183 if (fl & mode & RDSread && // reading from file?
184 pread(fd, blist->buf, len, offs) != len) {
185 sprintf(errmsg, "read error on '%s'", chName);
186 error(SYSTEM, errmsg);
187 }
188 return blist->buf;
189 }
190
191 // Return data buffer
192 bool
193 RdataShareFile::ReleaseMemory(void *dp, int fl)
194 {
195 if (!blist) return false;
196 RDSbuffer * bp = blist->Find(dp);
197 if (!bp) {
198 sprintf(errmsg, "return of unallocated block for '%s'", chName);
199 error(CONSISTENCY, errmsg);
200 return false;
201 }
202 if ((fl & (RDSwrite|RDSextend)) == RDSwrite && bp->pos + bp->len > osiz) {
203 sprintf(errmsg, "write request past EOF in '%s'", chName);
204 error(CONSISTENCY, errmsg);
205 return NULL;
206 }
207 if (fl & mode & RDSwrite) { // writing to file?
208 if (pwrite(fd, bp->buf, bp->len, bp->pos) != bp->len) {
209 sprintf(errmsg, "write error on '%s'", chName);
210 error(SYSTEM, errmsg);
211 return false;
212 }
213 if (bp->pos + bp->len > osiz)
214 osiz = bp->pos + bp->len;
215 }
216 RDSbuffer rbuf(0, blist); // remove from buffer list
217 RDSbuffer * bp2 = &rbuf;
218 while (bp2->next != bp)
219 bp2 = bp2->next;
220 bp2->next = bp->next;
221 bp->next = NULL;
222 delete bp; // frees buffer memory
223 blist = rbuf.next;
224 return true;
225 }