| 1 | // core.h: Replacement for core/*.py
 | 
| 2 | 
 | 
| 3 | #ifndef CORE_H
 | 
| 4 | #define CORE_H
 | 
| 5 | 
 | 
| 6 | #include <pwd.h>  // passwd
 | 
| 7 | #include <signal.h>
 | 
| 8 | #include <termios.h>
 | 
| 9 | 
 | 
| 10 | // For now, we assume that simple int and pointer operations are atomic, rather
 | 
| 11 | // than using std::atomic.  Could be a ./configure option later.
 | 
| 12 | //
 | 
| 13 | // See doc/portability.md.
 | 
| 14 | 
 | 
| 15 | #define LOCK_FREE_ATOMICS 0
 | 
| 16 | 
 | 
| 17 | #if LOCK_FREE_ATOMICS
 | 
| 18 |   #include <atomic>
 | 
| 19 | #endif
 | 
| 20 | 
 | 
| 21 | #include "_gen/frontend/syntax.asdl.h"
 | 
| 22 | #include "cpp/pgen2.h"
 | 
| 23 | #include "mycpp/runtime.h"
 | 
| 24 | 
 | 
| 25 | // Hacky forward declaration
 | 
| 26 | namespace completion {
 | 
| 27 | class RootCompleter;
 | 
| 28 | };
 | 
| 29 | 
 | 
