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 * Author: Brandon Potter
36 #include "sim/fd_array.hh"
45 #include "base/misc.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 : _input(input
), _output(output
), _errout(errout
), _fdArray(),
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 void (*seek
)(std::shared_ptr
<FileFDEntry
>)
135 = [] (std::shared_ptr
<FileFDEntry
> ffd
)
137 if (lseek(ffd
->getSimFD(), ffd
->getFileOffset(), SEEK_SET
) < 0)
138 fatal("Unable to seek to location in %s", ffd
->getFileName());
141 std::map
<std::string
, int>::iterator it
;
144 * Search through the input options and set fd if match is found;
145 * otherwise, open an input file and seek to location.
146 * Check if user has specified a different input file, and if so, use it
147 * instead of the file specified in the checkpoint. This also resets the
148 * file offset from the checkpointed value
150 std::shared_ptr
<FDEntry
> stdin_fde
= _fdArray
[STDIN_FILENO
];
151 auto stdin_ffd
= std::dynamic_pointer_cast
<FileFDEntry
>(stdin_fde
);
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);
160 if ((it
= imap
.find(stdin_ffd
->getFileName())) != imap
.end()) {
161 stdin_ffd
->setSimFD(it
->second
);
163 stdin_ffd
->setSimFD(openInputFile(stdin_ffd
->getFileName()));
168 * Search through the output options and set fd if match is found;
169 * otherwise, open an output file and seek to location.
170 * Check if user has specified a different output file, and if so, use it
171 * instead of the file specified in the checkpoint. This also resets the
172 * file offset from the checkpointed value
174 std::shared_ptr
<FDEntry
> stdout_fde
= _fdArray
[STDOUT_FILENO
];
175 auto stdout_ffd
= std::dynamic_pointer_cast
<FileFDEntry
>(stdout_fde
);
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);
184 if ((it
= oemap
.find(stdout_ffd
->getFileName())) != oemap
.end()) {
185 stdout_ffd
->setSimFD(it
->second
);
187 stdout_ffd
->setSimFD(openOutputFile(stdout_ffd
->getFileName()));
192 * Search through the error options and set fd if match is found;
193 * otherwise, open an error file and seek to location.
194 * Check if user has specified a different error file, and if so, use it
195 * instead of the file specified in the checkpoint. This also resets the
196 * file offset from the checkpointed value
198 std::shared_ptr
<FDEntry
> stderr_fde
= _fdArray
[STDERR_FILENO
];
199 auto stderr_ffd
= std::dynamic_pointer_cast
<FileFDEntry
>(stderr_fde
);
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);
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
);
214 stderr_ffd
->setSimFD(openOutputFile(stderr_ffd
->getFileName()));
218 for (int tgt_fd
= 3; tgt_fd
< _fdArray
.size(); tgt_fd
++) {
219 std::shared_ptr
<FDEntry
> fdp
= _fdArray
[tgt_fd
];
223 /* Need to reconnect pipe ends. */
224 if (auto pfd
= std::dynamic_pointer_cast
<PipeFDEntry
>(fdp
)) {
226 * Check which end of the pipe we are looking at; we only want
227 * to setup the pipe once so we arbitrarily choose the read
228 * end to be the end that sets up the pipe.
230 if (pfd
->getEndType() == PipeFDEntry::EndType::write
)
233 /* Setup the pipe or fatal out of the simulation. */
235 if (pipe(fd_pair
) < 0)
236 fatal("Unable to create new pipe");
239 * Reconstruct the ends of the pipe by reassigning the pipe
240 * that we created on the host. This one is the read end.
242 pfd
->setSimFD(fd_pair
[0]);
245 * Grab the write end by referencing the read ends source and
246 * using that tgt_fd to index the array.
248 int prs
= pfd
->getPipeReadSource();
249 std::shared_ptr
<FDEntry
> write_fdp
= _fdArray
[prs
];
251 /* Now cast it and make sure that we are still sane. */
252 auto write_pfd
= std::dynamic_pointer_cast
<PipeFDEntry
>(write_fdp
);
254 /* Hook up the write end back to the right side of the pipe. */
255 write_pfd
->setSimFD(fd_pair
[1]);
258 /* Need to reassign 'driver'. */
259 if (auto dfd
= std::dynamic_pointer_cast
<DeviceFDEntry
>(fdp
)) {
261 * Yeah, how does one retain the entire driver state from this
262 * particular set of code? If you figure it out, add some code
263 * here to rectify the issue.
265 fatal("Unable to restore checkpoints with emulated drivers");
268 /* Need to open files and seek. */
269 if (auto ffd
= std::dynamic_pointer_cast
<FileFDEntry
>(fdp
)) {
271 * Assume that this has the mode of an output file so there's no
272 * need to worry about properly recording the mode. If you're
273 * reading this and this happens to be your issue, at least be
274 * happy that you've discovered the issue (and not mad at me).
277 int sim_fd
= openFile(ffd
->getFileName(), ffd
->getFlags(), 0664);
278 ffd
->setSimFD(sim_fd
);
285 FDArray::allocFD(std::shared_ptr
<FDEntry
> in
)
287 for (int i
= 0; i
< _fdArray
.size(); i
++) {
288 std::shared_ptr
<FDEntry
> fdp
= _fdArray
[i
];
294 fatal("Out of target file descriptors");
298 FDArray::openFile(std::string
const& filename
, int flags
, mode_t mode
) const
300 int sim_fd
= open(filename
.c_str(), flags
, mode
);
303 fatal("Unable to open %s with mode %O", filename
, mode
);
307 FDArray::openInputFile(std::string
const& filename
) const
309 return openFile(filename
, O_RDONLY
, 00);
313 FDArray::openOutputFile(std::string
const& filename
) const
315 return openFile(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0664);
318 std::shared_ptr
<FDEntry
>
319 FDArray::getFDEntry(int tgt_fd
)
321 assert(0 <= tgt_fd
&& tgt_fd
< _fdArray
.size());
322 return _fdArray
[tgt_fd
];
326 FDArray::setFDEntry(int tgt_fd
, std::shared_ptr
<FDEntry
> fdep
)
328 assert(0 <= tgt_fd
&& tgt_fd
< _fdArray
.size());
329 _fdArray
[tgt_fd
] = fdep
;
333 FDArray::closeFDEntry(int tgt_fd
)
335 if (tgt_fd
>= _fdArray
.size() || tgt_fd
< 0)
339 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>(_fdArray
[tgt_fd
]);
341 sim_fd
= hbfdp
->getSimFD();
345 status
= close(sim_fd
);
348 _fdArray
[tgt_fd
] = nullptr;