2 * Copyright (c) 2016 Advanced Micro Devices, Inc.
5 * For use for simulation and test purposes only
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
17 * 3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
33 * Authors: Brandon Potter
36 #include "sim/fd_array.hh"
45 #include "base/logging.hh"
46 #include "params/Process.hh"
47 #include "sim/fd_entry.hh"
49 FDArray::FDArray(std::string
const& input
, std::string
const& output
,
50 std::string
const& errout
)
51 : _fdArray(), _input(input
), _output(output
), _errout(errout
),
53 {"cin", STDIN_FILENO
},
54 {"stdin", STDIN_FILENO
}},
56 {"cout", STDOUT_FILENO
},
57 {"stdout", STDOUT_FILENO
},
58 {"cerr", STDERR_FILENO
},
59 {"stderr", STDERR_FILENO
}}
62 std::map
<std::string
, int>::iterator it
;
65 * Search through the input options and setup the default fd if match is
66 * found; otherwise, open an input file and seek to location.
68 if ((it
= _imap
.find(input
)) != _imap
.end())
71 sim_fd
= openInputFile(input
);
73 auto ffd
= std::make_shared
<FileFDEntry
>(sim_fd
, O_RDONLY
, input
, false);
74 _fdArray
[STDIN_FILENO
] = ffd
;
77 * Search through the output/error options and setup the default fd if
78 * match is found; otherwise, open an output file and seek to location.
80 if ((it
= _oemap
.find(output
)) != _oemap
.end())
83 sim_fd
= openOutputFile(output
);
85 ffd
= std::make_shared
<FileFDEntry
>(sim_fd
, O_WRONLY
| O_CREAT
| O_TRUNC
,
87 _fdArray
[STDOUT_FILENO
] = ffd
;
90 ; /* Reuse the same file descriptor if these match. */
91 else if ((it
= _oemap
.find(errout
)) != _oemap
.end())
94 sim_fd
= openOutputFile(errout
);
96 ffd
= std::make_shared
<FileFDEntry
>(sim_fd
, O_WRONLY
| O_CREAT
| O_TRUNC
,
98 _fdArray
[STDERR_FILENO
] = ffd
;
102 FDArray::updateFileOffsets()
104 for (auto& fdp
: _fdArray
) {
106 * It only makes sense to check the offsets if the file descriptor
107 * type is 'File' (which indicates that this file is backed by a
108 * file on the host). If the type is File, then record the offset.
110 auto ffd
= std::dynamic_pointer_cast
<FileFDEntry
>(fdp
);
116 * Use lseek with SEEK_CUR with offset 0 to figure out where the
117 * offset currently resides and pass that back to our setter.
119 int sim_fd
= ffd
->getSimFD();
120 ffd
->setFileOffset(lseek(sim_fd
, 0, SEEK_CUR
));
125 FDArray::restoreFileOffsets()
128 * Use this lambda to highlight what we mean to do with the seek.
129 * Notice that this either seeks correctly (sets the file location on the
130 * host) or it fails with a fatal. The error is fatal because it's not
131 * possible to guarantee that the simulation will proceed as it should
132 * have in the same way that it would have proceeded sans checkpoints.
134 auto seek
= [] (std::shared_ptr
<FileFDEntry
> ffd
)
136 if (lseek(ffd
->getSimFD(), ffd
->getFileOffset(), SEEK_SET
) < 0)
137 fatal("Unable to seek to location in %s", ffd
->getFileName());
140 std::map
<std::string
, int>::iterator it
;
143 * Search through the input options and set fd if match is found;
144 * otherwise, open an input file and seek to location.
145 * Check if user has specified a different input file, and if so, use it
146 * instead of the file specified in the checkpoint. This also resets the
147 * file offset from the checkpointed value
149 std::shared_ptr
<FDEntry
> stdin_fde
= _fdArray
[STDIN_FILENO
];
150 auto stdin_ffd
= std::dynamic_pointer_cast
<FileFDEntry
>(stdin_fde
);
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);
159 if ((it
= _imap
.find(stdin_ffd
->getFileName())) != _imap
.end()) {
160 stdin_ffd
->setSimFD(it
->second
);
162 stdin_ffd
->setSimFD(openInputFile(stdin_ffd
->getFileName()));
167 * Search through the output options and set fd if match is found;
168 * otherwise, open an output file and seek to location.
169 * Check if user has specified a different output file, and if so, use it
170 * instead of the file specified in the checkpoint. This also resets the
171 * file offset from the checkpointed value
173 std::shared_ptr
<FDEntry
> stdout_fde
= _fdArray
[STDOUT_FILENO
];
174 auto stdout_ffd
= std::dynamic_pointer_cast
<FileFDEntry
>(stdout_fde
);
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);
183 if ((it
= _oemap
.find(stdout_ffd
->getFileName())) != _oemap
.end()) {
184 stdout_ffd
->setSimFD(it
->second
);
186 stdout_ffd
->setSimFD(openOutputFile(stdout_ffd
->getFileName()));
191 * Search through the error options and set fd if match is found;
192 * otherwise, open an error file and seek to location.
193 * Check if user has specified a different error file, and if so, use it
194 * instead of the file specified in the checkpoint. This also resets the
195 * file offset from the checkpointed value
197 std::shared_ptr
<FDEntry
> stderr_fde
= _fdArray
[STDERR_FILENO
];
198 auto stderr_ffd
= std::dynamic_pointer_cast
<FileFDEntry
>(stderr_fde
);
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);
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
);
213 stderr_ffd
->setSimFD(openOutputFile(stderr_ffd
->getFileName()));
217 for (int tgt_fd
= 3; tgt_fd
< _fdArray
.size(); tgt_fd
++) {
218 std::shared_ptr
<FDEntry
> fdp
= _fdArray
[tgt_fd
];
222 /* Need to reconnect pipe ends. */
223 if (auto pfd
= std::dynamic_pointer_cast
<PipeFDEntry
>(fdp
)) {
225 * Check which end of the pipe we are looking at; we only want
226 * to setup the pipe once so we arbitrarily choose the read
227 * end to be the end that sets up the pipe.
229 if (pfd
->getEndType() == PipeFDEntry::EndType::write
)
232 /* Setup the pipe or fatal out of the simulation. */
234 if (pipe(fd_pair
) < 0)
235 fatal("Unable to create new pipe");
238 * Reconstruct the ends of the pipe by reassigning the pipe
239 * that we created on the host. This one is the read end.
241 pfd
->setSimFD(fd_pair
[0]);
244 * Grab the write end by referencing the read ends source and
245 * using that tgt_fd to index the array.
247 int prs
= pfd
->getPipeReadSource();
248 std::shared_ptr
<FDEntry
> write_fdp
= _fdArray
[prs
];
250 /* Now cast it and make sure that we are still sane. */
251 auto write_pfd
= std::dynamic_pointer_cast
<PipeFDEntry
>(write_fdp
);
253 /* Hook up the write end back to the right side of the pipe. */
254 write_pfd
->setSimFD(fd_pair
[1]);
257 /* Need to reassign 'driver'. */
258 if (auto dfd
= std::dynamic_pointer_cast
<DeviceFDEntry
>(fdp
)) {
260 * Yeah, how does one retain the entire driver state from this
261 * particular set of code? If you figure it out, add some code
262 * here to rectify the issue.
264 fatal("Unable to restore checkpoints with emulated drivers");
267 /* Need to open files and seek. */
268 if (auto ffd
= std::dynamic_pointer_cast
<FileFDEntry
>(fdp
)) {
270 * Assume that this has the mode of an output file so there's no
271 * need to worry about properly recording the mode. If you're
272 * reading this and this happens to be your issue, at least be
273 * happy that you've discovered the issue (and not mad at me).
276 int sim_fd
= openFile(ffd
->getFileName(), ffd
->getFlags(), 0664);
277 ffd
->setSimFD(sim_fd
);
284 FDArray::allocFD(std::shared_ptr
<FDEntry
> in
)
286 for (int i
= 0; i
< _fdArray
.size(); i
++) {
287 std::shared_ptr
<FDEntry
> fdp
= _fdArray
[i
];
293 fatal("Out of target file descriptors");
297 FDArray::openFile(std::string
const& filename
, int flags
, mode_t mode
) const
299 int sim_fd
= open(filename
.c_str(), flags
, mode
);
302 fatal("Unable to open %s with mode %O", filename
, mode
);
306 FDArray::openInputFile(std::string
const& filename
) const
308 return openFile(filename
, O_RDONLY
, 00);
312 FDArray::openOutputFile(std::string
const& filename
) const
314 return openFile(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0664);
317 std::shared_ptr
<FDEntry
>
318 FDArray::getFDEntry(int tgt_fd
)
320 assert(0 <= tgt_fd
&& tgt_fd
< _fdArray
.size());
321 return _fdArray
[tgt_fd
];
325 FDArray::setFDEntry(int tgt_fd
, std::shared_ptr
<FDEntry
> fdep
)
327 assert(0 <= tgt_fd
&& tgt_fd
< _fdArray
.size());
328 _fdArray
[tgt_fd
] = fdep
;
332 FDArray::closeFDEntry(int tgt_fd
)
334 if (tgt_fd
>= _fdArray
.size() || tgt_fd
< 0)
338 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>(_fdArray
[tgt_fd
]);
340 sim_fd
= hbfdp
->getSimFD();
344 status
= close(sim_fd
);
347 _fdArray
[tgt_fd
] = nullptr;