| 30 | namespace pyos {
 | 
| 31 | 
 | 
| 32 | const int TERM_ICANON = ICANON;
 | 
| 33 | const int TERM_ECHO = ECHO;
 | 
| 34 | const int EOF_SENTINEL = 256;
 | 
| 35 | const int NEWLINE_CH = 10;
 | 
| 36 | const int UNTRAPPED_SIGWINCH = -1;
 | 
| 37 | 
 | 
| 38 | Tuple2<int, int> WaitPid(int waitpid_options);
 | 
| 39 | Tuple2<int, int> Read(int fd, int n, List<BigStr*>* chunks);
 | 
| 40 | Tuple2<int, int> ReadByte(int fd);
 | 
| 41 | BigStr* ReadLineBuffered();
 | 
| 42 | Dict<BigStr*, BigStr*>* Environ();
 | 
| 43 | int Chdir(BigStr* dest_dir);
 | 
| 44 | BigStr* GetMyHomeDir();
 | 
| 45 | BigStr* GetHomeDir(BigStr* user_name);
 | 
| 46 | 
 | 
| 47 | class ReadError {
 | 
| 48 |  public:
 | 
| 49 |   explicit ReadError(int err_num_) : err_num(err_num_) {
 | 
| 50 |   }
 | 
| 51 | 
 | 
| 52 |   static constexpr ObjHeader obj_header() {
 | 
| 53 |     return ObjHeader::ClassFixed(kZeroMask, sizeof(ReadError));
 | 
| 54 |   }
 | 
| 55 | 
 | 
| 56 |   int err_num;
 | 
| 57 | };
 | 
| 58 | 
 | 
| 59 | class PasswdEntry {
 | 
| 60 |  public:
 | 
| 61 |   explicit PasswdEntry(const passwd* entry)
 | 
| 62 |       : pw_name(StrFromC(entry->pw_name)),
 | 
| 63 |         pw_uid(entry->pw_uid),
 | 
| 64 |         pw_gid(entry->pw_gid) {
 | 
| 65 |   }
 | 
| 66 | 
 | 
| 67 |   static constexpr ObjHeader obj_header() {
 | 
| 68 |     return ObjHeader::ClassFixed(field_mask(), sizeof(PasswdEntry));
 | 
| 69 |   }
 | 
| 70 | 
 | 
| 71 |   BigStr* pw_name;
 | 
| 72 |   int pw_uid;
 | 
| 73 |   int pw_gid;
 | 
| 74 | 
 | 
| 75 |   static constexpr uint32_t field_mask() {
 | 
| 76 |     return maskbit(offsetof(PasswdEntry, pw_name));
 | 
| 77 |   }
 | 
| 78 | };
 | 
| 79 | 
 | 
| 80 | List<PasswdEntry*>* GetAllUsers();
 | 
| 81 | 
 | 
| 82 | BigStr* GetUserName(int uid);
 | 
| 83 | 
 | 
| 84 | BigStr* OsType();
 | 
| 85 | 
 | 
| 86 | Tuple2<mops::BigInt, mops::BigInt> GetRLimit(int resource);
 | 
| 87 | 
 | 
| 88 | void SetRLimit(int resource, mops::BigInt soft, mops::BigInt hard);
 | 
| 89 | 
 | 
| 90 | Tuple3<double, double, double> Time();
 | 
| 91 | 
 | 
| 92 | void PrintTimes();
 | 
| 93 | 
 | 
| 94 | bool InputAvailable(int fd);
 | 
| 95 | 
 | 
| 96 | IOError_OSError* FlushStdout();
 | 
| 97 | 
 | 
| 98 | Tuple2<int, void*> PushTermAttrs(int fd, int mask);
 | 
| 99 | void PopTermAttrs(int fd, int orig_local_modes, void* term_attrs);
 | 
| 100 | 
 | 
| 101 | // Make the signal queue slab 4096 bytes, including the GC header.  See
 | 
| 102 | // cpp/core_test.cc.
 | 
| 103 | const int kMaxPendingSignals = 1022;
 | 
| 104 | 
 | 
| 105 | class SignalSafe {
 | 
| 106 |   // State that is shared between the main thread and signal handlers.
 | 
| 107 |  public:
 | 
| 108 |   SignalSafe()
 | 
| 109 |       : pending_signals_(AllocSignalList()),
 | 
| 110 |         empty_list_(AllocSignalList()),  // to avoid repeated allocation
 | 
| 111 |         last_sig_num_(0),
 | 
| 112 |         received_sigint_(false),
 | 
| 113 |         received_sigwinch_(false),
 | 
| 114 |         sigwinch_code_(UNTRAPPED_SIGWINCH),
 | 
| 115 |         num_dropped_(0) {
 | 
| 116 |   }
 | 
| 117 | 
 | 
| 118 |   // Called from signal handling context.  Do not allocate.
 | 
| 119 |   void UpdateFromSignalHandler(int sig_num) {
 | 
| 120 |     if (pending_signals_->len_ < pending_signals_->capacity_) {
 | 
| 121 |       // We can append without allocating
 | 
| 122 |       pending_signals_->append(sig_num);
 | 
| 123 |     } else {
 | 
| 124 |       // Unlikely: we would have to allocate.  Just increment a counter, which
 | 
| 125 |       // we could expose somewhere in the UI.
 | 
| 126 |       num_dropped_++;
 | 
| 127 |     }
 | 
| 128 | 
 | 
| 129 |     if (sig_num == SIGINT) {
 | 
| 130 |       received_sigint_ = true;
 | 
| 131 |     }
 | 
| 132 | 
 | 
| 133 |     if (sig_num == SIGWINCH) {
 | 
| 134 |       received_sigwinch_ = true;
 | 
| 135 |       sig_num = sigwinch_code_;  // mutate param
 | 
| 136 |     }
 | 
| 137 | 
 | 
| 138 | #if LOCK_FREE_ATOMICS
 | 
| 139 |     last_sig_num_.store(sig_num);
 | 
| 140 | #else
 | 
| 141 |     last_sig_num_ = sig_num;
 | 
| 142 | #endif
 | 
| 143 |   }
 | 
| 144 | 
 | 
| 145 |   // Main thread takes signals so it can run traps.
 | 
| 146 |   List<int>* TakePendingSignals() {
 | 
| 147 |     List<int>* ret = pending_signals_;
 | 
| 148 | 
 | 
| 149 |     // Make sure we have a distinct list to reuse.
 | 
| 150 |     DCHECK(empty_list_ != pending_signals_);
 | 
| 151 |     pending_signals_ = empty_list_;
 | 
| 152 | 
 | 
| 153 |     return ret;
 | 
| 154 |   }
 | 
| 155 | 
 | 
| 156 |   // Main thread returns the same list as an optimization to avoid allocation.
 | 
| 157 |   void ReuseEmptyList(List<int>* empty_list) {
 | 
| 158 |     DCHECK(empty_list != pending_signals_);  // must be different
 | 
| 159 |     DCHECK(len(empty_list) == 0);            // main thread clears
 | 
| 160 |     DCHECK(empty_list->capacity_ == kMaxPendingSignals);
 | 
| 161 | 
 | 
| 162 |     empty_list_ = empty_list;
 | 
| 163 |   }
 | 
| 164 | 
 | 
| 165 |   // Main thread wants to get the last signal received.
 | 
| 166 |   int LastSignal() {
 | 
| 167 | #if LOCK_FREE_ATOMICS
 | 
| 168 |     return last_sig_num_.load();
 | 
| 169 | #else
 | 
| 170 |     return last_sig_num_;
 | 
| 171 | #endif
 | 
| 172 |   }
 | 
| 173 | 
 | 
| 174 |   // Main thread wants to know if SIGINT was received since the last time
 | 
| 175 |   // PollSigInt was called.
 | 
| 176 |   bool PollSigInt() {
 | 
| 177 |     bool result = received_sigint_;
 | 
| 178 |     received_sigint_ = false;
 | 
| 179 |     return result;
 | 
| 180 |   }
 | 
| 181 | 
 | 
| 182 |   // Main thread tells us whether SIGWINCH is trapped.
 | 
| 183 |   void SetSigWinchCode(int code) {
 | 
| 184 |     sigwinch_code_ = code;
 | 
| 185 |   }
 | 
| 186 | 
 | 
| 187 |   // Main thread wants to know if SIGWINCH was received since the last time
 | 
| 188 |   // PollSigWinch was called.
 | 
| 189 |   bool PollSigWinch() {
 | 
| 190 |     bool result = received_sigwinch_;
 | 
| 191 |     received_sigwinch_ = false;
 | 
| 192 |     return result;
 | 
| 193 |   }
 | 
| 194 | 
 | 
| 195 |   static constexpr uint32_t field_mask() {
 | 
| 196 |     return maskbit(offsetof(SignalSafe, pending_signals_)) |
 | 
| 197 |            maskbit(offsetof(SignalSafe, empty_list_));
 | 
| 198 |   }
 | 
| 199 | 
 | 
| 200 |   static constexpr ObjHeader obj_header() {
 | 
| 201 |     return ObjHeader::ClassFixed(field_mask(), sizeof(SignalSafe));
 | 
| 202 |   }
 | 
| 203 | 
 | 
| 204 |   List<int>* pending_signals_;  // public for testing
 | 
| 205 |   List<int>* empty_list_;
 | 
| 206 | 
 | 
| 207 |  private:
 | 
| 208 |   // Enforce private state because two different "threads" will use it!
 | 
| 209 | 
 | 
| 210 |   // Reserve a fixed number of signals.
 | 
| 211 |   List<int>* AllocSignalList() {
 | 
| 212 |     List<int>* ret = NewList<int>();
 | 
| 213 |     ret->reserve(kMaxPendingSignals);
 | 
| 214 |     return ret;
 | 
| 215 |   }
 | 
| 216 | 
 | 
| 217 | #if LOCK_FREE_ATOMICS
 | 
| 218 |   std::atomic<int> last_sig_num_;
 | 
| 219 | #else
 | 
| 220 |   int last_sig_num_;
 | 
| 221 | #endif
 | 
| 222 |   // Not sufficient: volatile sig_atomic_t last_sig_num_;
 | 
| 223 | 
 | 
| 224 |   int received_sigint_;
 | 
| 225 |   int received_sigwinch_;
 | 
| 226 |   int sigwinch_code_;
 | 
| 227 |   int num_dropped_;
 | 
| 228 | };
 | 
| 229 | 
 | 
| 230 | extern SignalSafe* gSignalSafe;
 | 
| 231 | 
 | 
| 232 | // Allocate global and return it.
 | 
| 233 | SignalSafe* InitSignalSafe();
 | 
| 234 | 
 | 
| 235 | void Sigaction(int sig_num, void (*handler)(int));
 | 
| 236 | 
 | 
| 237 | void RegisterSignalInterest(int sig_num);
 | 
| 238 | 
 | 
| 239 | Tuple2<BigStr*, int>* MakeDirCacheKey(BigStr* path);
 | 
| 240 | 
 | 
| 241 | }  // namespace pyos
 | 
