stdio_file_implementation.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * Copyright (c) 2021, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Array.h>
  8. #include <AK/IntrusiveList.h>
  9. #include <AK/Types.h>
  10. #include <bits/FILE.h>
  11. #include <bits/pthread_integration.h>
  12. #include <bits/wchar.h>
  13. #include <pthread.h>
  14. #include <sys/types.h>
  15. struct FILE {
  16. public:
  17. FILE(int fd, int mode)
  18. : m_fd(fd)
  19. , m_mode(mode)
  20. {
  21. pthread_mutexattr_t attr = { __PTHREAD_MUTEX_RECURSIVE };
  22. pthread_mutex_init(&m_mutex, &attr);
  23. }
  24. ~FILE();
  25. static FILE* create(int fd, int mode);
  26. void setbuf(u8* data, int mode, size_t size) { m_buffer.setbuf(data, mode, size); }
  27. bool flush();
  28. void purge();
  29. size_t pending();
  30. bool close();
  31. void lock();
  32. void unlock();
  33. int fileno() const { return m_fd; }
  34. bool eof() const { return m_eof; }
  35. int mode() const { return m_mode; }
  36. u8 flags() const { return m_flags; }
  37. int error() const { return m_error; }
  38. void clear_err() { m_error = 0; }
  39. void set_err() { m_error = 1; }
  40. size_t read(u8*, size_t);
  41. size_t write(u8 const*, size_t);
  42. template<typename CharType>
  43. bool gets(CharType*, size_t);
  44. bool ungetc(u8 byte) { return m_buffer.enqueue_front(byte); }
  45. int seek(off_t offset, int whence);
  46. off_t tell();
  47. pid_t popen_child() { return m_popen_child; }
  48. void set_popen_child(pid_t child_pid) { m_popen_child = child_pid; }
  49. void reopen(int fd, int mode);
  50. u8 const* readptr(size_t& available_size);
  51. void readptr_increase(size_t increment);
  52. enum Flags : u8 {
  53. None = 0,
  54. LastRead = 1,
  55. LastWrite = 2,
  56. };
  57. private:
  58. struct Buffer {
  59. // A ringbuffer that also transparently implements ungetc().
  60. public:
  61. ~Buffer();
  62. int mode() const { return m_mode; }
  63. void setbuf(u8* data, int mode, size_t size);
  64. // Make sure to call realize() before enqueuing any data.
  65. // Dequeuing can be attempted without it.
  66. void realize(int fd);
  67. void drop();
  68. bool may_use() const;
  69. bool is_not_empty() const { return m_ungotten || !m_empty; }
  70. size_t buffered_size() const;
  71. u8 const* begin_dequeue(size_t& available_size) const;
  72. void did_dequeue(size_t actual_size);
  73. u8* begin_enqueue(size_t& available_size) const;
  74. void did_enqueue(size_t actual_size);
  75. bool enqueue_front(u8 byte);
  76. private:
  77. constexpr static auto unget_buffer_size = MB_CUR_MAX;
  78. constexpr static u32 ungotten_mask = ((u32)0xffffffff) >> (sizeof(u32) * 8 - unget_buffer_size);
  79. // Note: the fields here are arranged this way
  80. // to make sizeof(Buffer) smaller.
  81. u8* m_data { nullptr };
  82. size_t m_capacity { BUFSIZ };
  83. size_t m_begin { 0 };
  84. size_t m_end { 0 };
  85. int m_mode { -1 };
  86. Array<u8, unget_buffer_size> m_unget_buffer { 0 };
  87. u32 m_ungotten : unget_buffer_size { 0 };
  88. bool m_data_is_malloced : 1 { false };
  89. // When m_begin == m_end, we want to distinguish whether
  90. // the buffer is full or empty.
  91. bool m_empty : 1 { true };
  92. };
  93. // Read or write using the underlying fd, bypassing the buffer.
  94. ssize_t do_read(u8*, size_t);
  95. ssize_t do_write(u8 const*, size_t);
  96. // Read some data into the buffer.
  97. bool read_into_buffer();
  98. // Flush *some* data from the buffer.
  99. bool write_from_buffer();
  100. int m_fd { -1 };
  101. int m_mode { 0 };
  102. u8 m_flags { Flags::None };
  103. int m_error { 0 };
  104. bool m_eof { false };
  105. pid_t m_popen_child { -1 };
  106. Buffer m_buffer;
  107. __pthread_mutex_t m_mutex;
  108. IntrusiveListNode<FILE> m_list_node;
  109. public:
  110. using List = IntrusiveList<&FILE::m_list_node>;
  111. };
  112. class ScopedFileLock {
  113. public:
  114. ScopedFileLock(FILE* file)
  115. : m_file(file)
  116. {
  117. m_file->lock();
  118. }
  119. ~ScopedFileLock()
  120. {
  121. m_file->unlock();
  122. }
  123. private:
  124. FILE* m_file;
  125. };