77#include < emscripten.h>
88#include < emscripten/bind.h>
99
10+ /* 50 lines */
11+ #define MBB_CONIO_BASE_THRESHOLD (50 )
12+
1013/* 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;
1220
13- /* 10 characters */
14- #define MBB_CONOUT_THRESHOLD (10 )
21+ static void (*conout_hook_ptr)(const char *s, size_t len);
1522
1623// used for exit code callback in JS
1724
@@ -95,15 +102,44 @@ extern "C" {
95102 }
96103}
97104
98- static void __exit_hook (int status) {
105+ static inline void __exit_hook (int status) {
99106 EM_ASM ({
100107 Module[' mbb_main_cb' ]($0 );
101108 }, status);
102109}
103110
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+
104136static int __main_wrap (int argc, char **argv) {
105137 int res;
106138
139+ // reset conout hook state
140+ conout_hook_ptr = __conout_hook_dflt;
141+ mbb_conio_cnt = 0 ;
142+
107143 res = __mbb_main (argc, argv);
108144
109145 // asyncify breaks retval, so we do this to inform js side
@@ -117,29 +153,11 @@ __attribute__((noreturn)) static void __exit_wrap(int status) {
117153 __real_exit (status);
118154}
119155
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) {
138157 switch (fd) {
139158 case STDOUT_FILENO:
140159 case STDERR_FILENO:
141- // give browser a chance to update UI
142- __conout_hook (s, len);
160+ conout_hook_ptr (s, len);
143161 break ;
144162 default :
145163 break ;
@@ -162,7 +180,7 @@ static int __vprintf_wrap(const char *format, va_list ap) {
162180 int res;
163181
164182 res = vprintf (format, ap);
165- __conout_hook (format, strlen (format));
183+ conout_hook_ptr (format, strlen (format));
166184
167185 return res;
168186}
@@ -193,8 +211,3 @@ static void __enable_conio_hack(void) {
193211EMSCRIPTEN_BINDINGS (conio_hack) {
194212 emscripten::function (" mbb_enable_conio_hack" , &__enable_conio_hack);
195213}
196-
197- __attribute__ ((constructor)) static void __init_io_mode(void ) {
198- // disable line buffering
199- setvbuf (stdout, NULL , _IONBF, BUFSIZ);
200- }
0 commit comments