quic/qbox
Loading...
Searching...
No Matches
legacy_char_backend_stdio.h
1/*
2 * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#pragma once
8
9#include "backends/legacy-char-backend.h"
10
11#include <unistd.h>
12
13#ifndef WIN32
14#include <async_event.h>
15#include <uutils.h>
16#include <module_factory_registery.h>
17#include <queue>
18#include <signal.h>
19#include <termios.h>
20#endif
21#include <atomic>
22
24{
25private:
26 gs::async_event m_event;
27 std::queue<unsigned char> m_queue;
28 std::mutex m_mutex;
29 std::atomic_bool m_running;
30 std::unique_ptr<std::thread> rcv_thread_id;
31 pthread_t rcv_pthread_id = 0;
32
33public:
34
35#ifdef WIN32
36#pragma message("CharBackendStdio not yet implemented for WIN32")
37#endif
38 static void catch_fn(int signo) {}
39
40 static void tty_reset()
41 {
42#ifndef WIN32
43 struct termios tty;
44
45 int fd = 0; /* stdout */
46
47 tcgetattr(fd, &tty);
48
49 tty.c_lflag |= ECHO | ECHONL | ICANON | IEXTEN;
50
52#endif
53 }
54
55 legacy_char_backend_stdio(sc_core::sc_module_name name, bool read_write = true): m_running(true)
56 {
57 SCP_TRACE(()) << "legacy_char_backend_stdio constructor";
58 SC_METHOD(rcv);
59 sensitive << m_event;
61
62#ifndef WIN32
63 struct termios tty;
64
65 int fd = 0; /* stdout */
66
67 tcgetattr(fd, &tty);
68
69 tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
70
72
73 atexit(tty_reset);
74
75 gs::SigHandler::get().register_on_exit_cb(std::string(this->name()) + ".char_backend_stdio::tty_reset",
76 tty_reset);
77 gs::SigHandler::get().add_sig_handler(SIGINT, gs::SigHandler::Handler_CB::PASS);
78 gs::SigHandler::get().register_handler(std::string(this->name()) + ".char_backend_stdio::SIGINT_handler",
79 [&](int signo) {
80 std::lock_guard<std::mutex> lock(m_mutex);
81 if (signo == SIGINT) {
82 char ch = '\x03';
83 m_queue.push(ch);
84 if (!m_queue.empty()) m_event.async_notify();
85 }
86 });
87#endif
88 if (read_write) {
89 rcv_thread_id = std::make_unique<std::thread>(&legacy_char_backend_stdio::rcv_thread, this);
90 }
91 }
92
93 void* rcv_thread()
94 {
95 struct sigaction act = { 0 };
96 act.sa_handler = &catch_fn;
98
99 rcv_pthread_id = pthread_self();
100 sigset_t set;
101 sigemptyset(&set);
102 sigaddset(&set, SIGURG);
104
105 int fd = 0;
106 char c;
107
108 while (m_running) {
109 int r = read(fd, &c, 1);
110 if (r == 1) {
111 std::lock_guard<std::mutex> lock(m_mutex);
112
113 if (c >= 0) {
114 m_queue.push(c);
115 }
116 if (!m_queue.empty()) {
117 m_event.async_notify();
118 }
119 }
120 if (r == 0) {
121 break;
122 }
123 }
124
125 return NULL;
126 }
127
128 void rcv(void)
129 {
130 unsigned char c;
131
132 std::lock_guard<std::mutex> lock(m_mutex);
133
134 while (!m_queue.empty()) {
135 if (m_can_receive(m_opaque)) {
136 c = m_queue.front();
137 m_queue.pop();
138 m_receive(m_opaque, &c, 1);
139 } else {
140 /* notify myself later, hopefully the queue drains */
141 m_event.notify(); // sc_core::sc_time(1, sc_core::SC_MS));
142 return;
143 }
144 }
145 }
146
147 void write(unsigned char c)
148 {
149 putchar(c);
150 fflush(stdout);
151 }
152
154 {
155 gs::SigHandler::get().deregister_on_exit_cb(std::string(name()) + ".char_backend_stdio::tty_reset");
156 gs::SigHandler::get().deregister_handler(std::string(name()) + ".char_backend_stdio::SIGINT_handler");
157 m_running = false;
158 if (rcv_pthread_id) pthread_kill(rcv_pthread_id, SIGURG);
159 if (rcv_thread_id->joinable()) rcv_thread_id->join();
160 }
161};
162extern "C" void module_register();
Definition legacy-char-backend.h:15
Definition target.h:160
Definition async_event.h:22
Definition legacy_char_backend_stdio.h:24