Skip to content

Commit 0984442

Browse files
committed
runtime: flush std file descriptors at exit
1 parent b20b52f commit 0984442

3 files changed

Lines changed: 40 additions & 29 deletions

File tree

src/interpreter/Interpreter.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,30 @@ void Interpreter::internal_setup(const std::string &name,
227227
return buffered_writer->call(PyTuple::create(stderr).unwrap(), nullptr);
228228
})
229229
.and_then([text_io_wrapper](PyObject *stderr_buffer_writer) {
230+
auto *line_buffering = py_true();
230231
return text_io_wrapper->call(
231-
PyTuple::create(stderr_buffer_writer).unwrap(), nullptr);
232+
PyTuple::create(
233+
stderr_buffer_writer, py_none(), py_none(), py_none(), line_buffering)
234+
.unwrap(),
235+
nullptr);
232236
});
233237
ASSERT(py_stderr.is_ok());
234-
sys->add_symbol(PyString::create("stdin").unwrap(), py_stdin.unwrap());
235-
sys->add_symbol(PyString::create("stdout").unwrap(), py_stdout.unwrap());
236-
sys->add_symbol(PyString::create("stderr").unwrap(), py_stderr.unwrap());
238+
239+
for (auto [name, obj] : std::views::zip(std::array{ "stdin", "stdout", "stderr" },
240+
std::array{ py_stdin.unwrap(), py_stdout.unwrap(), py_stderr.unwrap() })) {
241+
sys->add_symbol(PyString::create(name).unwrap(), obj);
242+
register_callback(PyNativeFunction::create(
243+
std::string{ name } + "_exit",
244+
[obj](PyTuple *, PyDict *) -> PyResult<PyObject *> {
245+
return obj->get_method(PyString::create("flush").unwrap())
246+
.and_then([](PyObject *flush) {
247+
return flush->call(nullptr, nullptr);
248+
});
249+
},
250+
obj)
251+
.unwrap(),
252+
nullptr);
253+
}
237254
}
238255

239256
if (config.requires_importlib) {

src/runtime/modules/BuiltinsModule.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,7 @@ PyResult<PyObject *> print(const PyTuple *args, const PyDict *kwargs, Interprete
9292
// sys.stdout may be None when FILE* stdout isn't connected
9393
if (!file || file == py_none()) { return Ok(py_none()); }
9494
}
95-
// TODO: flush should be false, but for now we keep it as true, since there is no flush at
96-
// interpreter shutdown
97-
bool flush = true;
95+
bool flush = false;
9896
if (kwargs) {
9997
static const Value separator_keyword = String{ "sep" };
10098
static const Value end_keyword = String{ "end" };

src/runtime/modules/IOModule.cpp

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2959,8 +2959,7 @@ class TextIOWrapper : public TextIOBase
29592959

29602960
std::optional<Bytes> m_buffer_bytes;
29612961
size_t m_position{ 0 };
2962-
std::optional<Bytes> m_pending_bytes;// bytes to be written
2963-
size_t m_pending_bytes_count{ 0 };
2962+
Bytes m_pending_bytes;
29642963

29652964
size_t m_chunk_size{ 8192 };
29662965

@@ -3230,18 +3229,17 @@ class TextIOWrapper : public TextIOBase
32303229
return Ok(result);
32313230
}
32323231

3233-
PyResult<size_t> writeflush()
3232+
PyResult<std::monostate> writeflush()
32343233
{
3235-
if (!m_pending_bytes.has_value()) { return Ok(0); }
3234+
if (m_pending_bytes.b.empty()) { return Ok(std::monostate{}); }
32363235
auto written =
32373236
m_buffer->get_method(PyString::create("write").unwrap())
32383237
.and_then([this](PyObject *write) {
3239-
return write->call(PyTuple::create(m_pending_bytes.value()).unwrap(), nullptr);
3238+
return write->call(PyTuple::create(m_pending_bytes).unwrap(), nullptr);
32403239
});
32413240
if (written.is_err()) { return Err(written.unwrap_err()); }
32423241
m_pending_bytes = {};
3243-
m_pending_bytes_count = 0;
3244-
return Ok(0);
3242+
return Ok(std::monostate{});
32453243
}
32463244

32473245

@@ -3252,26 +3250,25 @@ class TextIOWrapper : public TextIOBase
32523250
auto *text = PyObject::from(args->elements()[0]).unwrap();
32533251
ASSERT(as<PyString>(text));
32543252
const auto text_len = as<PyString>(text)->size();
3253+
32553254
// TODO: Should use encoder
3256-
m_pending_bytes = Bytes::from_unescaped_string(as<PyString>(text)->to_string());
3257-
m_pending_bytes_count = m_pending_bytes->b.size();
3255+
auto new_bytes = Bytes::from_unescaped_string(as<PyString>(text)->to_string());
3256+
m_pending_bytes.b.insert(m_pending_bytes.b.end(), new_bytes.b.begin(), new_bytes.b.end());
3257+
32583258
const auto should_flush = [this]() -> bool {
32593259
if (!m_line_buffering) { return false; }
3260-
if (std::ranges::find(m_pending_bytes->b, std::byte{ '\n' })
3261-
!= m_pending_bytes->b.end()) {
3260+
if (std::ranges::find(m_pending_bytes.b, std::byte{ '\n' })
3261+
!= m_pending_bytes.b.end()) {
32623262
return true;
32633263
}
3264-
return std::ranges::find(m_pending_bytes->b, std::byte{ '\r' })
3265-
!= m_pending_bytes->b.end();
3264+
return std::ranges::find(m_pending_bytes.b, std::byte{ '\r' })
3265+
!= m_pending_bytes.b.end();
32663266
}();
3267-
auto result = writeflush();
3268-
while (result.is_ok()) {
3269-
ASSERT(m_pending_bytes_count >= result.unwrap());
3270-
m_pending_bytes_count -= result.unwrap();
3271-
if (m_pending_bytes_count == 0) { break; }
3272-
result = writeflush();
3267+
3268+
if (m_pending_bytes.b.size() >= m_chunk_size || should_flush || m_write_through) {
3269+
auto result = writeflush();
3270+
if (result.is_err()) { return Err(result.unwrap_err()); }
32733271
}
3274-
if (result.is_err()) { return Err(result.unwrap_err()); }
32753272

32763273
if (should_flush) {
32773274
if (auto r = m_buffer->get_method(PyString::create("flush").unwrap())
@@ -3337,8 +3334,7 @@ class TextIOWrapper : public TextIOBase
33373334

33383335
m_line_buffering = line_buffering;
33393336
m_write_through = write_through;
3340-
m_newline = newline.value_or("'\n");
3341-
m_pending_bytes_count = 0;
3337+
m_newline = newline.value_or("\n");
33423338

33433339
return Ok(1);
33443340
}

0 commit comments

Comments
 (0)