| 242 | 
 | 
| 243 | namespace pyutil {
 | 
| 244 | 
 | 
| 245 | float infinity();
 | 
| 246 | float nan();
 | 
| 247 | 
 | 
| 248 | bool IsValidCharEscape(BigStr* c);
 | 
| 249 | BigStr* ChArrayToString(List<int>* ch_array);
 | 
| 250 | 
 | 
| 251 | class _ResourceLoader {
 | 
| 252 |  public:
 | 
| 253 |   _ResourceLoader() {
 | 
| 254 |   }
 | 
| 255 | 
 | 
| 256 |   virtual BigStr* Get(BigStr* path);
 | 
| 257 | 
 | 
| 258 |   static constexpr ObjHeader obj_header() {
 | 
| 259 |     return ObjHeader::ClassFixed(kZeroMask, sizeof(_ResourceLoader));
 | 
| 260 |   }
 | 
| 261 | };
 | 
| 262 | 
 | 
| 263 | _ResourceLoader* GetResourceLoader();
 | 
| 264 | 
 | 
| 265 | BigStr* GetVersion(_ResourceLoader* loader);
 | 
| 266 | 
 | 
| 267 | void PrintVersionDetails(_ResourceLoader* loader);
 | 
| 268 | 
 | 
| 269 | BigStr* strerror(IOError_OSError* e);
 | 
| 270 | 
 | 
| 271 | BigStr* BackslashEscape(BigStr* s, BigStr* meta_chars);
 | 
| 272 | 
 | 
| 273 | grammar::Grammar* LoadYshGrammar(_ResourceLoader*);
 | 
| 274 | 
 | 
| 275 | }  // namespace pyutil
 | 
| 276 | 
 | 
| 277 | #endif  // CORE_H
 |