7
7
#include < emscripten.h>
8
8
#include < emscripten/bind.h>
9
9
10
+ /* 50 lines */
11
+ #define MBB_CONIO_BASE_THRESHOLD (50 )
12
+
10
13
/* 20 ms */
11
- #define MBB_CONIO_DELAY (20 )
14
+ #define MBB_CONIO_BASE_DELAY (20 )
15
+
16
+ /* 1 ms */
17
+ #define MBB_CONIO_LOWEST_DELAY (1 )
18
+
19
+ static char mbb_conio_cnt;
12
20
13
- /* 10 characters */
14
- #define MBB_CONOUT_THRESHOLD (10 )
21
+ static void (*conout_hook_ptr)(const char *s, size_t len);
15
22
16
23
// used for exit code callback in JS
17
24
@@ -95,15 +102,44 @@ extern "C" {
95
102
}
96
103
}
97
104
98
- static void __exit_hook (int status) {
105
+ static inline void __exit_hook (int status) {
99
106
EM_ASM ({
100
107
Module[' mbb_main_cb' ]($0 );
101
108
}, status);
102
109
}
103
110
111
+ static inline bool __should_sleep (const char *s, size_t len) {
112
+
113
+ return !!memchr (s, ' \n ' , len);
114
+ }
115
+
116
+ static void __conout_hook_fast (const char *s, size_t len) {
117
+ if (!__should_sleep (s, len))
118
+ return ;
119
+
120
+ emscripten_sleep (MBB_CONIO_LOWEST_DELAY);
121
+ }
122
+
123
+ static void __conout_hook_dflt (const char *s, size_t len) {
124
+ if (!__should_sleep (s, len))
125
+ return ;
126
+
127
+ if (++mbb_conio_cnt >= MBB_CONIO_BASE_THRESHOLD) {
128
+ mbb_conio_cnt = 0 ;
129
+ conout_hook_ptr = __conout_hook_fast;
130
+ return ;
131
+ }
132
+
133
+ emscripten_sleep (MBB_CONIO_BASE_DELAY);
134
+ }
135
+
104
136
static int __main_wrap (int argc, char **argv) {
105
137
int res;
106
138
139
+ // reset conout hook state
140
+ conout_hook_ptr = __conout_hook_dflt;
141
+ mbb_conio_cnt = 0 ;
142
+
107
143
res = __mbb_main (argc, argv);
108
144
109
145
// asyncify breaks retval, so we do this to inform js side
@@ -117,29 +153,11 @@ __attribute__((noreturn)) static void __exit_wrap(int status) {
117
153
__real_exit (status);
118
154
}
119
155
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) {
156
+ static inline void __check_do_conout_hook (int fd, const char *s, size_t len) {
138
157
switch (fd) {
139
158
case STDOUT_FILENO:
140
159
case STDERR_FILENO:
141
- // give browser a chance to update UI
142
- __conout_hook (s, len);
160
+ conout_hook_ptr (s, len);
143
161
break ;
144
162
default :
145
163
break ;
@@ -162,7 +180,7 @@ static int __vprintf_wrap(const char *format, va_list ap) {
162
180
int res;
163
181
164
182
res = vprintf (format, ap);
165
- __conout_hook (format, strlen (format));
183
+ conout_hook_ptr (format, strlen (format));
166
184
167
185
return res;
168
186
}
@@ -193,8 +211,3 @@ static void __enable_conio_hack(void) {
193
211
EMSCRIPTEN_BINDINGS (conio_hack) {
194
212
emscripten::function (" mbb_enable_conio_hack" , &__enable_conio_hack);
195
213
}
196
-
197
- __attribute__ ((constructor)) static void __init_io_mode(void ) {
198
- // disable line buffering
199
- setvbuf (stdout, NULL , _IONBF, BUFSIZ);
200
- }
0 commit comments