7
7
#include < emscripten.h>
8
8
#include < emscripten/bind.h>
9
9
10
+ /* 50 lines */
11
+ #define MBB_CONIO_BASE_THRESHOLD (50 )
12
+
13
+ /* 2 lines */
14
+ #define MBB_CONIO_LOWER_THRESHOLD (2 )
15
+
10
16
/* 20 ms */
11
- #define MBB_CONIO_DELAY (20 )
17
+ #define MBB_CONIO_BASE_DELAY (20 )
18
+
19
+ /* 1 ms */
20
+ #define MBB_CONIO_LOWEST_DELAY (1 )
21
+
22
+ static char mbb_conio_cnt;
12
23
13
- /* 10 characters */
14
- #define MBB_CONOUT_THRESHOLD (10 )
24
+ static void (*conout_hook_ptr)(const char *s, size_t len);
15
25
16
26
// used for exit code callback in JS
17
27
@@ -95,15 +105,47 @@ extern "C" {
95
105
}
96
106
}
97
107
98
- static void __exit_hook (int status) {
108
+ static inline void __exit_hook (int status) {
99
109
EM_ASM ({
100
110
Module[' mbb_main_cb' ]($0 );
101
111
}, status);
102
112
}
103
113
114
+ static inline bool __check_do_sleep (const char *s, size_t len) {
115
+
116
+ return !!memchr (s, ' \n ' , len);
117
+ }
118
+
119
+ static void __conout_hook_fast (const char *s, size_t len) {
120
+ if (!__check_do_sleep (s, len))
121
+ return ;
122
+
123
+ if (++mbb_conio_cnt >= MBB_CONIO_LOWER_THRESHOLD) {
124
+ mbb_conio_cnt = 0 ;
125
+ emscripten_sleep (MBB_CONIO_LOWEST_DELAY);
126
+ }
127
+ }
128
+
129
+ static void __conout_hook_dflt (const char *s, size_t len) {
130
+ if (!__check_do_sleep (s, len))
131
+ return ;
132
+
133
+ if (++mbb_conio_cnt >= MBB_CONIO_BASE_THRESHOLD) {
134
+ mbb_conio_cnt = 0 ;
135
+ conout_hook_ptr = __conout_hook_fast;
136
+ return ;
137
+ }
138
+
139
+ emscripten_sleep (MBB_CONIO_BASE_DELAY);
140
+ }
141
+
104
142
static int __main_wrap (int argc, char **argv) {
105
143
int res;
106
144
145
+ // reset conout hook state
146
+ conout_hook_ptr = __conout_hook_dflt;
147
+ mbb_conio_cnt = 0 ;
148
+
107
149
res = __mbb_main (argc, argv);
108
150
109
151
// asyncify breaks retval, so we do this to inform js side
@@ -117,29 +159,11 @@ __attribute__((noreturn)) static void __exit_wrap(int status) {
117
159
__real_exit (status);
118
160
}
119
161
120
- static void __conout_hook (const char *s, size_t len) {
121
- // when should we update UI?
122
-
123
- if (len >= MBB_CONOUT_THRESHOLD)
124
- goto do_sleep; // when the line is long enough
125
-
126
- if (memchr (s, ' \n ' , len) || memchr (s, ' \r ' , len))
127
- goto do_sleep; // when there is a newline char in the str
128
-
129
- return ;
130
-
131
- do_sleep:
132
- // sleeping is even more expensive to perf
133
- // so only do this when needed
134
- emscripten_sleep (MBB_CONIO_DELAY); // note this needs -sASYNCIFY in LDFLAGS
135
- }
136
-
137
- static void __check_do_conout_hook (int fd, const char *s, size_t len) {
162
+ static inline void __check_do_conout_hook (int fd, const char *s, size_t len) {
138
163
switch (fd) {
139
164
case STDOUT_FILENO:
140
165
case STDERR_FILENO:
141
- // give browser a chance to update UI
142
- __conout_hook (s, len);
166
+ conout_hook_ptr (s, len);
143
167
break ;
144
168
default :
145
169
break ;
@@ -162,7 +186,7 @@ static int __vprintf_wrap(const char *format, va_list ap) {
162
186
int res;
163
187
164
188
res = vprintf (format, ap);
165
- __conout_hook (format, strlen (format));
189
+ conout_hook_ptr (format, strlen (format));
166
190
167
191
return res;
168
192
}
@@ -193,8 +217,3 @@ static void __enable_conio_hack(void) {
193
217
EMSCRIPTEN_BINDINGS (conio_hack) {
194
218
emscripten::function (" mbb_enable_conio_hack" , &__enable_conio_hack);
195
219
}
196
-
197
- __attribute__ ((constructor)) static void __init_io_mode(void ) {
198
- // disable line buffering
199
- setvbuf (stdout, NULL , _IONBF, BUFSIZ);
200
- }
0 commit comments