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#ifdef WIN32
35#pragma message("CharBackendStdio not yet implemented for WIN32")
36#endif
37 static void catch_fn(int signo) {}
38
39 static void tty_reset()
40 {
41#ifndef WIN32
42 struct termios tty;
43
44 int fd = 0; /* stdout */
45
46 tcgetattr(fd, &tty);
47
48 tty.c_lflag |= ECHO | ECHONL | ICANON | IEXTEN;
49
51#endif
52 }
53
54 legacy_char_backend_stdio(sc_core::sc_module_name name, bool read_write = true): m_running(true)
55 {
56 SCP_TRACE(()) << "legacy_char_backend_stdio constructor";
57 SC_METHOD(rcv);
58 sensitive << m_event;
60
61#ifndef WIN32
62 struct termios tty;
63
64 int fd = 0; /* stdout */
65
66 tcgetattr(fd, &tty);
67
68 tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
69
71
72 atexit(tty_reset);
73
74 gs::SigHandler::get().register_on_exit_cb(std::string(this->name()) + ".char_backend_stdio::tty_reset",
75 tty_reset);
76 gs::SigHandler::get().add_sigint_handler(gs::Handler_CB::PASS);
77 gs::SigHandler::get().register_handler(std::string(this->name()) + ".char_backend_stdio::SIGINT_handler",
78 [&](int signo) {
79 std::lock_guard<std::mutex> lock(m_mutex);
80 if (signo == SIGINT) {
81 char ch = '\x03';
82 m_queue.push(ch);
83 if (!m_queue.empty()) m_event.async_notify();
84 }
85 });
86#endif
87 if (read_write) {
88 rcv_thread_id = std::make_unique<std::thread>(&legacy_char_backend_stdio::rcv_thread, this);
89 }
90 }
91
92 void* rcv_thread()
93 {
94 struct sigaction act = { 0 };
95 act.sa_handler = &catch_fn;
97
98 rcv_pthread_id = pthread_self();
99 sigset_t set;
100 sigemptyset(&set);
101 sigaddset(&set, SIGURG);
103
104 int fd = 0;
105 char c;
106
107 while (m_running) {
108 int r = read(fd, &c, 1);
109 if (r == 1) {
110 std::lock_guard<std::mutex> lock(m_mutex);
111
112 if (c >= 0) {
113 m_queue.push(c);
114 }
115 if (!m_queue.empty()) {
116 m_event.async_notify();
117 }
118 }
119 if (r == 0) {
120 break;
121 }
122 }
123
124 return NULL;
125 }
126
127 void rcv(void)
128 {
129 unsigned char c;
130
131 std::lock_guard<std::mutex> lock(m_mutex);
132
133 while (!m_queue.empty()) {
134 if (m_can_receive(m_opaque)) {
135 c = m_queue.front();
136 m_queue.pop();
137 m_receive(m_opaque, &c, 1);
138 } else {
139 /* notify myself later, hopefully the queue drains */
140 m_event.notify(); // sc_core::sc_time(1, sc_core::SC_MS));
141 return;
142 }
143 }
144 }
145
146 void write(unsigned char c)
147 {
148 putchar(c);
149 fflush(stdout);
150 }
151
153 {
154 gs::SigHandler::get().deregister_on_exit_cb(std::string(name()) + ".char_backend_stdio::tty_reset");
155 gs::SigHandler::get().deregister_handler(std::string(name()) + ".char_backend_stdio::SIGINT_handler");
156 m_running = false;
157 if (rcv_pthread_id) pthread_kill(rcv_pthread_id, SIGURG);
158 if (rcv_thread_id->joinable()) rcv_thread_id->join();
159 }
160};
161extern "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