gem5  v22.1.0.0
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 
46 namespace gem5
47 {
48 
49 FDArray::FDArray(std::string const& input, std::string const& output,
50  std::string const& errout)
51  : _fdArray(), _input(input), _output(output), _errout(errout),
52  _imap {{"", -1},
53  {"cin", STDIN_FILENO},
54  {"stdin", STDIN_FILENO}},
55  _oemap{{"", -1},
56  {"cout", STDOUT_FILENO},
57  {"stdout", STDOUT_FILENO},
58  {"cerr", STDERR_FILENO},
59  {"stderr", STDERR_FILENO}}
60 {
61  int sim_fd;
62  std::map<std::string, int>::iterator it;
63 
68  if ((it = _imap.find(input)) != _imap.end())
69  sim_fd = it->second;
70  else
71  sim_fd = openInputFile(input);
72 
73  auto ffd = std::make_shared<FileFDEntry>(sim_fd, O_RDONLY, input, false);
74  _fdArray[STDIN_FILENO] = ffd;
75 
80  if ((it = _oemap.find(output)) != _oemap.end())
81  sim_fd = it->second;
82  else
83  sim_fd = openOutputFile(output);
84 
85  ffd = std::make_shared<FileFDEntry>(sim_fd, O_WRONLY | O_CREAT | O_TRUNC,
86  output, false);
87  _fdArray[STDOUT_FILENO] = ffd;
88 
89  if (output == errout)
90  ; /* Reuse the same file descriptor if these match. */
91  else if ((it = _oemap.find(errout)) != _oemap.end())
92  sim_fd = it->second;
93  else
94  sim_fd = openOutputFile(errout);
95 
96  ffd = std::make_shared<FileFDEntry>(sim_fd, O_WRONLY | O_CREAT | O_TRUNC,
97  errout, false);
98  _fdArray[STDERR_FILENO] = ffd;
99 }
100 
101 void
102 FDArray::updateFileOffsets()
103 {
104  for (auto& fdp : _fdArray) {
110  auto ffd = std::dynamic_pointer_cast<FileFDEntry>(fdp);
111 
112  if (!ffd)
113  continue;
114 
119  int sim_fd = ffd->getSimFD();
120  ffd->setFileOffset(lseek(sim_fd, 0, SEEK_CUR));
121  }
122 }
123 
124 void
125 FDArray::restoreFileOffsets()
126 {
134  auto seek = [] (std::shared_ptr<FileFDEntry> ffd)
135  {
136  if (lseek(ffd->getSimFD(), ffd->getFileOffset(), SEEK_SET) < 0)
137  fatal("Unable to seek to location in %s", ffd->getFileName());
138  };
139 
140  std::map<std::string, int>::iterator it;
141 
149  std::shared_ptr<FDEntry> stdin_fde = _fdArray[STDIN_FILENO];
150  auto stdin_ffd = std::dynamic_pointer_cast<FileFDEntry>(stdin_fde);
151 
152  if (_input != stdin_ffd->getFileName()) {
153  warn("Using new input file (%s) rather than checkpointed (%s)\n",
154  _input, stdin_ffd->getFileName());
155  stdin_ffd->setFileName(_input);
156  stdin_ffd->setFileOffset(0);
157  }
158 
159  if ((it = _imap.find(stdin_ffd->getFileName())) != _imap.end()) {
160  stdin_ffd->setSimFD(it->second);
161  } else {
162  stdin_ffd->setSimFD(openInputFile(stdin_ffd->getFileName()));
163  seek(stdin_ffd);
164  }
165 
173  std::shared_ptr<FDEntry> stdout_fde = _fdArray[STDOUT_FILENO];
174  auto stdout_ffd = std::dynamic_pointer_cast<FileFDEntry>(stdout_fde);
175 
176  if (_output != stdout_ffd->getFileName()) {
177  warn("Using new output file (%s) rather than checkpointed (%s)\n",
178  _output, stdout_ffd->getFileName());
179  stdout_ffd->setFileName(_output);
180  stdout_ffd->setFileOffset(0);
181  }
182 
183  if ((it = _oemap.find(stdout_ffd->getFileName())) != _oemap.end()) {
184  stdout_ffd->setSimFD(it->second);
185  } else {
186  stdout_ffd->setSimFD(openOutputFile(stdout_ffd->getFileName()));
187  seek(stdout_ffd);
188  }
189 
197  std::shared_ptr<FDEntry> stderr_fde = _fdArray[STDERR_FILENO];
198  auto stderr_ffd = std::dynamic_pointer_cast<FileFDEntry>(stderr_fde);
199 
200  if (_errout != stderr_ffd->getFileName()) {
201  warn("Using new error file (%s) rather than checkpointed (%s)\n",
202  _errout, stderr_ffd->getFileName());
203  stderr_ffd->setFileName(_errout);
204  stderr_ffd->setFileOffset(0);
205  }
206 
207  if (stdout_ffd->getFileName() == stderr_ffd->getFileName()) {
208  /* Reuse the same sim_fd file descriptor if these match. */
209  stderr_ffd->setSimFD(stdout_ffd->getSimFD());
210  } else if ((it = _oemap.find(stderr_ffd->getFileName())) != _oemap.end()) {
211  stderr_ffd->setSimFD(it->second);
212  } else {
213  stderr_ffd->setSimFD(openOutputFile(stderr_ffd->getFileName()));
214  seek(stderr_ffd);
215  }
216 
217  for (int tgt_fd = 3; tgt_fd < _fdArray.size(); tgt_fd++) {
218  std::shared_ptr<FDEntry> fdp = _fdArray[tgt_fd];
219  if (!fdp)
220  continue;
221 
222  /* Need to reconnect pipe ends. */
223  if (auto pfd = std::dynamic_pointer_cast<PipeFDEntry>(fdp)) {
229  if (pfd->getEndType() == PipeFDEntry::EndType::write)
230  continue;
231 
232  /* Setup the pipe or fatal out of the simulation. */
233  int fd_pair[2];
234  if (pipe(fd_pair) < 0)
235  fatal("Unable to create new pipe");
236 
241  pfd->setSimFD(fd_pair[0]);
242 
247  int prs = pfd->getPipeReadSource();
248  std::shared_ptr<FDEntry> write_fdp = _fdArray[prs];
249 
250  /* Now cast it and make sure that we are still sane. */
251  auto write_pfd = std::dynamic_pointer_cast<PipeFDEntry>(write_fdp);
252 
253  /* Hook up the write end back to the right side of the pipe. */
254  write_pfd->setSimFD(fd_pair[1]);
255  }
256 
257  /* Need to reassign 'driver'. */
258  if (auto dfd = std::dynamic_pointer_cast<DeviceFDEntry>(fdp)) {
264  fatal("Unable to restore checkpoints with emulated drivers");
265  }
266 
267  /* Need to open files and seek. */
268  if (auto ffd = std::dynamic_pointer_cast<FileFDEntry>(fdp)) {
276  int sim_fd = openFile(ffd->getFileName(), ffd->getFlags(), 0664);
277  ffd->setSimFD(sim_fd);
278  seek(ffd);
279  }
280  }
281 }
282 
283 int
284 FDArray::allocFD(std::shared_ptr<FDEntry> in)
285 {
286  for (int i = 0; i < _fdArray.size(); i++) {
287  std::shared_ptr<FDEntry> fdp = _fdArray[i];
288  if (!fdp) {
289  _fdArray[i] = in;
290  return i;
291  }
292  }
293  fatal("Out of target file descriptors");
294 }
295 
296 int
297 FDArray::openFile(std::string const& filename, int flags, mode_t mode) const
298 {
299  int sim_fd = open(filename.c_str(), flags, mode);
300  if (sim_fd != -1)
301  return sim_fd;
302  fatal("Unable to open %s with mode %d", filename, mode);
303 }
304 
305 int
306 FDArray::openInputFile(std::string const& filename) const
307 {
308  return openFile(filename, O_RDONLY, 00);
309 }
310 
311 int
312 FDArray::openOutputFile(std::string const& filename) const
313 {
314  return openFile(simout.resolve(filename),
315  O_WRONLY | O_CREAT | O_TRUNC, 0664);
316 }
317 
318 std::shared_ptr<FDEntry>
319 FDArray::getFDEntry(int tgt_fd)
320 {
321  assert(0 <= tgt_fd && tgt_fd < _fdArray.size());
322  return _fdArray[tgt_fd];
323 }
324 
325 void
326 FDArray::setFDEntry(int tgt_fd, std::shared_ptr<FDEntry> fdep)
327 {
328  assert(0 <= tgt_fd && tgt_fd < _fdArray.size());
329  _fdArray[tgt_fd] = fdep;
330 }
331 
332 int
333 FDArray::closeFDEntry(int tgt_fd)
334 {
335  if (tgt_fd >= _fdArray.size() || tgt_fd < 0)
336  return -EBADF;
337 
338  int sim_fd = -1;
339  auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>(_fdArray[tgt_fd]);
340  if (hbfdp)
341  sim_fd = hbfdp->getSimFD();
342 
343  int status = 0;
344  if (sim_fd > 2)
345  status = close(sim_fd);
346 
347  if (status == 0)
348  _fdArray[tgt_fd] = nullptr;
349 
350  return status;
351 }
352 
353 void
355  ScopedCheckpointSection sec(cp, "fdarray");
356  paramOut(cp, "size", _fdArray.size());
357  for (int tgt_fd = 0; tgt_fd < _fdArray.size(); tgt_fd++) {
358  auto fd = _fdArray[tgt_fd];
359  ScopedCheckpointSection sec(cp, csprintf("Entry%d", tgt_fd));
360  if (!fd) {
361  paramOut(cp, "class", FDEntry::FDClass::fd_null);
362  continue;
363  }
364  paramOut(cp, "class", fd->getClass());
365  fd->serialize(cp);
366  }
367 }
368 
369 void
371  ScopedCheckpointSection sec(cp, "fdarray");
372  uint64_t size;
373  paramIn(cp, "size", size);
374  assert(_fdArray.size() == size &&
375  "FDArray sizes do not match at unserialize!");
376 
377  for (int tgt_fd = 0; tgt_fd < _fdArray.size(); tgt_fd++) {
378  if (tgt_fd == STDIN_FILENO || tgt_fd == STDOUT_FILENO ||
379  tgt_fd == STDERR_FILENO)
380  continue;
381  ScopedCheckpointSection sec(cp, csprintf("Entry%d", tgt_fd));
382  FDEntry::FDClass fd_class;
383  paramIn(cp, "class", fd_class);
384  std::shared_ptr<FDEntry> fdep;
385 
386  switch (fd_class) {
387  case FDEntry::FDClass::fd_base:
388  panic("Abstract fd entry was serialized");
389  break;
390  case FDEntry::FDClass::fd_hb:
391  fdep = std::make_shared<HBFDEntry>(0, 0);
392  break;
393  case FDEntry::FDClass::fd_file:
394  fdep = std::make_shared<FileFDEntry>(0, 0, "", 0, 00);
395  break;
396  case FDEntry::FDClass::fd_device:
397  fdep = std::make_shared<DeviceFDEntry>(nullptr, "");
398  break;
399  case FDEntry::FDClass::fd_pipe:
400  fdep = std::make_shared<PipeFDEntry>(
401  0, 0, PipeFDEntry::EndType::read);
402  break;
403  case FDEntry::FDClass::fd_socket:
404  fdep = std::make_shared<SocketFDEntry>(0, 0, 0, 0);
405  break;
406  case FDEntry::FDClass::fd_null:
407  continue;
408  default:
409  panic("Unrecognized fd class");
410  break;
411  }
412 
413  fdep->unserialize(cp);
414 
415  auto this_ffd = std::dynamic_pointer_cast<FileFDEntry>(fdep);
416  if (!this_ffd)
417  continue;
418  setFDEntry(tgt_fd, fdep);
419 
420  mode_t mode = this_ffd->getFileMode();
421  std::string const& path = this_ffd->getFileName();
422  int flags = this_ffd->getFlags();
423 
424  // Re-open the file and assign a new sim_fd
425  int sim_fd = openFile(path, flags, mode);
426  this_ffd->setSimFD(sim_fd);
427 
428  // Restore the file offset to the proper value
429  uint64_t file_offset = this_ffd->getFileOffset();
430  lseek(sim_fd, file_offset, SEEK_SET);
431  }
432 }
433 
434 } // 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:49
std::string resolve(const std::string &name) const
Returns relative file names prepended with name of this directory.
Definition: output.cc:204
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
uint8_t flags
Definition: helpers.cc:66
#define warn(...)
Definition: logging.hh:246
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
Definition: misc_types.hh:429
std::ostream & output()
Get the ostream from the current global logger.
Definition: trace.cc:79
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
std::ostream CheckpointOut
Definition: serialize.hh:66
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
Definition: types.cc:40
void unserialize(ThreadContext &tc, CheckpointIn &cp)
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
void serialize(const ThreadContext &tc, CheckpointOut &cp)
Thread context serialization helpers.
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161

Generated on Wed Dec 21 2022 10:22:39 for gem5 by doxygen 1.9.1