1 /* v/loop.c
2 **
3 */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <fcntl.h>
7 #include <sys/ioctl.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include <setjmp.h>
12 #include <gmp.h>
13 #include <sigsegv.h>
14 #include <stdint.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <uv.h>
18 #include <errno.h>
19 #include <curses.h>
20 #include <termios.h>
21 #include <term.h>
22 
23 #include "all.h"
24 #include "vere/vere.h"
25 
26 #if 0
27 static jmp_buf Signal_buf;
28 #ifndef SIGSTKSZ
29 # define SIGSTKSZ 16384
30 #endif
31 static uint8_t Sigstk[SIGSTKSZ];
32 
33 uint8_t u3_Critical;
34 
35 typedef enum {
36   sig_none,
37   sig_overflow,
38   sig_interrupt,
39   sig_terminate,
40   sig_memory,
41   sig_assert,
42   sig_timer
43 } u3_kill;
44 
45 volatile u3_kill Sigcause;            //  reasons for exception
46 
47 static void _lo_cont(void *arg1, void *arg2, void *arg3)
48 {
49   (void)(arg1);
50   (void)(arg2);
51   (void)(arg3);
52   siglongjmp(Signal_buf, 1);
53 }
54 
55 static void
56 _lo_signal_handle_over(int emergency, stackoverflow_context_t scp)
57 {
58   if ( u3_Critical ) {
59     //  Careful not to grow the stack during critical sections.
60     //
61     write(2, "stack disaster\n", strlen("stack disaster" + 2));
62     abort();
63   }
64 
65 #if 0
66   if ( 1 == emergency ) {
67     write(2, "stack emergency\n", strlen("stack emergency" + 2));
68     abort();
69   } else
70 #endif
71   {
72     Sigcause = sig_overflow;
73     sigsegv_leave_handler(_lo_cont, NULL, NULL, NULL);
74   }
75 }
76 
77 static void
78 _lo_signal_handle_term(int x)
79 {
80   if ( !u3_Critical ) {
81     Sigcause = sig_terminate;
82     u3_Host.liv = c3n;
83     longjmp(Signal_buf, 1);
84   }
85 }
86 
87 static void
88 _lo_signal_handle_intr(int x)
89 {
90   if ( !u3_Critical ) {
91     Sigcause = sig_interrupt;
92     longjmp(Signal_buf, 1);
93   }
94 }
95 
96 static void
97 _lo_signal_handle_alrm(int x)
98 {
99   if ( !u3_Critical ) {
100     Sigcause = sig_timer;
101     longjmp(Signal_buf, 1);
102   }
103 }
104 
105 /* _lo_signal_done():
106 */
107 static void
108 _lo_signal_done()
109 {
110   // signal(SIGINT, SIG_IGN);
111   signal(SIGTERM, SIG_IGN);
112   signal(SIGVTALRM, SIG_IGN);
113 
114   stackoverflow_deinstall_handler();
115   {
116     struct itimerval itm_u;
117 
118     timerclear(&itm_u.it_interval);
119     timerclear(&itm_u.it_value);
120 
121     setitimer(ITIMER_VIRTUAL, &itm_u, 0);
122   }
123   u3_unix_ef_move();
124 }
125 
126 /* _lo_signal_deep(): start deep processing; set timer for sec_w or 0.
127 */
128 static void
129 _lo_signal_deep(c3_w sec_w)
130 {
131   u3_unix_ef_hold();
132 
133   stackoverflow_install_handler(_lo_signal_handle_over, Sigstk, SIGSTKSZ);
134   signal(SIGINT, _lo_signal_handle_intr);
135   signal(SIGTERM, _lo_signal_handle_term);
136 
137   {
138     struct itimerval itm_u;
139 
140     timerclear(&itm_u.it_interval);
141     itm_u.it_value.tv_sec = sec_w;
142     itm_u.it_value.tv_usec = 0;
143 
144     setitimer(ITIMER_VIRTUAL, &itm_u, 0);
145   }
146   signal(SIGVTALRM, _lo_signal_handle_alrm);
147 }
148 #endif
149 
150 /* u3_loop_signal_memory(): end computation for out-of-memory.
151 */
152 void
u3_loop_signal_memory()153 u3_loop_signal_memory()
154 {
155   fprintf(stderr, "\r\nout of memory\r\n");
156   c3_assert(0);
157 
158 #if 0
159   Sigcause = sig_memory;
160   longjmp(Signal_buf, 1);
161 #endif
162 }
163 
164 /* _lo_init(): initialize I/O across the process.
165 */
166 static void
_lo_init()167 _lo_init()
168 {
169   c3_l cod_l;
170 
171   cod_l = u3a_lush(c3__unix);
172   u3_unix_io_init();
173   u3a_lop(cod_l);
174 
175   cod_l = u3a_lush(c3__ames);
176   u3_ames_io_init();
177   u3a_lop(cod_l);
178 
179   cod_l = u3a_lush(c3__term);
180   u3_term_io_init();
181   u3a_lop(cod_l);
182 
183   cod_l = u3a_lush(c3__http);
184   u3_http_io_init();
185   u3a_lop(cod_l);
186 
187   cod_l = u3a_lush(c3__cttp);
188   u3_cttp_io_init();
189   u3a_lop(cod_l);
190 
191   cod_l = u3a_lush(c3__save);
192   u3_save_io_init();
193   u3a_lop(cod_l);
194 
195   cod_l = u3a_lush(c3__behn);
196   u3_behn_io_init();
197   u3a_lop(cod_l);
198 }
199 
200 /* _lo_talk(): bring up listeners across the process.
201 */
202 static void
_lo_talk()203 _lo_talk()
204 {
205   c3_l cod_l;
206 
207   cod_l = u3a_lush(c3__unix);
208   u3_unix_io_talk();
209   u3a_lop(cod_l);
210 
211   cod_l = u3a_lush(c3__ames);
212   u3_ames_io_talk();
213   u3a_lop(cod_l);
214 
215   cod_l = u3a_lush(c3__http);
216   u3_http_io_talk();
217   u3a_lop(cod_l);
218 
219 }
220 
221 /* u3_lo_exit(): terminate I/O across the process.
222 */
223 void
u3_lo_exit(void)224 u3_lo_exit(void)
225 {
226   c3_l cod_l;
227 
228   cod_l = u3a_lush(c3__unix);
229   u3_unix_io_exit();
230   u3a_lop(cod_l);
231 
232   cod_l = u3a_lush(c3__ames);
233   u3_ames_io_exit();
234   u3a_lop(cod_l);
235 
236   cod_l = u3a_lush(c3__term);
237   u3_term_io_exit();
238   u3a_lop(cod_l);
239 
240   cod_l = u3a_lush(c3__http);
241   u3_http_io_exit();
242   u3a_lop(cod_l);
243 
244   cod_l = u3a_lush(c3__cttp);
245   u3_cttp_io_exit();
246   u3a_lop(cod_l);
247 
248   cod_l = u3a_lush(c3__save);
249   u3_save_io_exit();
250   u3a_lop(cod_l);
251 
252   cod_l = u3a_lush(c3__behn);
253   u3_behn_io_exit();
254   u3a_lop(cod_l);
255 }
256 
257 /* _lo_poll(): reset event flags across the process.
258 */
259 static void
_lo_poll(void)260 _lo_poll(void)
261 {
262   c3_l cod_l;
263 
264   cod_l = u3a_lush(c3__ames);
265   u3_ames_io_poll();
266   u3a_lop(cod_l);
267 
268   cod_l = u3a_lush(c3__http);
269   u3_http_io_poll();
270   u3a_lop(cod_l);
271 
272   cod_l = u3a_lush(c3__term);
273   u3_term_io_poll();
274   u3a_lop(cod_l);
275 
276   cod_l = u3a_lush(c3__save);
277   u3_save_io_poll();
278   u3a_lop(cod_l);
279 
280   cod_l = u3a_lush(c3__unix);
281   u3_unix_io_poll();
282   u3a_lop(cod_l);
283 
284   cod_l = u3a_lush(c3__behn);
285   u3_behn_io_poll();
286   u3a_lop(cod_l);
287 }
288 
289 #if 0
290 /* _lo_how(): print how.
291 */
292 static const c3_c*
293 _lo_how(u3_noun how)
294 {
295   switch ( how ) {
296     default: c3_assert(0); break;
297 
298     case c3__ames: return "ames";
299     case c3__behn: return "behn";
300     case c3__term: return "cons";
301     case c3__htcn: return "http-conn";
302     case c3__htls: return "http-lisn";
303     case c3__save: return "save";
304     case c3__unix: return "unix";
305   }
306 }
307 #endif
308 
309 /* u3_lo_bail(): clean up all event state.
310 */
311 void
u3_lo_bail(void)312 u3_lo_bail(void)
313 {
314   fflush(stdout);
315   u3_lo_exit();
316 
317   exit(1);
318 }
319 
320 /* _lo_tape(): dump a tape, old style.  Don't do this.
321 */
322 static void
_lo_tape(FILE * fil_u,u3_noun tep)323 _lo_tape(FILE* fil_u, u3_noun tep)
324 {
325   u3_noun tap = tep;
326 
327   while ( u3_nul != tap ) {
328     c3_c car_c;
329 
330     if ( u3h(tap) >= 127 ) {
331       car_c = '?';
332     } else car_c = u3h(tap);
333 
334     putc(car_c, fil_u);
335     tap = u3t(tap);
336   }
337   u3z(tep);
338 }
339 
340 /* _lo_wall(): dump a wall, old style.  Don't do this.
341 */
342 static void
_lo_wall(u3_noun wol)343 _lo_wall(u3_noun wol)
344 {
345   FILE* fil_u = u3_term_io_hija();
346   u3_noun wal = wol;
347 
348   while ( u3_nul != wal ) {
349     _lo_tape(fil_u, u3k(u3h(wal)));
350 
351     putc(13, fil_u);
352     putc(10, fil_u);
353 
354     wal = u3t(wal);
355   }
356   u3_term_io_loja(0);
357   u3z(wol);
358 }
359 
360 /* u3_lo_tank(): dump single tank.
361 */
362 void
u3_lo_tank(c3_l tab_l,u3_noun tac)363 u3_lo_tank(c3_l tab_l, u3_noun tac)
364 {
365   u3_lo_punt(tab_l, u3nc(tac, u3_nul));
366 }
367 
368 /* u3_lo_punt(): dump tank list.
369 */
370 void
u3_lo_punt(c3_l tab_l,u3_noun tac)371 u3_lo_punt(c3_l tab_l, u3_noun tac)
372 {
373   u3_noun blu   = u3_term_get_blew(0);
374   c3_l    col_l = u3h(blu);
375   u3_noun cat   = tac;
376 
377   //  We are calling nock here, but hopefully need no protection.
378   //
379   while ( c3y == u3r_du(cat) ) {
380     u3_noun wol = u3dc("wash", u3nc(tab_l, col_l), u3k(u3h(cat)));
381 
382     _lo_wall(wol);
383     cat = u3t(cat);
384   }
385   u3z(tac);
386   u3z(blu);
387 }
388 
389 /* u3_lo_sway(): print trace.
390 */
391 void
u3_lo_sway(c3_l tab_l,u3_noun tax)392 u3_lo_sway(c3_l tab_l, u3_noun tax)
393 {
394   u3_noun mok = u3dc("mook", 2, tax);
395 
396   u3_lo_punt(tab_l, u3k(u3t(mok)));
397   u3z(mok);
398 }
399 
400 /* _lo_time(): set time.
401 */
402 static void
_lo_time(void)403 _lo_time(void)
404 {
405   struct timeval tim_tv;
406 
407   gettimeofday(&tim_tv, 0);
408   u3v_time(u3_time_in_tv(&tim_tv));
409 }
410 
411 /* u3_lo_open(): begin callback processing.
412 */
413 void
u3_lo_open(void)414 u3_lo_open(void)
415 {
416   if ( u3C.wag_w & (u3o_debug_ram | u3o_check_corrupt) ) {
417     //
418     //  Assumption: there are no noun roots outside u3A.
419     //
420     u3m_grab(u3_none);
421   }
422 #if 0
423   if ( u3C.wag_w & u3o_debug_cpu ) {
424     struct itimerval itm_u;
425 
426     getitimer(ITIMER_VIRTUAL, &itm_u);
427     fprintf(stderr, "tv_sec %d, tv_usec %d, value %d/%d\r\n",
428                      itm_u.it_interval.tv_sec,
429                      itm_u.it_interval.tv_usec,
430                      itm_u.it_value.tv_sec,
431                      itm_u.it_interval.tv_usec);
432   }
433 #endif
434   _lo_time();
435 }
436 
437 /* u3_lo_shut(): end callback processing.
438 */
439 void
u3_lo_shut(c3_o inn)440 u3_lo_shut(c3_o inn)
441 {
442   // u3m_grab(u3_none);
443 
444   //  process actions
445   //
446   u3_raft_work();
447 
448   // u3_lo_grab("lo_shut b", u3_none);
449 
450   //  update time
451   //
452   _lo_time();
453 
454   // u3_lo_grab("lo_shut c", u3_none);
455 
456   //  for input operations, poll fs (XX not permanent)
457   //  XX remove raty_lead guard
458   //
459   if ( c3y == inn ) {
460     u3_unix_ef_look(c3n);
461     u3_raft_work();
462     _lo_time();
463   }
464 
465   // u3_lo_grab("lo_shut d", u3_none);
466 
467   //  clean shutdown
468   //
469   if ( c3n == u3_Host.liv ) {
470     //  direct save and die
471     //
472     // u3_lo_grab("lo_exit", u3_none);
473     // u3_loom_save(u3A->ent_d);
474     // u3_loom_exit();
475     u3t_damp();
476     u3_lo_exit();
477 
478     //  save a checkpoint before exiting
479     u3e_save();
480     exit(u3_Host.xit_i);
481   }
482   else {
483     //  poll arvo to generate any event binding changes
484     //
485     _lo_poll();
486   }
487 }
488 
489 #if 0
490 //  _lo_bench_noop(): benchmark no-op events.
491 //
492 static void
493 _lo_bench_noop(c3_w num_w)
494 {
495   c3_w i_w;
496 
497   for ( i_w = 0; i_w < num_w; i_w++ ) {
498     u3_reck_plan(u3A, u3nq(u3_blip, c3__term, 1, u3_nul),
499                       u3nc(c3__noop, u3_nul));
500   }
501 
502   u3_raft_work(u3A);
503 }
504 
505 //  _lo_bench_scot_p(): benchmark prettyprint.
506 //
507 static void
508 _lo_bench_scot_p(c3_w num_w)
509 {
510   c3_w i_w;
511 
512   for ( i_w = 0; i_w < num_w; i_w++ ) {
513     u3_noun soc = u3dc("scot", 'p', u3k(u3A->now));
514 
515     u3z(soc);
516   }
517 }
518 
519 //  _lo_bench_slay_p(): benchmark prettyprint.
520 //
521 static void
522 _lo_bench_slay_p(c3_w num_w)
523 {
524   c3_w i_w;
525 
526   for ( i_w = 0; i_w < num_w; i_w++ ) {
527     u3_noun soc = u3dc("scot", 'p', u3k(u3A->now));
528     u3_noun dub = u3do("slay", soc);
529 
530     u3z(dub);
531   }
532 }
533 
534 //  _lo_bench_scot_da(): benchmark prettyprint.
535 //
536 static void
537 _lo_bench_scot_da(c3_w num_w)
538 {
539   c3_w i_w;
540 
541   for ( i_w = 0; i_w < num_w; i_w++ ) {
542     u3_noun soc = u3dc("scot", c3__da, u3k(u3A->now));
543 
544     u3z(soc);
545   }
546 }
547 
548 //  _lo_bench_dec(): benchmark decrement.
549 //
550 static void
551 _lo_bench_dec(c3_w num_w)
552 {
553   c3_w i_w;
554 
555   for ( i_w = 0; i_w < num_w; i_w++ ) {
556     u3_noun soc = u3do("dec", u3k(u3A->now));
557 
558     u3z(soc);
559   }
560 }
561 
562 //  _lo_bench_scot_ud(): benchmark prettyprint.
563 //
564 static void
565 _lo_bench_scot_ud(c3_w num_w)
566 {
567   c3_w i_w;
568 
569   for ( i_w = 0; i_w < num_w; i_w++ ) {
570     u3_noun soc = u3dc("scot", c3__ud, u3k(u3A->now));
571 
572     u3z(soc);
573   }
574 }
575 
576 //  _lo_bench(): lo-tech profiling.
577 //
578 static void
579 _lo_bench(const c3_c* lab_c, void (*fun)(c3_w), c3_w num_w)
580 {
581   u3_noun old, new;
582 
583   uL(fprintf(uH, "bench: %s: start...\n", lab_c));
584   u3_reck_time(u3A);
585   old = u3k(u3A->now);
586 
587   fun(num_w);
588 
589   u3_reck_time(u3A);
590   new = u3k(u3A->now);
591   {
592     c3_w tms_w = (c3_w)u3_time_gap_ms(old, new);
593 
594     if ( tms_w > (10 * num_w) ) {
595       uL(fprintf(uH, "bench: %s*%d: %d ms, %d ms each.\n",
596                       lab_c, num_w, tms_w, (tms_w / num_w)));
597     }
598     else {
599       uL(fprintf(uH, "bench: %s*%d: %d ms, %d us each.\n",
600                       lab_c, num_w, tms_w, ((tms_w * 1000) / num_w)));
601     }
602   }
603 }
604 #endif
605 
606 /*  u3_lo_show(): generic noun print.
607 */
608 void
u3_lo_show(c3_c * cap_c,u3_noun nun)609 u3_lo_show(c3_c* cap_c, u3_noun nun)
610 {
611   u3_noun pav   = u3dc("pave", c3__noun, nun);
612   c3_c*   txt_c = (c3_c*)u3r_tape(pav);
613 
614   fprintf(stderr, "%s: %s\r\n", cap_c, txt_c);
615   u3z(pav);
616   free(txt_c);
617 }
618 
619 static void
_lo_slow()620 _lo_slow()
621 {
622 #if 0
623   _lo_bench("scot %p", _lo_bench_scot_p, 256);
624   _lo_bench("scot %da", _lo_bench_scot_da, 256);
625   _lo_bench("scot %ud", _lo_bench_scot_ud, 256);
626   _lo_bench("slay %p", _lo_bench_slay_p, 256);
627   _lo_bench("noop", _lo_bench_noop, 256);
628 #endif
629 }
630 
631 /* u3_lo_loop(): begin main event loop.
632 */
633 void
u3_lo_loop()634 u3_lo_loop()
635 {
636   uv_loop_t* lup_u = uv_default_loop();
637 
638   u3_Host.lup_u = lup_u;
639 
640   signal(SIGPIPE, SIG_IGN);     //  pipe, schmipe
641   // signal(SIGIO, SIG_IGN);    //  linux is wont to produce for some reason
642 
643   _lo_init();
644 
645   u3_raft_init();
646 
647   if ( _(u3_Host.ops_u.tex) ) {
648     u3t_boff();
649     u3t_damp();
650     u3_lo_exit();
651 
652     fprintf(stderr, "dry run: exit\r\n");
653     exit(0);
654   }
655   else {
656     if ( c3n == u3_Host.ops_u.bat ) {
657       uv_run(u3L, UV_RUN_DEFAULT);
658     }
659   }
660 }
661 
662 /* u3_lo_lead(): actions on promotion to leader.
663 */
664 void
u3_lo_lead(void)665 u3_lo_lead(void)
666 {
667   //  Further server configuration.
668   //
669   {
670     u3_http_ef_bake();
671   }
672 
673   _lo_talk();
674   {
675     u3_unix_ef_look(c3n);
676     u3v_plan(u3nt(u3_blip, c3__ames, u3_nul),
677                u3nc(c3__kick, u3k(u3A->now)));
678   }
679   _lo_poll();
680 
681 #if 0
682   u3_loom_save(u3A->ent_d);
683 
684   u3_Host.sav_u.ent_d = rec_u->ent_d;
685 #endif
686 
687   if ( c3y == u3_Host.ops_u.nuu ) {
688     if ( u3_Host.ops_u.who_c ) {
689       u3_term_ef_ticket(u3_Host.ops_u.who_c, u3_Host.ops_u.tic_c);
690     }
691     u3_term_ef_boil(1);
692   }
693 
694   if ( c3y == u3_Host.ops_u.veb ) {
695     u3_term_ef_verb();
696   }
697 
698 #if 1
699   _lo_slow();
700 #endif
701 }
702 
703 #if 0
704 /* _lo_mark_reck(): mark a reck.
705 */
706 static c3_w
707 _lo_mark_reck(u3_reck* rec_u)
708 {
709   c3_w siz_w = 0;
710   c3_w egg_w;
711 
712   siz_w += u3m_mark_noun(rec_u->ken);
713   siz_w += u3m_mark_noun(rec_u->roc);
714 
715   siz_w += u3m_mark_noun(rec_u->yot);
716   siz_w += u3m_mark_noun(rec_u->now);
717   siz_w += u3m_mark_noun(rec_u->wen);
718   siz_w += u3m_mark_noun(rec_u->sen);
719   siz_w += u3m_mark_noun(rec_u->own);
720   siz_w += u3m_mark_noun(rec_u->roe);
721   siz_w += u3m_mark_noun(rec_u->key);
722 
723   {
724     u3_cart* egg_u;
725 
726     egg_w = 0;
727     for ( egg_u = rec_u->ova.egg_u; egg_u; egg_u = egg_u->nex_u ) {
728       egg_w += u3m_mark_noun(egg_u->vir);
729     }
730     siz_w += egg_w;
731   }
732 #if 0
733   fprintf(stderr, "ken %d, roc %d, yot %d, roe %d, egg %d\r\n",
734                    ken_w, roc_w, yot_w, roe_w, egg_w);
735 #endif
736   return siz_w;
737 }
738 
739 /* _lo_mark(): mark the whole vere system.
740 */
741 static c3_w
742 _lo_mark()
743 {
744   c3_w siz_w;
745 
746   siz_w = u3m_mark_internal();
747   siz_w += _lo_mark_reck(u3_Host.arv_u);
748 
749   return siz_w;
750 }
751 #endif
752 
753 #if 0
754 /* _lo_word(): print a word to the passed stream.
755 */
756 static void
757 _lo_word(FILE* fil_u, c3_w wod_w)
758 {
759   u3_noun top = c3y;
760 
761   if ( wod_w / (1000 * 1000 * 1000) ) {
762     fprintf(fil_u, "%u.", wod_w / (1000 * 1000 * 1000));
763     wod_w %= (1000 * 1000 * 1000);
764     top = c3n;
765   }
766   if ( wod_w / (1000 * 1000) ) {
767     fprintf(fil_u, ((top == c3y) ? "%u." : "%03u."),
768                    wod_w / (1000 * 1000));
769     wod_w %= (1000 * 1000);
770     top = c3n;
771   }
772   if ( wod_w / 1000 ) {
773     fprintf(fil_u, ((top == c3y) ? "%u." : "%03u."), wod_w / 1000);
774     wod_w %= 1000;
775     top = c3n;
776   }
777   fprintf(fil_u, ((top == c3y) ? "%u" : "%03u"), wod_w);
778 }
779 
780 /* u3_lo_grab(): garbage-collect the world, plus roots.
781 */
782 void
783 u3_lo_grab(c3_c* cap_c, u3_noun som, ...)
784 {
785   c3_w siz_w, lec_w;
786 
787   siz_w = _lo_mark();
788   {
789     va_list vap;
790     u3_noun tur;
791 
792     va_start(vap, som);
793 
794     if ( som != u3_none ) {
795       siz_w += u3m_mark_noun(som);
796 
797       while ( u3_none != (tur = va_arg(vap, u3_noun)) ) {
798         siz_w += u3m_mark_noun(tur);
799       }
800     }
801     va_end(vap);
802   }
803   lec_w = u3m_sweep(siz_w);
804 
805   // if ( lec_w || (c3y == u3_Flag_Verbose) )
806   if ( lec_w  || !strcmp("init", cap_c) ) {
807     FILE* fil_u = uH;
808     fprintf(fil_u, "%s: gc: ", cap_c);
809     if ( lec_w ) {
810       _lo_word(fil_u, 4 * lec_w);
811       fprintf(fil_u, " bytes shed; ");
812     }
813     _lo_word(fil_u, 4 * siz_w);
814     uL(fprintf(fil_u, " bytes live\n"));
815 
816 #if 0
817     if ( lec_w ) {
818       uL(fprintf(uH, "zero garbage tolerance!\n"));
819       u3_lo_exit();
820       c3_assert(0);
821       exit(1);
822     }
823 #endif
824   }
825   u3_wire_lan(u3_Wire) = c3y;
826 }
827 #endif
828