ARB
AW_status.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : AW_status.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include <aw_root.hxx>
12 #include <aw_question.hxx>
13 #include <aw_awars.hxx>
14 #include <aw_window.hxx>
15 #include "aw_msg.hxx"
16 #include "aw_status.hxx"
17 
18 #include <arbdbt.h>
19 #include <arb_strbuf.h>
20 #include <arb_sleep.h>
21 #include <SigHandler.h>
22 
23 #include <cerrno>
24 #include <cstdarg>
25 #include <ctime>
26 #include <unistd.h>
27 
28 using namespace std;
29 
30 #define FD_SET_TYPE
31 
32 // Globals
33 #define AW_GAUGE_SIZE 40 // length of gauge display (in characters)
34 #define AW_GAUGE_GRANULARITY 1000 // how fine the gauge is transported to status (no of steps) [old value = 255]
35 
36 #define AW_GAUGE_PERCENT(pc) ((pc)*AW_GAUGE_GRANULARITY/100)
37 
38 #define AW_STATUS_KILL_DELAY 4000 // in ms
39 #define AW_STATUS_LISTEN_DELAY 300 // in ms
40 #define AW_STATUS_HIDE_DELAY 60 // in sec
41 #define AW_STATUS_PIPE_CHECK_DELAY 1000*2 // in ms (a pipe check every 2 seconds)
42 
43 #define AWAR_STATUS "tmp/status/"
44 #define AWAR_STATUS_TITLE AWAR_STATUS "title"
45 #define AWAR_STATUS_TEXT AWAR_STATUS "text"
46 #define AWAR_STATUS_GAUGE AWAR_STATUS "gauge"
47 #define AWAR_STATUS_ELAPSED AWAR_STATUS "elapsed"
48 
49 #define AW_MESSAGE_LINES 500
50 
51 #if defined(DEBUG)
52 
53 // ARB_LOGGING should always be undefined in SVN version!
54 // #define ARB_LOGGING
55 // #define TRACE_STATUS // // // enable debug output for status window (which runs forked!)
56 // #define TRACE_STATUS_MORE // // enable more debug output
57 // #define PIPE_DEBUGGING // // enable debug output for pipes (for write commands)
58 
59 #endif // DEBUG
60 
62  // messages send from status-process to main-process :
65  // messages send from main-process to status-process :
73 };
74 
75 #define AW_EST_BUFFER 5
76 
77 struct aw_stg_struct {
78  int fd_to[2];
79  int fd_from[2];
80  bool mode;
81  int hide;
82  int hide_delay; // in seconds
83  pid_t pid;
84  bool is_child; // true in status window process
86  int err_no;
90  char *lines[AW_MESSAGE_LINES];
91  bool need_refresh; // if true -> message list needs to refresh
95  time_t last_start; // time of last status start
97  long last_estimation[AW_EST_BUFFER];
99 };
100 
102  { 0, 0 }, // fd_to
103  { 0, 0 }, // fd_from
104  AW_STATUS_OK, // mode
105  0, // hide
106  0, // hide_delay
107  0, // pid
108  false, // is_child
109  0, // pipe_broken
110  0, // errno
111  NULp, // aws
112  NULp, // awm
113  false, // status_initialized
114  { NULp, NULp, NULp }, // lines
115  false, // need_refresh
116  0, // last_refresh_time
117  0, // last_message_time
118  0, // local_message
119  0, // last_start
120  0, // last_est_count
121  { 0 }, // last_estimation
122  -1, // last_used_est
123 };
124 
125 // timeouts :
126 
127 #define POLL_TIMEOUT 0 // idle wait POLL_TIMEOUT microseconds before returning EOF when polling
128 
129 #if defined(DEBUG)
130 #define WRITE_TIMEOUT 1000 // 1 second for debug version (short because it always reaches timeout inside debugger)
131 #else
132 #define WRITE_TIMEOUT 10000 // 10 seconds for release
133 #endif // DEBUG
134 
135 static void mark_pipe_broken(int err_no) {
136 #if defined(PIPE_DEBUGGING)
137  if (aw_stg.pipe_broken != 0) {
138  fprintf(stderr,
139  "Pipe already broken in mark_pipe_broken(); pipe_broken=%i aw_stg.errno=%i errno=%i\n",
140  aw_stg.pipe_broken, aw_stg.err_no, err_no);
141  }
142 
143  fprintf(stderr, "Marking pipe as broken (errno=%i)\n", err_no);
144 #endif // PIPE_DEBUGGING
145 
146  aw_stg.err_no = err_no;
147  aw_stg.pipe_broken = 1;
148 
149  static bool error_shown = false;
150  if (!error_shown) {
151  fprintf(stderr,
152  "******************************************************************\n"
153  "The connection to the status window was blocked unexpectedly!\n"
154  "This happens if you run the program from inside the debugger\n"
155  "or when the process is blocked longer than %5.2f seconds.\n"
156  "Further communication with the status window is suppressed.\n"
157  "******************************************************************\n"
158  , WRITE_TIMEOUT/1000.0);
159  }
160 }
161 
162 static ssize_t safe_write(int fd, const char *buf, int count) {
163  if (aw_stg.pipe_broken != 0) {
164 #if defined(PIPE_DEBUGGING)
165  fprintf(stderr, "pipe is broken -- avoiding write of %i bytes\n", count);
166 #endif // PIPE_DEBUGGING
167  return -1;
168  }
169 
170  aw_assert(count>0); // write nothing - bad idea
171 
172  ssize_t result = -1;
173  {
174  fd_set set;
175  struct timeval timeout;
176  timeout.tv_sec = WRITE_TIMEOUT/1000;
177  timeout.tv_usec = WRITE_TIMEOUT%1000;
178 
179  FD_ZERO(&set);
180  FD_SET(fd, &set);
181 
182  int sel_res = select(fd+1, NULp, &set, NULp, &timeout);
183 
184  if (sel_res == -1) {
185  fprintf(stderr, "select (before write) returned error (errno=%i)\n", errno);
186  exit(EXIT_FAILURE);
187  }
188 
189  bool pipe_would_block = !FD_ISSET(fd, &set);
190 
191 #if defined(PIPE_DEBUGGING)
192  fprintf(stderr, "select returned %i, pipe_would_block=%i (errno=%i)\n",
193  sel_res, int(pipe_would_block), errno);
194 
195  if (pipe_would_block) {
196  fprintf(stderr, " Avoiding to write to pipe (because it would block!)\n");
197  }
198  else {
199  fprintf(stderr, " Write %i bytes to pipe.\n", count);
200  }
201 #endif // PIPE_DEBUGGING
202 
203  if (!pipe_would_block) {
204  result = write(fd, buf, count);
205  }
206  }
207 
208  if (result<0) {
209  mark_pipe_broken(errno);
210  }
211  else if (result != count) {
212 #if defined(PIPE_DEBUGGING)
213  fprintf(stderr, "write wrote %i bytes instead of %i as requested.\n", result, count);
214 #endif // PIPE_DEBUGGING
215  mark_pipe_broken(0);
216  }
217 
218  return result;
219 }
220 
221 static void aw_status_write(int fd, int cmd) {
222  char buf = cmd;
223  safe_write(fd, &buf, 1);
224 }
225 
226 static int aw_status_read_byte(int fd, int poll_flag) {
227  /* read one byte from the pipe,
228  * if poll ==1 then don't wait for any data, but return EOF */
229  int erg;
230  unsigned char buffer[2];
231 
232  if (poll_flag) {
233  fd_set set;
234  struct timeval timeout;
235  timeout.tv_sec = POLL_TIMEOUT/1000;
236  timeout.tv_usec = POLL_TIMEOUT%1000;
237 
238  FD_ZERO (&set);
239  FD_SET (fd, &set);
240 
241  erg = select(FD_SETSIZE, FD_SET_TYPE &set, NULp, NULp, &timeout);
242  if (erg == 0) return EOF;
243  }
244  erg = read(fd, (char *)&(buffer[0]), 1);
245  if (erg<=0) {
246  // process died
247  fprintf(stderr, "father died, now i kill myself\n");
248  exit(EXIT_FAILURE);
249  }
250  return buffer[0];
251 }
252 
253 static int aw_status_read_int(int fd, int poll_flag) {
254  /* read one integer from the pipe,
255  * if poll ==1 then don't wait for any data, but return EOF */
256 
257  int erg;
258 
259  if (poll_flag) {
260  fd_set set;
261  struct timeval timeout;
262  timeout.tv_sec = POLL_TIMEOUT/1000;
263  timeout.tv_usec = POLL_TIMEOUT%1000;
264 
265  FD_ZERO (&set);
266  FD_SET (fd, &set);
267 
268  erg = select(FD_SETSIZE, FD_SET_TYPE &set, NULp, NULp, &timeout);
269  if (erg == 0) return EOF;
270  }
271  union {
272  unsigned char buffer[sizeof(int)+1];
273  int as_int;
274  } input;
275 
276  erg = read(fd, input.buffer, sizeof(int));
277  if (erg<=0) { // process died
278  fprintf(stderr, "father died, now i kill myself\n");
279  exit(EXIT_FAILURE);
280  }
281  return input.as_int;
282 }
283 
284 static int aw_status_read_command(int fd, int poll_flag, char*& str, int *gaugePtr = NULp) {
285  char buffer[1024];
286  int cmd = aw_status_read_byte(fd, poll_flag);
287 
288  if (cmd == AW_STATUS_CMD_TEXT ||
289  cmd == AW_STATUS_CMD_OPEN ||
290  cmd == AW_STATUS_CMD_NEW_TITLE ||
291  cmd == AW_STATUS_CMD_MESSAGE) {
292  char *p = buffer;
293  int c;
294  for (
295  c = aw_status_read_byte(fd, 0);
296  c;
297  c = aw_status_read_byte(fd, 0)) {
298  *(p++) = c;
299  }
300  *(p++) = c;
301 
302  str = strdup(buffer);
303  }
304  else if (cmd == AW_STATUS_CMD_GAUGE) {
305  int gauge = aw_status_read_int(fd, 0);
306  if (gaugePtr) *gaugePtr = gauge;
307 
308  char *p = buffer;
309  int i = 0;
310 
311  int rough_gauge = (gauge*AW_GAUGE_SIZE)/AW_GAUGE_GRANULARITY;
312  for (; i<rough_gauge && i<AW_GAUGE_SIZE; ++i) *p++ = '*';
313  for (; i<AW_GAUGE_SIZE; ++i) *p++ = '-';
314 
315  if (rough_gauge<AW_GAUGE_SIZE) {
316  int fine_gauge = (gauge*AW_GAUGE_SIZE*4)/AW_GAUGE_GRANULARITY;
317  buffer[rough_gauge] = "-\\|/"[fine_gauge%4];
318  }
319 
320  *p = 0;
321  str = strdup(buffer);
322  }
323  else {
324  str = NULp;
325  }
326  return cmd;
327 }
328 
329 static void aw_status_check_pipe() {
330  if (getppid() <= 1) {
331 #if defined(TRACE_STATUS)
332  fprintf(stderr, "Terminating status process.\n");
333 #endif // TRACE_STATUS
334  exit(EXIT_FAILURE);
335  }
336 }
337 
338 static void aw_status_wait_for_open(int fd) {
339  char *str = NULp;
340  int cmd;
341  int erg;
342 
343  for (cmd = 0; cmd != AW_STATUS_CMD_INIT;) {
344  for (erg = 0; !erg;) {
345  struct timeval timeout;
346  timeout.tv_sec = AW_STATUS_PIPE_CHECK_DELAY / 1000;
347  timeout.tv_usec = AW_STATUS_PIPE_CHECK_DELAY % 1000;
348 
349  fd_set set;
350 
351  FD_ZERO (&set);
352  FD_SET (fd, &set);
353 
354 #if defined(TRACE_STATUS)
355  fprintf(stderr, "Waiting for status open command..\n"); fflush(stderr);
356 #endif // TRACE_STATUS
357  erg = select(FD_SETSIZE, FD_SET_TYPE &set, NULp, NULp, &timeout);
358  if (!erg) aw_status_check_pipe(); // time out
359  }
360  freenull(str);
361  cmd = aw_status_read_command(fd, 0, str);
362  }
363  aw_stg.mode = AW_STATUS_OK;
364  freenull(str);
365 
366 #if defined(TRACE_STATUS)
367  fprintf(stderr, "OK got status open command!\n"); fflush(stderr);
368 #endif // TRACE_STATUS
369 }
370 
371 
373  if (aw_stg.hide) {
374  aw_stg.aws->show();
375  aw_stg.hide = 0;
376  }
377  return 0; // do not recall
378 }
379 
380 static void aw_status_hide(AW_window *aws) {
381  aw_stg.hide = 1;
382  aws->hide();
383 
384  // install timer event
385  aws->get_root()->add_timed_callback(aw_stg.hide_delay*1000, makeTimedCallback(aw_status_timer_hide_event));
386 
387  // increase hide delay for next press of hide button
388  if (aw_stg.hide_delay < (60*60)) { // max hide delay is 1 hour
389  aw_stg.hide_delay *= 3; // initial: 60sec -> 3min -> 9min -> 27min -> 60min (max)
390  }
391  else {
392  aw_stg.hide_delay = 60*60;
393  }
394 }
395 
396 
397 static unsigned aw_status_timer_event(AW_root *awr) {
398 #if defined(TRACE_STATUS_MORE)
399  fprintf(stderr, "in aw_status_timer_event\n"); fflush(stdout);
400 #endif // TRACE_STATUS_MORE
401  if (aw_stg.mode == AW_STATUS_ABORT) {
402  int action = aw_question(NULp,
403  "Couldn't quit properly in time.\n"
404  "Now you can either\n"
405  "- wait again (recommended),\n"
406  "- kill the whole application(!) or\n"
407  "- continue.",
408  "Wait again,Kill application!,Continue");
409 
410  switch (action) {
411  case 0:
412  break;
413  case 1: {
414  char buf[255];
415  sprintf(buf, "kill -9 %i", aw_stg.pid);
417  exit(EXIT_SUCCESS);
418  }
419  case 2: {
420  char *title = awr->awar(AWAR_STATUS_TITLE)->read_string();
421  char *subtitle = awr->awar(AWAR_STATUS_TEXT)->read_string();
422 
423  aw_message(GBS_global_string("If you think the process should be made abortable,\n"
424  "please send the following information to devel@arb-home.de:\n"
425  "\n"
426  "Calculation not abortable from status window.\n"
427  "Title: %s\n"
428  "Subtitle: %s\n",
429  title, subtitle));
430  aw_stg.mode = AW_STATUS_OK;
431 
432  free(subtitle);
433  free(title);
434  break;
435  }
436  }
437  }
438  return 0; // do not recall
439 }
440 
441 static void aw_status_kill(AW_window *aws) {
442  if (aw_stg.mode == AW_STATUS_ABORT) {
444  if (aw_stg.mode == AW_STATUS_OK) { // continue
445  return;
446  }
447  }
448  else {
449  if (!aw_ask_sure("aw_status_kill", "Are you sure to abort running calculation?")) {
450  return; // don't abort
451  }
452  aw_stg.mode = AW_STATUS_ABORT;
453  }
454  aw_status_write(aw_stg.fd_from[1], aw_stg.mode);
455 
456  if (aw_stg.mode == AW_STATUS_ABORT) {
457 #if defined(TRACE_STATUS_MORE)
458  fprintf(stderr, "add aw_status_timer_event with delay = %i\n", AW_STATUS_KILL_DELAY); fflush(stdout);
459 #endif // TRACE_STATUS_MORE
460  aws->get_root()->add_timed_callback(AW_STATUS_KILL_DELAY, makeTimedCallback(aw_status_timer_event)); // install timer event
461  }
462 }
463 
466 
467  for (int i = AW_MESSAGE_LINES-1; i>=0; i--) {
468  if (aw_stg.lines[i]) {
469  msgs.cat(aw_stg.lines[i]);
470  msgs.put('\n');
471  }
472  };
473 
475 
476  aw_stg.need_refresh = false;
477  aw_stg.last_refresh_time = aw_stg.last_message_time;
478 }
479 
481  free(aw_stg.lines[0]);
482  for (int i = 1; i< AW_MESSAGE_LINES; i++) {
483  aw_stg.lines[i-1] = aw_stg.lines[i];
484  };
485 
486  time_t t = time(NULp);
487  struct tm *lt = localtime(&t);
488  const char *lf = strchr(message, '\n');
489  char *copy = NULp;
490 
491  if (lf) { // contains linefeeds
492  const int indentation = 10;
493  int count = 1;
494 
495  while (lf) { lf = strchr(lf+1, '\n'); ++count; }
496 
497  int newsize = strlen(message)+count*indentation+1;
498  ARB_alloc(copy, newsize);
499 
500  lf = strchr(message, '\n');
501  char *cp = copy;
502  while (lf) {
503  int len = lf-message;
504  memcpy(cp, message, len+1);
505  cp += len+1;
506  memset(cp, ' ', indentation);
507  cp += indentation;
508 
509  message = lf+1;
510  lf = strchr(message, '\n');
511  }
512 
513  strcpy(cp, message);
514 
515  message = copy;
516  }
517 
518  aw_stg.lines[AW_MESSAGE_LINES-1] = GBS_global_string_copy("%02i:%02i.%02i %s",
519  lt->tm_hour, lt->tm_min, lt->tm_sec,
520  message);
521  aw_stg.last_message_time = t;
522  free(copy);
523 
524  aw_stg.need_refresh = true;
525 }
526 
527 static void aw_insert_message_in_tmp_message(AW_root *awr, const char *message) {
530 }
531 
532 inline const char *sec2disp(long seconds) {
533  static char buffer[50];
534 
535  if (seconds<0) seconds = 0;
536  if (seconds<100) {
537  sprintf(buffer, "%li sec", seconds);
538  }
539  else {
540  long minutes = (seconds+30)/60;
541 
542  if (minutes<60) {
543  sprintf(buffer, "%li min", minutes);
544  }
545  else {
546  long hours = minutes/60;
547  minutes = minutes%60;
548 
549  sprintf(buffer, "%lih:%02li min", hours, minutes);
550  }
551  }
552  return buffer;
553 }
554 
555 #ifdef ARB_LOGGING
556 static void aw_status_append_to_log(const char* str) {
557  static const char *logname = 0;
558  if (!logname) {
559  logname = GBS_global_string_copy("%s/arb.log", GB_getenvHOME());
560  }
561 
562  int fd = open(logname, O_WRONLY|O_APPEND);
563  if (fd == -1) fd = open(logname, O_CREAT|O_WRONLY|O_APPEND, S_IWUSR | S_IRUSR);
564  if (fd == -1) return;
565 
566  write(fd, str, strlen(str));
567  write(fd, "\n", 1);
568  close(fd);
569 }
570 #endif
571 
572 
573 static unsigned aw_status_timer_listen_event(AW_root *awr) {
574  static int delay = AW_STATUS_LISTEN_DELAY;
575  int cmd;
576  char *str = NULp;
577  int gaugeValue = 0;
578 
579 #if defined(TRACE_STATUS_MORE)
580  fprintf(stderr, "in aw_status_timer_listen_event (aw_stg.is_child=%i)\n", (int)aw_stg.is_child); fflush(stdout);
581 #endif // TRACE_STATUS_MORE
582 
583  if (aw_stg.need_refresh && aw_stg.last_refresh_time != aw_stg.last_message_time) {
584  aw_refresh_tmp_message_display(awr); // force refresh each second
585  }
586 
587  cmd = aw_status_read_command(aw_stg.fd_to[0], 1, str, &gaugeValue);
588  if (cmd == EOF) {
590  delay = delay*3/2+1; // wait a longer time
591  if (aw_stg.need_refresh) aw_refresh_tmp_message_display(awr); // and do the refresh here
592  }
593  else {
594  delay = delay*2/3+1; // shorten time (was *2/3+1)
595  }
596  char *gauge = NULp;
597  while (cmd != EOF) {
598  switch (cmd) {
599  case AW_STATUS_CMD_OPEN:
600 #if defined(TRACE_STATUS)
601  fprintf(stderr, "received AW_STATUS_CMD_OPEN\n"); fflush(stdout);
602 #endif // TRACE_STATUS
603  aw_stg.mode = AW_STATUS_OK;
604  aw_stg.last_start = time(NULp);
605  aw_stg.last_est_count = 0;
606  aw_stg.last_used_est = -1;
607  aw_stg.aws->show();
608  aw_stg.hide = 0;
610 
611 #if defined(ARB_LOGGING)
612  aw_status_append_to_log("----------------------------");
613 #endif // ARB_LOGGING
614  awr->awar(AWAR_STATUS_TITLE)->write_string(str);
615  awr->awar(AWAR_STATUS_GAUGE)->write_string("----------------------------");
618  cmd = EOF;
619  freenull(str);
620  continue; // break while loop
621 
622  case AW_STATUS_CMD_CLOSE:
623 #if defined(TRACE_STATUS)
624  fprintf(stderr, "received AW_STATUS_CMD_CLOSE\n"); fflush(stdout);
625 #endif // TRACE_STATUS
626  aw_stg.mode = AW_STATUS_OK;
627  aw_stg.aws->hide();
628  break;
629 
630  case AW_STATUS_CMD_TEXT:
631 #if defined(TRACE_STATUS)
632  fprintf(stderr, "received AW_STATUS_CMD_TEXT\n"); fflush(stdout);
633 #endif // TRACE_STATUS
634 #if defined(ARB_LOGGING)
635  aw_status_append_to_log(str);
636 #endif // ARB_LOGGING
637  awr->awar(AWAR_STATUS_TEXT)->write_string(str);
638  break;
639 
641 #if defined(TRACE_STATUS)
642  fprintf(stderr, "received AW_STATUS_CMD_NEW_TITLE\n"); fflush(stdout);
643 #endif // TRACE_STATUS
644 #if defined(ARB_LOGGING)
645  aw_status_append_to_log(str);
646 #endif // ARB_LOGGING
647  awr->awar(AWAR_STATUS_TITLE)->write_string(str);
648  break;
649 
650  case AW_STATUS_CMD_GAUGE: {
651 #if defined(TRACE_STATUS)
652  fprintf(stderr, "received AW_STATUS_CMD_GAUGE\n"); fflush(stdout);
653 #endif // TRACE_STATUS
654 
655  reassign(gauge, str);
656 
657  if (gaugeValue>0) {
658  long sec_elapsed = time(NULp)-aw_stg.last_start;
659  long sec_estimated = (sec_elapsed*AW_GAUGE_GRANULARITY)/gaugeValue; // guess overall time
660 
661 #define PRINT_MIN_GAUGE AW_GAUGE_PERCENT(2)
662 
663  char buffer[200];
664  int off = 0;
665  off += sprintf(buffer+off, "%i%% ", gaugeValue*100/AW_GAUGE_GRANULARITY);
666  off += sprintf(buffer+off, "Elapsed: %s ", sec2disp(sec_elapsed));
667 
668  // rotate estimations
669  memmove(aw_stg.last_estimation, aw_stg.last_estimation+1, sizeof(aw_stg.last_estimation[0])*(AW_EST_BUFFER-1));
670  aw_stg.last_estimation[AW_EST_BUFFER-1] = sec_estimated;
671 
672  if (aw_stg.last_est_count == AW_EST_BUFFER) { // now we can estimate!
673  long used_estimation = 0;
674  int i;
675 
676  for (i = 0; i<AW_EST_BUFFER; ++i) {
677  used_estimation += aw_stg.last_estimation[i];
678  }
679  used_estimation /= AW_EST_BUFFER;
680 
681  if (aw_stg.last_used_est != -1) {
682  long diff = labs(aw_stg.last_used_est-used_estimation);
683  if (diff <= 1) { used_estimation = aw_stg.last_used_est; } // fake away low frequency changes
684  }
685 
686  long sec_rest = used_estimation-sec_elapsed;
687  off += sprintf(buffer+off, "Rest: %s", sec2disp(sec_rest));
688  aw_stg.last_used_est = used_estimation;
689  }
690  else {
691  aw_stg.last_est_count++;
692  off += sprintf(buffer+off, "Rest: ???");
693  }
694 
695  awr->awar(AWAR_STATUS_ELAPSED)->write_string(buffer);
696 
697 #if defined(TRACE_STATUS)
698  fprintf(stderr, "gauge=%i\n", gaugeValue); fflush(stdout);
699 #endif // TRACE_STATUS
700  }
701  else if (gaugeValue == 0) { // restart timer
702  aw_stg.last_start = time(NULp);
703  aw_stg.last_est_count = 0;
704  aw_stg.last_used_est = 0;
705 #if defined(TRACE_STATUS)
706  fprintf(stderr, "reset status timer (gauge=0)\n"); fflush(stdout);
707 #endif // TRACE_STATUS
708  }
709  break;
710  }
712 #if defined(TRACE_STATUS)
713  fprintf(stderr, "received AW_STATUS_CMD_MESSAGE\n"); fflush(stdout);
714 #endif // TRACE_STATUS
715 #if defined(ARB_LOGGING)
716  aw_status_append_to_log(str);
717 #endif // ARB_LOGGING
718  aw_stg.awm->activate();
720  break;
721 
722  default:
723  break;
724  }
725  freenull(str);
726  cmd = aw_status_read_command(aw_stg.fd_to[0], 1, str, &gaugeValue);
727  }
728  freenull(str);
729 
730 #if defined(TRACE_STATUS_MORE)
731  fprintf(stderr, "exited while loop\n"); fflush(stdout);
732 #endif // TRACE_STATUS_MORE
733 
734  if (gauge) {
735  awr->awar(AWAR_STATUS_GAUGE)->write_string(gauge);
736  free(gauge);
737  }
739  else if (delay<0) delay = 0;
740 #if defined(TRACE_STATUS_MORE)
741  fprintf(stderr, "add aw_status_timer_listen_event with delay = %i\n", delay); fflush(stdout);
742 #endif // TRACE_STATUS_MORE
743  aw_assert(delay>0);
744  return delay;
745 }
746 
748  AW_root *awr = aww->get_root();
749  for (int i = 0; i< AW_MESSAGE_LINES; i++) freenull(aw_stg.lines[i]);
751 }
752 
754  aw_clear_message_cb(aww);
755  AW_POPDOWN(aww);
756 }
757 
758 static void create_status_awars(AW_root *aw_root) {
759  aw_root->awar_string(AWAR_STATUS_TITLE, "------------------------------------");
760  aw_root->awar_string(AWAR_STATUS_TEXT, "");
761  aw_root->awar_string(AWAR_STATUS_GAUGE, "------------------------------------");
762  aw_root->awar_string(AWAR_STATUS_ELAPSED, "");
763  aw_root->awar_string(AWAR_ERROR_MESSAGES, "");
764 }
765 
767  // fork status window.
768  // Note: call this function once as early as possible
769 
770  aw_assert(aw_stg.pid == 0); // do not init status twice!
771  aw_assert(!AW_root::SINGLETON); // aw_initstatus has to be called before constructing AW_root
772  aw_assert(GB_open_DBs() == 0); // aw_initstatus has to be called before opening the first ARB-DB
773 
774  int error = pipe(aw_stg.fd_to);
775  if (error) GBK_terminate("Cannot create socketpair [1]");
776  error = pipe(aw_stg.fd_from);
777  if (error) GBK_terminate("Cannot create socketpair [2]");
778 
779  aw_stg.pid = getpid();
780  GB_install_pid(1);
781  pid_t clientid = fork();
782 
783  if (clientid) { // i am the father
784 #if defined(TRACE_STATUS)
785  fprintf(stderr, "Forked status! (i am the father)\n"); fflush(stderr);
786 #endif // TRACE_STATUS
787  return;
788  }
789  else {
790  GB_install_pid(1);
791 
792 #if defined(TRACE_STATUS)
793  fprintf(stderr, "Forked status! (i am the child)\n"); fflush(stderr);
794 #endif // TRACE_STATUS
795 
796  aw_stg.is_child = true; // mark as child
797 
798  GB_shell shell;
799  AW_root *aw_root = new AW_root("status.arb", "ARB_STATUS", true, new NullTracker); // uses_pix_res("icons/ARB_STATUS.xpm"); see ../SOURCE_TOOLS/check_resources.pl@uses_pix_res
800  create_status_awars(aw_root);
801 
802  AW_window_simple *aws = new AW_window_simple;
803  aws->init(aw_root, "STATUS_BOX", "STATUS BOX");
804  aws->load_xfig("status.fig");
805 
806  aws->button_length(AW_GAUGE_SIZE+4);
807  aws->at("Titel");
808  aws->create_button(NULp, AWAR_STATUS_TITLE);
809 
810  aws->at("Text");
811  aws->create_button(NULp, AWAR_STATUS_TEXT);
812 
813  aws->at("Gauge");
814  aws->create_button(NULp, AWAR_STATUS_GAUGE);
815 
816  aws->at("elapsed");
817  aws->create_button(NULp, AWAR_STATUS_ELAPSED);
818 
819  aws->at("Hide");
820  aws->callback(aw_status_hide);
821  aws->create_button("HIDE", "Hide", "h");
822 
823  aws->at("Kill");
824  aws->callback(aw_status_kill);
825  aws->create_button("ABORT", "Abort", "k");
826 
827  aw_stg.hide = 0;
828  aw_stg.aws = aws;
829 
830  AW_window_simple *awm = new AW_window_simple;
831  awm->init(aw_root, "MESSAGE_BOX", "MESSAGE BOX");
832  awm->load_xfig("message.fig");
833 
834  awm->at("Message");
835  awm->create_text_field(AWAR_ERROR_MESSAGES, 10, 2);
836 
837  awm->at("Hide");
838  awm->callback(AW_POPDOWN);
839  awm->create_button("HIDE", "Hide", "h");
840 
841  awm->at("Clear");
842  awm->callback(aw_clear_message_cb);
843  awm->create_button("CLEAR", "Clear", "C");
844 
845  awm->at("HideNClear");
846  awm->callback(aw_clear_and_hide_message_cb);
847  awm->create_button("HIDE_CLEAR", "Ok", "O");
848 
849  aw_stg.awm = awm;
850 
851 #if defined(TRACE_STATUS)
852  fprintf(stderr, "Created status window!\n"); fflush(stderr);
853 #endif // TRACE_STATUS
854 
855  aw_status_wait_for_open(aw_stg.fd_to[0]);
856 
857  // install callback
858  aws->get_root()->add_timed_callback_never_disabled(30, makeTimedCallback(aw_status_timer_listen_event)); // use short delay for first callback
859 
860  // do NOT AWT_install_cb_guards here!
861  aw_root->main_loop(); // never returns
862  }
863 }
864 
865 static void status_write_cmd_and_text(StatusCommand cmd, const char *text, int textlen) {
866  aw_status_write(aw_stg.fd_to[1], cmd);
867  safe_write(aw_stg.fd_to[1], text, textlen+1);
868 }
869 static void status_write_cmd_and_text(StatusCommand cmd, const char *text) {
870  if (!text) text = "";
871  status_write_cmd_and_text(cmd, text, strlen(text));
872 }
873 
874 void aw_openstatus(const char *title) {
875  aw_stg.mode = AW_STATUS_OK;
876  if (!aw_stg.status_initialized) {
877  aw_stg.status_initialized = true;
879  }
881 }
882 
885 }
886 
887 void aw_status_title(const char *new_title) {
889 }
890 void aw_status_subtitle(const char *text) {
892 }
893 
894 void aw_status_gauge(double gauge) {
895  static int last_val = -1;
896  int val = (int)(gauge*AW_GAUGE_GRANULARITY);
897 
898  if (val != last_val) {
899  if (val>0 || gauge == 0.0) { // only write 0 if gauge really is 0 (cause 0 resets the timer)
900  aw_assert(gauge <= 1.0); // please fix the gauge calculation in caller!
902  safe_write(aw_stg.fd_to[1], (char*)&val, sizeof(int));
903  }
904  last_val = val;
905  }
906 }
907 
909  if (aw_stg.mode != AW_STATUS_ABORT) {
910  // check if user has pressed the 'Abort' button
911  static ARB_timestamp last_check;
912  if (last_check.sec_since() >= 1) { // perform check not more often than every second!
913  char *str = NULp;
914  for (int cmd = 0; cmd != EOF; cmd = aw_status_read_command(aw_stg.fd_from[0], 1, str)) {
915  freenull(str);
916  if (cmd == AW_STATUS_ABORT) aw_stg.mode = AW_STATUS_ABORT;
917  }
918  last_check.update();
919  }
920  }
921  return aw_stg.mode;
922 }
923 
924 // -------------------
925 // aw_message
926 
928  aw_stg.local_message = 1;
929 }
930 
931 
932 void aw_message(const char *msg) {
933  aw_assert(!RUNNING_TEST()); // aw_message hangs when called from nightly builds
934 #if defined(DEBUG)
935  printf("aw_message: '%s'\n", msg);
936 #endif // DEBUG
937  if (aw_stg.local_message) {
939  }
940  else {
941  if (!aw_stg.status_initialized) {
942  aw_stg.status_initialized = true;
944  }
946  }
947 }
948 
GB_ERROR GBK_system(const char *system_command)
Definition: arb_msg.cxx:519
#define FD_SET_TYPE
Definition: AW_status.cxx:30
#define AW_STATUS_PIPE_CHECK_DELAY
Definition: AW_status.cxx:41
string result
static ssize_t safe_write(int fd, const char *buf, int count)
Definition: AW_status.cxx:162
int fd_from[2]
Definition: AW_status.cxx:79
static void status_write_cmd_and_text(StatusCommand cmd, const char *text, int textlen)
Definition: AW_status.cxx:865
#define AW_STATUS_HIDE_DELAY
Definition: AW_status.cxx:40
static aw_stg_struct aw_stg
Definition: AW_status.cxx:101
void aw_openstatus(const char *title)
Definition: AW_status.cxx:874
#define AWAR_STATUS_GAUGE
Definition: AW_status.cxx:46
#define AW_GAUGE_SIZE
Definition: AW_status.cxx:33
#define AW_GAUGE_GRANULARITY
Definition: AW_status.cxx:34
#define AWAR_STATUS_TITLE
Definition: AW_status.cxx:44
static void aw_status_hide(AW_window *aws)
Definition: AW_status.cxx:380
void aw_status_title(const char *new_title)
Definition: AW_status.cxx:887
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
const char * title
Definition: readseq.c:22
static int aw_status_read_byte(int fd, int poll_flag)
Definition: AW_status.cxx:226
STL namespace.
void AW_POPDOWN(AW_window *window)
Definition: AW_window.cxx:52
int GB_open_DBs(void)
Definition: arbdb.cxx:516
void cat(const char *from)
Definition: arb_strbuf.h:158
void add_timed_callback(int ms, const TimedCallback &tcb)
Definition: AW_root.cxx:538
static void aw_status_write(int fd, int cmd)
Definition: AW_status.cxx:221
#define EXIT_SUCCESS
Definition: arb_a2ps.c:154
bool need_refresh
Definition: AW_status.cxx:91
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
long sec_since() const
Definition: arb_sleep.h:117
void activate()
Definition: aw_window.hxx:354
void aw_closestatus()
Definition: AW_status.cxx:883
StatusCommand
Definition: AW_status.cxx:61
void update()
Definition: arb_sleep.h:109
AW_window * aws
Definition: AW_status.cxx:87
static AW_root * SINGLETON
Definition: aw_root.hxx:102
void show()
Definition: AW_window.cxx:1658
static int diff(int v1, int v2, int v3, int v4, int st, int en)
Definition: ClustalV.cxx:534
void aw_clear_message_cb(AW_window *aww)
Definition: AW_status.cxx:747
#define AWAR_STATUS_TEXT
Definition: AW_status.cxx:45
fflush(stdout)
static unsigned aw_status_timer_event(AW_root *awr)
Definition: AW_status.cxx:397
static void mark_pipe_broken(int err_no)
Definition: AW_status.cxx:135
static unsigned aw_status_timer_hide_event(AW_root *)
Definition: AW_status.cxx:372
GB_ERROR GB_install_pid(int mode)
Definition: adcomm.cxx:1957
#define AW_STATUS_KILL_DELAY
Definition: AW_status.cxx:38
TYPE * ARB_alloc(size_t nelem)
Definition: arb_mem.h:56
const char * sec2disp(long seconds)
Definition: AW_status.cxx:532
bool status_initialized
Definition: AW_status.cxx:89
static GB_CSTR GB_getenvHOME()
Definition: adsocket.cxx:549
static void aw_status_kill(AW_window *aws)
Definition: AW_status.cxx:441
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:463
#define AW_STATUS_LISTEN_DELAY
Definition: AW_status.cxx:39
#define aw_assert(bed)
Definition: aw_position.hxx:29
long last_estimation[AW_EST_BUFFER]
Definition: AW_status.cxx:97
void message(char *errortext)
static void error(const char *msg)
Definition: mkptypes.cxx:96
#define WRITE_TIMEOUT
Definition: AW_status.cxx:132
#define AW_EST_BUFFER
Definition: AW_status.cxx:75
virtual void init(AW_root *root, const char *wid, const char *windowname, int width, int height)
void aw_status_subtitle(const char *text)
Definition: AW_status.cxx:890
long last_est_count
Definition: AW_status.cxx:96
char * read_string() const
Definition: AW_awar.cxx:201
static void aw_insert_message_in_tmp_message_delayed(const char *message)
Definition: AW_status.cxx:480
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
#define RUNNING_TEST()
Definition: arb_assert.h:278
int fd_to[2]
Definition: AW_status.cxx:78
time_t last_start
Definition: AW_status.cxx:95
#define EXIT_FAILURE
Definition: arb_a2ps.c:157
static AW_window_menu_modes_opengl * awm
#define POLL_TIMEOUT
Definition: AW_status.cxx:127
time_t last_refresh_time
Definition: AW_status.cxx:92
bool aw_ask_sure(const char *unique_id, const char *msg)
void main_loop()
Definition: AW_root.cxx:625
int aw_question(const char *unique_id, const char *question, const char *buttons, bool sameSizeButtons, const char *helpfile)
Definition: AW_question.cxx:26
time_t last_message_time
Definition: AW_status.cxx:93
static void copy(double **i, double **j)
Definition: trnsprob.cxx:32
static void create_status_awars(AW_root *aw_root)
Definition: AW_status.cxx:758
static int aw_status_read_int(int fd, int poll_flag)
Definition: AW_status.cxx:253
#define AWAR_ERROR_MESSAGES
static unsigned aw_status_timer_listen_event(AW_root *awr)
Definition: AW_status.cxx:573
bool aw_status_aborted()
Definition: AW_status.cxx:908
void aw_message(const char *msg)
Definition: AW_status.cxx:932
void hide()
Definition: AW_window.cxx:1807
void aw_status_gauge(double gauge)
Definition: AW_status.cxx:894
AW_root * get_root()
Definition: aw_window.hxx:348
static void aw_status_wait_for_open(int fd)
Definition: AW_status.cxx:338
#define NULp
Definition: cxxforward.h:97
static void aw_status_check_pipe()
Definition: AW_status.cxx:329
static void aw_refresh_tmp_message_display(AW_root *awr)
Definition: AW_status.cxx:464
GB_ERROR write_string(const char *aw_string)
#define AW_MESSAGE_LINES
Definition: AW_status.cxx:49
const char * get_data() const
Definition: arb_strbuf.h:70
static void aw_clear_and_hide_message_cb(AW_window *aww)
Definition: AW_status.cxx:753
static void aw_insert_message_in_tmp_message(AW_root *awr, const char *message)
Definition: AW_status.cxx:527
AW_window * awm
Definition: AW_status.cxx:88
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:570
long last_used_est
Definition: AW_status.cxx:98
#define AWAR_STATUS_ELAPSED
Definition: AW_status.cxx:47
void aw_initstatus()
Definition: AW_status.cxx:766
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
static int aw_status_read_command(int fd, int poll_flag, char *&str, int *gaugePtr=NULp)
Definition: AW_status.cxx:284
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:195
void aw_set_local_message()
Definition: AW_status.cxx:927
char * lines[AW_MESSAGE_LINES]
Definition: AW_status.cxx:90
void put(char c)
Definition: arb_strbuf.h:138