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

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.2 static const char RCSid[] = "$Id: RdataShareFile.cpp,v 2.1 2024/10/29 00:36:54 greg Exp $";
3 greg 2.1 #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 greg 2.2 oflags |= O_RDWR|O_CREAT;
88     break;
89     case RDSwrite:
90     oflags |= O_WRONLY|O_CREAT;
91 greg 2.1 break;
92     case RDSread:
93     oflags |= O_RDONLY;
94     break;
95     }
96 greg 2.2 if (flags & RDSexcl) oflags |= O_EXCL;
97 greg 2.1 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     }