gem5 v24.0.0.0
Loading...
Searching...
No Matches
fd_array.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016 Advanced Micro Devices, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "sim/fd_array.hh"
33
34#include <fcntl.h>
35#include <unistd.h>
36
37#include <array>
38#include <memory>
39#include <string>
40
41#include "base/logging.hh"
42#include "base/output.hh"
43#include "params/Process.hh"
44#include "sim/fd_entry.hh"
45#include "sim/process.hh"
46
47namespace gem5
48{
49
50FDArray::FDArray(std::string const& input, std::string const& output,
51 std::string const& errout)
52 : _fdArray(), _input(input), _output(output), _errout(errout),
53 _imap {{"", -1},
54 {"cin", STDIN_FILENO},
55 {"stdin", STDIN_FILENO}},
56 _oemap{{"", -1},
57 {"cout", STDOUT_FILENO},
58 {"stdout", STDOUT_FILENO},
59 {"cerr", STDERR_FILENO},
60 {"stderr", STDERR_FILENO}}
61{
62 int sim_fd;
63 std::map<std::string, int>::iterator it;
64
69 if ((it = _imap.find(input)) != _imap.end())
70 sim_fd = it->second;
71 else
72 sim_fd = openInputFile(input);
73
74 auto ffd = std::make_shared<FileFDEntry>(sim_fd, O_RDONLY, input, false);
75 _fdArray[STDIN_FILENO] = ffd;
76
81 if ((it = _oemap.find(output)) != _oemap.end())
82 sim_fd = it->second;
83 else
84 sim_fd = openOutputFile(output);
85
86 ffd = std::make_shared<FileFDEntry>(sim_fd, O_WRONLY | O_CREAT | O_TRUNC,
87 output, false);
88 _fdArray[STDOUT_FILENO] = ffd;
89
90 if (output == errout)
91 ; /* Reuse the same file descriptor if these match. */
92 else if ((it = _oemap.find(errout)) != _oemap.end())
93 sim_fd = it->second;
94 else
95 sim_fd = openOutputFile(errout);
96
97 ffd = std::make_shared<FileFDEntry>(sim_fd, O_WRONLY | O_CREAT | O_TRUNC,
98 errout, false);
99 _fdArray[STDERR_FILENO] = ffd;
100}
101
102void
103FDArray::updateFileOffsets()
104{
105 for (auto& fdp : _fdArray) {
111 auto ffd = std::dynamic_pointer_cast<FileFDEntry>(fdp);
112
113 if (!ffd)
114 continue;
115
120 int sim_fd = ffd->getSimFD();
121 ffd->setFileOffset(lseek(sim_fd, 0, SEEK_CUR));
122 }
123}
124
125void
126FDArray::restoreFileOffsets()
127{
135 auto seek = [] (std::shared_ptr<FileFDEntry> ffd)
136 {
137 if (lseek(ffd->getSimFD(), ffd->getFileOffset(), SEEK_SET) < 0)
138 fatal("Unable to seek to location in %s", ffd->getFileName());
139 };
140
141 std::map<std::string, int>::iterator it;
142
150 std::shared_ptr<FDEntry> stdin_fde = _fdArray[STDIN_FILENO];
151 auto stdin_ffd = std::dynamic_pointer_cast<FileFDEntry>(stdin_fde);
152
153 if (_input != stdin_ffd->getFileName()) {
154 warn("Using new input file (%s) rather than checkpointed (%s)\n",
155 _input, stdin_ffd->getFileName());
156 stdin_ffd->setFileName(_input);
157 stdin_ffd->setFileOffset(0);
158 }
159
160 if ((it = _imap.find(stdin_ffd->getFileName())) != _imap.end()) {
161 stdin_ffd->setSimFD(it->second);
162 } else {
163 stdin_ffd->setSimFD(openInputFile(stdin_ffd->getFileName()));
164 seek(stdin_ffd);
165 }
166
174 std::shared_ptr<FDEntry> stdout_fde = _fdArray[STDOUT_FILENO];
175 auto stdout_ffd = std::dynamic_pointer_cast<FileFDEntry>(stdout_fde);
176
177 if (_output != stdout_ffd->getFileName()) {
178 warn("Using new output file (%s) rather than checkpointed (%s)\n",
179 _output, stdout_ffd->getFileName());
180 stdout_ffd->setFileName(_output);
181 stdout_ffd->setFileOffset(0);
182 }
183
184 if ((it = _oemap.find(stdout_ffd->getFileName())) != _oemap.end()) {
185 stdout_ffd->setSimFD(it->second);
186 } else {
187 stdout_ffd->setSimFD(openOutputFile(stdout_ffd->getFileName()));
188 seek(stdout_ffd);
189 }
190
198 std::shared_ptr<FDEntry> stderr_fde = _fdArray[STDERR_FILENO];
199 auto stderr_ffd = std::dynamic_pointer_cast<FileFDEntry>(stderr_fde);
200
201 if (_errout != stderr_ffd->getFileName()) {
202 warn("Using new error file (%s) rather than checkpointed (%s)\n",
203 _errout, stderr_ffd->getFileName());
204 stderr_ffd->setFileName(_errout);
205 stderr_ffd->setFileOffset(0);
206 }
207
208 if (stdout_ffd->getFileName() == stderr_ffd->getFileName()) {
209 /* Reuse the same sim_fd file descriptor if these match. */
210 stderr_ffd->setSimFD(stdout_ffd->getSimFD());
211 } else if ((it = _oemap.find(stderr_ffd->getFileName())) != _oemap.end()) {
212 stderr_ffd->setSimFD(it->second);
213 } else {
214 stderr_ffd->setSimFD(openOutputFile(stderr_ffd->getFileName()));
215 seek(stderr_ffd);
216 }
217
218 for (int tgt_fd = 3; tgt_fd < _fdArray.size(); tgt_fd++) {
219 std::shared_ptr<FDEntry> fdp = _fdArray[tgt_fd];
220 if (!fdp)
221 continue;
222
223 /* Need to reconnect pipe ends. */
224 if (auto pfd = std::dynamic_pointer_cast<PipeFDEntry>(fdp)) {
230 if (pfd->getEndType() == PipeFDEntry::EndType::write)
231 continue;
232
233 /* Setup the pipe or fatal out of the simulation. */
234 int fd_pair[2];
235 if (pipe(fd_pair) < 0)
236 fatal("Unable to create new pipe");
237
242 pfd->setSimFD(fd_pair[0]);
243
248 int prs = pfd->getPipeReadSource();
249 std::shared_ptr<FDEntry> write_fdp = _fdArray[prs];
250
251 /* Now cast it and make sure that we are still sane. */
252 auto write_pfd = std::dynamic_pointer_cast<PipeFDEntry>(write_fdp);
253
254 /* Hook up the write end back to the right side of the pipe. */
255 write_pfd->setSimFD(fd_pair[1]);
256 }
257
258 /* Need to reassign 'driver'. */
259 if (auto dfd = std::dynamic_pointer_cast<DeviceFDEntry>(fdp)) {
265 fatal("Unable to restore checkpoints with emulated drivers");
266 }
267
268 /* Need to open files and seek. */
269 if (auto ffd = std::dynamic_pointer_cast<FileFDEntry>(fdp)) {
277 int sim_fd = openFile(ffd->getFileName(), ffd->getFlags(), 0664);
278 ffd->setSimFD(sim_fd);
279 seek(ffd);
280 }
281 }
282}
283
284int
285FDArray::allocFD(std::shared_ptr<FDEntry> in)
286{
287 for (int i = 0; i < _fdArray.size(); i++) {
288 std::shared_ptr<FDEntry> fdp = _fdArray[i];
289 if (!fdp) {
290 _fdArray[i] = in;
291 return i;
292 }
293 }
294 fatal("Out of target file descriptors");
295}
296
297int
298FDArray::openFile(std::string const& filename, int flags, mode_t mode) const
299{
300 int sim_fd = open(filename.c_str(), flags, mode);
301 if (sim_fd != -1)
302 return sim_fd;
303 fatal("Unable to open %s with mode %d", filename, mode);
304}
305
306int
307FDArray::openInputFile(std::string const& filename) const
308{
309 return openFile(filename, O_RDONLY, 00);
310}
311
312int
313FDArray::openOutputFile(std::string const& filename) const
314{
315 return openFile(simout.resolve(filename),
316 O_WRONLY | O_CREAT | O_TRUNC, 0664);
317}
318
319std::shared_ptr<FDEntry>
320FDArray::getFDEntry(int tgt_fd)
321{
322 assert(0 <= tgt_fd && tgt_fd < _fdArray.size());
323 return _fdArray[tgt_fd];
324}
325
326void
327FDArray::setFDEntry(int tgt_fd, std::shared_ptr<FDEntry> fdep)
328{
329 assert(0 <= tgt_fd && tgt_fd < _fdArray.size());
330 _fdArray[tgt_fd] = fdep;
331}
332
333int
334FDArray::closeFDEntry(int tgt_fd)
335{
336 if (tgt_fd >= _fdArray.size() || tgt_fd < 0)
337 return -EBADF;
338
339 int sim_fd = -1;
340 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>(_fdArray[tgt_fd]);
341 if (hbfdp)
342 sim_fd = hbfdp->getSimFD();
343
344 int status = 0;
345 if (sim_fd > 2)
346 status = close(sim_fd);
347
348 if (status == 0)
349 _fdArray[tgt_fd] = nullptr;
350
351 return status;
352}
353
354void
355FDArray::serialize(CheckpointOut &cp) const {
356 ScopedCheckpointSection sec(cp, "fdarray");
357 paramOut(cp, "size", _fdArray.size());
358 for (int tgt_fd = 0; tgt_fd < _fdArray.size(); tgt_fd++) {
359 auto fd = _fdArray[tgt_fd];
360 ScopedCheckpointSection sec(cp, csprintf("Entry%d", tgt_fd));
361 if (!fd) {
362 paramOut(cp, "class", FDEntry::FDClass::fd_null);
363 continue;
364 }
365 paramOut(cp, "class", fd->getClass());
366 fd->serialize(cp);
367 }
368}
369
370void
371FDArray::unserialize(CheckpointIn &cp, Process* process_ptr) {
372 ScopedCheckpointSection sec(cp, "fdarray");
373 uint64_t size;
374 paramIn(cp, "size", size);
375 assert(_fdArray.size() == size &&
376 "FDArray sizes do not match at unserialize!");
377
378 for (int tgt_fd = 0; tgt_fd < _fdArray.size(); tgt_fd++) {
379 if (tgt_fd == STDIN_FILENO || tgt_fd == STDOUT_FILENO ||
380 tgt_fd == STDERR_FILENO)
381 continue;
382 ScopedCheckpointSection sec(cp, csprintf("Entry%d", tgt_fd));
383 FDEntry::FDClass fd_class;
384 paramIn(cp, "class", fd_class);
385 std::shared_ptr<FDEntry> fdep;
386
387 switch (fd_class) {
388 case FDEntry::FDClass::fd_base:
389 panic("Abstract fd entry was serialized");
390 break;
391 case FDEntry::FDClass::fd_hb:
392 fdep = std::make_shared<HBFDEntry>(0, 0);
393 break;
394 case FDEntry::FDClass::fd_file:
395 fdep = std::make_shared<FileFDEntry>(0, 0, "", 0, 00);
396 break;
397 case FDEntry::FDClass::fd_device:
398 fdep = std::make_shared<DeviceFDEntry>(nullptr, "");
399 break;
400 case FDEntry::FDClass::fd_pipe:
401 fdep = std::make_shared<PipeFDEntry>(
402 0, 0, PipeFDEntry::EndType::read);
403 break;
404 case FDEntry::FDClass::fd_socket:
405 fdep = std::make_shared<SocketFDEntry>(0, 0, 0, 0);
406 break;
407 case FDEntry::FDClass::fd_null:
408 continue;
409 default:
410 panic("Unrecognized fd class");
411 break;
412 }
413
414 fdep->unserialize(cp);
415
416 auto this_ffd = std::dynamic_pointer_cast<FileFDEntry>(fdep);
417 if (!this_ffd)
418 continue;
419 setFDEntry(tgt_fd, fdep);
420
421 mode_t mode = this_ffd->getFileMode();
422
423 std::string path;
424
425 if (process_ptr) {
426 // Check if it is needed to redirect the app path to another host
427 // path
428 path = process_ptr->checkPathRedirect(this_ffd->getFileName());
429 }
430 else {
431 path = this_ffd->getFileName();
432 }
433
434 int flags = this_ffd->getFlags();
435
436 // Re-open the file and assign a new sim_fd
437 int sim_fd;
438 sim_fd = openFile(path, flags, mode);
439
440 this_ffd->setSimFD(sim_fd);
441
442 // Restore the file offset to the proper value
443 uint64_t file_offset = this_ffd->getFileOffset();
444 lseek(sim_fd, file_offset, SEEK_SET);
445 }
446}
447
448} // namespace gem5
FDArray(std::string const &input, std::string const &output, std::string const &errout)
Initialize the file descriptor array and set the standard file descriptors to defaults or values pass...
Definition fd_array.cc:50
std::string resolve(const std::string &name) const
Returns relative file names prepended with name of this directory.
Definition output.cc:204
std::string checkPathRedirect(const std::string &filename)
Redirect file path if it matches any keys initialized by system object.
Definition process.cc:424
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
uint8_t flags
Definition helpers.cc:87
#define warn(...)
Definition logging.hh:256
Bitfield< 14, 12 > fd
Definition types.hh:150
Bitfield< 4, 0 > mode
Definition misc_types.hh:74
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 5, 0 > status
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
std::ostream CheckpointOut
Definition serialize.hh:66
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
Definition types.cc:40
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
Definition types.cc:72
OutputDirectory simout
Definition output.cc:62
static void output(const char *filename)
Definition debug.cc:60
std::string csprintf(const char *format, const Args &...args)
Definition cprintf.hh:161

Generated on Tue Jun 18 2024 16:24:06 for gem5 by doxygen 1.11.0