Commits
C. Enrique Garcia Dabo authored 99cc55d6eb6 Merge
98 98 | |
99 99 | |
100 100 | |
101 101 | using namespace casa; |
102 102 | |
103 103 | static pid_t manager_root_pid = 0; |
104 104 | static pid_t manager_xvfb_pid = 0; |
105 105 | static bool sigterm_received = false; |
106 106 | static void preprocess_args( int argc, const char *argv[], int &numargs, char **&args, |
107 107 | char *&server_string, bool &do_dbus, bool &inital_run, |
108 - | bool &server_startup, bool &daemon, |
108 + | bool &server_startup, bool &daemon, bool &xvfb_self_start, |
109 109 | bool &without_gui, bool &persistent, bool &casapy_start, |
110 110 | char *&logfile_path, char *&data_path, bool &do_not_fork ); |
111 111 | static void start_manager_root( const char *origname, int numargs, char **args, |
112 - | const char *dbusname, bool without_gui, pid_t root_pid ); |
112 + | const char *dbusname, bool without_gui, bool daemon, pid_t root_pid ); |
113 113 | static void launch_server( const char *origname, int numargs, char **args, |
114 114 | const char *dbusname, bool without_gui, |
115 115 | bool persistent, bool casapy_start ); |
116 116 | static char *find_xvfb( const char *paths ); |
117 117 | static pid_t launch_xvfb( const char *name, pid_t pid, char *&display, char *&authority ); |
118 118 | |
119 119 | static void exiting_server( int /*sig*/ ) { |
120 120 | if ( manager_xvfb_pid ) kill( manager_xvfb_pid, SIGKILL ); |
121 121 | exit(0); |
122 122 | } |
249 249 | |
250 250 | CrashReporter::initializeFromApplication(argv[0]); |
251 251 | |
252 252 | |
253 253 | casa::dbus::diagnostic.argv( argc, argv ); |
254 254 | |
255 255 | |
256 256 | bool server_startup = false; |
257 257 | bool do_not_fork = false; |
258 258 | bool daemon = false; |
259 + | bool xvfb_self_start = false; |
259 260 | bool without_gui = false; |
260 261 | bool persistent = false; |
261 262 | bool casapy_start = false; |
262 263 | char *server_string = 0; |
263 264 | bool with_dbus = false; |
264 265 | char *logfile_path = 0; |
265 266 | char *command_line_data_path = 0; |
266 267 | bool initial_run = false; |
267 268 | |
268 269 | char **args; |
279 280 | // |
280 281 | // This avoids this swapping, making the behavior more consistent when running on an X11 |
281 282 | // system displaying on OSX or just when using it with OSX. |
282 283 | // |
283 284 | // This option makes *NO*DIFFERENCE* for the context menu on the "Point Button Tool". |
284 285 | // Thu Aug 30 10:32:15 EDT 2012 <drs> |
285 286 | // |
286 287 | // QCoreApplication::setAttribute(Qt::AA_MacDontSwapCtrlAndMeta); |
287 288 | |
288 289 | preprocess_args( argc, argv, numargs, args, server_string, with_dbus, |
289 - | initial_run, server_startup, daemon, without_gui, |
290 + | initial_run, server_startup, daemon, xvfb_self_start, without_gui, |
290 291 | persistent, casapy_start, logfile_path, command_line_data_path, do_not_fork ); |
291 292 | |
292 293 | // |
293 294 | // configure datapath for casacore and colormaps... |
294 295 | // |
295 296 | auto ends_with = []( const std::string& str, const std::string& ending ) { |
296 297 | return ( str.size( ) >= ending.size( ) ) && equal( ending.rbegin( ), ending.rend( ), str.rbegin( ) ); |
297 298 | }; |
298 299 | // |
299 300 | // on linux argv[0] will be "casaviewer" |
399 400 | casacore::LogSinkInterface *sink = new casacore::StreamLogSink(new ofstream(logfile_path,std::ios_base::app)); |
400 401 | casacore::LogSink::globalSink(sink); |
401 402 | } |
402 403 | } |
403 404 | |
404 405 | if ( (server_startup || without_gui) && initial_run && ! do_not_fork ) { |
405 406 | if ( daemon ) { |
406 407 | launch_server( argv[0], numargs, args, server_string, without_gui, |
407 408 | persistent, casapy_start ); |
408 409 | } else { |
409 - | start_manager_root( argv[0], numargs, args, server_string, without_gui, getpid( ) ); |
410 + | start_manager_root( argv[0], numargs, args, server_string, without_gui, false, getpid( ) ); |
410 411 | } |
411 412 | exit(0); |
412 413 | } |
413 414 | |
414 415 | INITIALIZE_PGPLOT |
415 416 | try { |
417 + | Int qappExitStatus = -1; |
416 418 | |
417 - | ViewerApp qapp(numargs, args, true); |
419 + | // Create a scope here, which causes the destructor of qapp to be called before killing the manager_xvfb_pid. |
420 + | { // qapp scope |
421 + | ViewerApp qapp(numargs, args, true); |
418 422 | |
419 - | // if it's a server, stick around even if all windows are closed... |
420 - | if ( server_startup ) { |
421 - | qapp.setQuitOnLastWindowClosed(false); |
422 - | } |
423 + | // if it's a server, stick around even if all windows are closed... |
424 + | if ( server_startup ) { |
425 + | qapp.setQuitOnLastWindowClosed(false); |
426 + | } |
423 427 | |
424 - | String filename = "", |
425 - | displaytype = "", |
426 - | datatype = "", |
427 - | arg2 = "", |
428 - | arg3 = ""; |
428 + | String filename = "", |
429 + | displaytype = "", |
430 + | datatype = "", |
431 + | arg2 = "", |
432 + | arg3 = ""; |
433 + | |
434 + | |
435 + | Int narg; |
436 + | |
437 + | |
438 + | narg = qapp.argc(); |
439 + | if(narg>1) filename = qapp.argv()[1]; |
440 + | if(narg>2) arg2 = qapp.argv()[2]; |
441 + | if(narg>3) arg3 = qapp.argv()[3]; |
442 + | |
443 + | narg = numargs; |
444 + | if(narg>1) filename = args[1]; |
445 + | if(narg>2) arg2 = args[2]; |
446 + | if(narg>3) arg3 = args[3]; |
447 + | |
448 + | |
449 + | // Workaround for python task's "empty parameter" disability.... |
450 + | if(filename==".") filename=""; |
451 + | |
452 + | if ( filename != "" && filename[0] == '-' && filename[1] == '-' ) { |
453 + | struct stat statbuf; |
454 + | if ( stat( filename.c_str( ), &statbuf ) == -1 ) { |
455 + | filename = ""; |
456 + | } |
457 + | } |
429 458 | |
459 + | // Pass along the remaining arguments to QtViewer... |
460 + | // instead of littering the ctor arguments... |
461 + | std::list<std::string> stdargs; |
462 + | for ( int arg_index=0; args[arg_index]; ++arg_index ) |
463 + | stdargs.push_back(args[arg_index]); |
430 464 | |
431 - | Int narg; |
465 + | QtViewer* v = new QtViewer( stdargs, server_startup || with_dbus, server_string ); |
466 + | qapp.subscribe(v); |
432 467 | |
433 - | |
434 - | narg = qapp.argc(); |
435 - | if(narg>1) filename = qapp.argv()[1]; |
436 - | if(narg>2) arg2 = qapp.argv()[2]; |
437 - | if(narg>3) arg3 = qapp.argv()[3]; |
438 - | |
439 - | narg = numargs; |
440 - | if(narg>1) filename = args[1]; |
441 - | if(narg>2) arg2 = args[2]; |
442 - | if(narg>3) arg3 = args[3]; |
443 - | |
468 + | if ( ! server_startup ) { |
444 469 | |
445 - | // Workaround for python task's "empty parameter" disability.... |
446 - | if(filename==".") filename=""; |
470 + | // define the panel |
471 + | QtDisplayPanelGui* dpg; |
447 472 | |
448 - | if ( filename != "" && filename[0] == '-' && filename[1] == '-' ) { |
449 - | struct stat statbuf; |
450 - | if ( stat( filename.c_str( ), &statbuf ) == -1 ) { |
451 - | filename = ""; |
452 - | } |
453 - | } |
473 + | dpg = v->createDPG( ); |
454 474 | |
455 - | // Pass along the remaining arguments to QtViewer... |
456 - | // instead of littering the ctor arguments... |
457 - | std::list<std::string> stdargs; |
458 - | for ( int arg_index=0; args[arg_index]; ++arg_index ) |
459 - | stdargs.push_back(args[arg_index]); |
460 - | |
461 - | QtViewer* v = new QtViewer( stdargs, server_startup || with_dbus, server_string ); |
462 - | qapp.subscribe(v); |
463 - | |
464 - | if ( ! server_startup ) { |
465 - | |
466 - | // define the panel |
467 - | QtDisplayPanelGui* dpg; |
468 - | |
469 - | dpg = v->createDPG( ); |
470 - | |
471 - | QtDisplayData* qdd = 0; |
472 - | |
473 - | // Data files are now typed automatically (see v_->filetype(filename), |
474 - | // below; e.g.: "image" or "ms"). arg2 need be used only to specify a |
475 - | // displaytype, and then only when it is not the default displaytype |
476 - | // for the datatype (e.g. viewer "my.im", "contour" ). |
477 - | // |
478 - | // The user can enter an lel expression in place of filename, but such |
479 - | // an expression _cannot_ be automatically typed. In this case the user |
480 - | // must have "lel" in arg2 (or in arg3: the only case where arg3 is vaguely |
481 - | // useful is something like: |
482 - | // |
483 - | // casaviewer "'my.im'-'other.im'" contour lel |
484 - | // |
485 - | // arg3 is not even offered in the viewer casapy task). |
486 - | // |
487 - | // The logic below allows displaytypes or datatypes to be entered in |
488 - | // either order, and for old datatypes to be used other than "lel" (these |
489 - | // are simply ignored). This allows old (deprecated) parameter usage in |
490 - | // scripts (such as viewer("my.ms", "ms")) to continue to be understood. |
491 - | // |
492 - | // However, the canonical 'allowed' parameter set (per user documentation) |
493 - | // is now just: |
494 - | // |
495 - | // viewer [filename [displaytype]] |
496 - | // |
497 - | |
498 - | if(filename!="") { |
499 - | |
500 - | Bool tryDDcreate = true; |
501 - | |
502 - | if(arg3=="lel" || arg2=="lel") { |
503 - | |
504 - | // (this means that first ('filename') parameter is supposed to |
505 - | // contain a valid lel (image expression) string; this is advanced |
506 - | // (and undocumented) parameter usage). |
507 - | |
508 - | datatype = "lel"; |
509 - | displaytype = (arg3=="lel")? arg2 : arg3; |
510 - | v->dataDisplaysAs(datatype, displaytype); |
511 - | } else { |
475 + | QtDisplayData* qdd = 0; |
512 476 | |
513 - | datatype = v->filetype(filename); |
477 + | // Data files are now typed automatically (see v_->filetype(filename), |
478 + | // below; e.g.: "image" or "ms"). arg2 need be used only to specify a |
479 + | // displaytype, and then only when it is not the default displaytype |
480 + | // for the datatype (e.g. viewer "my.im", "contour" ). |
481 + | // |
482 + | // The user can enter an lel expression in place of filename, but such |
483 + | // an expression _cannot_ be automatically typed. In this case the user |
484 + | // must have "lel" in arg2 (or in arg3: the only case where arg3 is vaguely |
485 + | // useful is something like: |
486 + | // |
487 + | // casaviewer "'my.im'-'other.im'" contour lel |
488 + | // |
489 + | // arg3 is not even offered in the viewer casapy task). |
490 + | // |
491 + | // The logic below allows displaytypes or datatypes to be entered in |
492 + | // either order, and for old datatypes to be used other than "lel" (these |
493 + | // are simply ignored). This allows old (deprecated) parameter usage in |
494 + | // scripts (such as viewer("my.ms", "ms")) to continue to be understood. |
495 + | // |
496 + | // However, the canonical 'allowed' parameter set (per user documentation) |
497 + | // is now just: |
498 + | // |
499 + | // viewer [filename [displaytype]] |
500 + | // |
514 501 | |
502 + | if(filename!="") { |
515 503 | |
516 - | if(datatype=="restore") { |
504 + | Bool tryDDcreate = true; |
517 505 | |
518 - | // filename is a restore file. |
506 + | if(arg3=="lel" || arg2=="lel") { |
519 507 | |
520 - | tryDDcreate = false; |
508 + | // (this means that first ('filename') parameter is supposed to |
509 + | // contain a valid lel (image expression) string; this is advanced |
510 + | // (and undocumented) parameter usage). |
521 511 | |
522 - | dpg->restorePanelState(filename); |
523 - | } |
512 + | datatype = "lel"; |
513 + | displaytype = (arg3=="lel")? arg2 : arg3; |
514 + | v->dataDisplaysAs(datatype, displaytype); |
515 + | } else { |
524 516 | |
525 - | else { |
517 + | datatype = v->filetype(filename); |
526 518 | |
527 - | if(datatype=="nonexistent") { |
528 - | cerr << "***Can't find " << filename << "***" << endl; |
529 - | tryDDcreate = false; |
530 - | } |
531 519 | |
532 - | if(datatype=="unknown") { |
533 - | cerr << "***Unknown file type for " << filename << "***" << endl; |
520 + | if(datatype=="restore") { |
521 + | |
522 + | // filename is a restore file. |
523 + | |
534 524 | tryDDcreate = false; |
525 + | |
526 + | dpg->restorePanelState(filename); |
535 527 | } |
536 528 | |
537 - | // filename names a normal data file. If user has passed a valid |
538 - | // displaytype in either arg2 or arg3, use it; otherwise, the |
539 - | // default displaytype for datatype will be inserted. |
529 + | else { |
540 530 | |
541 - | displaytype = arg2; |
542 - | if(!v->dataDisplaysAs(datatype, displaytype)) { |
543 - | displaytype = arg3; |
544 - | v->dataDisplaysAs(datatype, displaytype); |
531 + | if(datatype=="nonexistent") { |
532 + | cerr << "***Can't find " << filename << "***" << endl; |
533 + | tryDDcreate = false; |
534 + | } |
535 + | |
536 + | if(datatype=="unknown") { |
537 + | cerr << "***Unknown file type for " << filename << "***" << endl; |
538 + | tryDDcreate = false; |
539 + | } |
540 + | |
541 + | // filename names a normal data file. If user has passed a valid |
542 + | // displaytype in either arg2 or arg3, use it; otherwise, the |
543 + | // default displaytype for datatype will be inserted. |
544 + | |
545 + | displaytype = arg2; |
546 + | if(!v->dataDisplaysAs(datatype, displaytype)) { |
547 + | displaytype = arg3; |
548 + | v->dataDisplaysAs(datatype, displaytype); |
549 + | } |
545 550 | } |
546 551 | } |
547 - | } |
548 552 | |
549 553 | |
550 - | if(tryDDcreate) { |
554 + | if(tryDDcreate) { |
551 555 | |
552 - | qdd = dpg->createDD(filename, datatype, displaytype, true, |
553 - | -1, false, false, false/*, ddo*/ ); |
554 - | dpg->addedData( QString::fromStdString(displaytype), qdd ); |
556 + | qdd = dpg->createDD(filename, datatype, displaytype, true, |
557 + | -1, false, false, false/*, ddo*/ ); |
558 + | dpg->addedData( QString::fromStdString(displaytype), qdd ); |
555 559 | |
556 560 | |
557 - | if(qdd==0) cerr << dpg->errMsg() << endl; |
561 + | if(qdd==0) cerr << dpg->errMsg() << endl; |
562 + | } |
558 563 | } |
559 - | } |
560 564 | |
561 - | dpg->show(); |
565 + | dpg->show(); |
562 566 | |
563 - | if( dpg->isEmptyDD() ) dpg->showDataManager(); |
567 + | if( dpg->isEmptyDD() ) dpg->showDataManager(); |
564 568 | |
565 - | } |
569 + | } |
566 570 | |
567 - | Int stat = qapp.exec(); |
571 + | qappExitStatus = qapp.exec(); |
568 572 | |
569 - | //delete dpg; // Used to lead to crash (double-deletion |
570 - | // of MWCTools); should work now. |
573 + | //delete dpg; // Used to lead to crash (double-deletion |
574 + | // of MWCTools); should work now. |
575 + | delete v; |
576 + | } // qapp scope |
571 577 | |
572 - | delete v; |
578 + | // Once qapp has destructed, it is safe to kill the xvfb instance |
579 + | // that we created in launch_server->start_manager_root. |
580 + | if (xvfb_self_start && manager_xvfb_pid != 0) { |
581 + | // Not killing the xvfb process causes mpi runs to hang. |
582 + | kill( manager_xvfb_pid, SIGTERM ); |
583 + | } |
573 584 | |
574 - | // cerr<<"Normal exit -- status: "<<stat<<endl; //#diag |
585 + | // cerr<<"Normal exit -- status: "<<qappExitStatus<<endl; //#diag |
575 586 | |
576 - | return stat; |
587 + | return qappExitStatus; |
577 588 | } |
578 589 | |
579 590 | catch (const casacore::AipsError& err) { |
580 591 | cerr<<"**"<<err.getMesg()<<endl; |
581 592 | } catch (...) { |
582 593 | cerr<<"**non-AipsError exception**"<<endl; |
583 594 | } |
584 595 | |
585 596 | } |
586 597 | |
587 598 | // processes argv into args stripping out the the viewer setup flags... numargs has the number |
588 599 | // of args, and the last arg (not included in numargs count) is null (for execvp) |
589 600 | static void preprocess_args( int argc, const char *argv[], int &numargs, char **&args, |
590 601 | char *&server_string, bool &with_dbus, bool &initial_run, |
591 - | bool &server_startup, bool &daemon, bool &without_gui, bool &persistent, |
602 + | bool &server_startup, bool &daemon, bool &xvfb_self_start, bool &without_gui, bool &persistent, |
592 603 | bool &casapy_start, char *&logfile_path, char *&data_path, bool &do_not_fork ) { |
593 604 | |
605 + | |
594 606 | without_gui = false; |
595 607 | persistent = false; |
596 608 | casapy_start = false; |
597 609 | server_string = 0; |
598 610 | data_path = 0; |
599 611 | |
600 612 | initial_run = (isdigit(argv[0][0]) ? false : true); |
601 613 | |
602 614 | for ( int x = 0; x < argc; ++x ) { |
603 615 | if ( ! strncmp(argv[x],"--nogui",7) ) { |
688 700 | if ( strlen(file) <= 0 ) { |
689 701 | free( file ); |
690 702 | } else { |
691 703 | logfile_path = file; |
692 704 | } |
693 705 | } else if ( x + 1 < argc ) { |
694 706 | logfile_path = strdup(argv[++x]); |
695 707 | } |
696 708 | } else if ( ! strncmp(argv[x],"--xvfb-pid=",11) ) { |
697 709 | sscanf( argv[x], "--xvfb-pid=%u", &manager_xvfb_pid ); |
710 + | } else if ( ! strcmp(argv[x],"--xvfb-self-start") ) { |
711 + | xvfb_self_start = true; |
698 712 | } |
699 713 | } |
700 714 | |
701 715 | char *orig_name = strdup(argv[0]); |
702 716 | char *name = orig_name + strlen(orig_name) - 1; |
703 717 | while ( name > orig_name && *name != '/' ) --name; |
704 718 | if ( *name == '/' ) ++name; |
705 719 | |
706 720 | // pre-process the command line arguments (for now), it looks like |
707 721 | // the current scheme is to hard-wire a limited set of command line |
736 750 | } |
737 751 | |
738 752 | for ( int x = 1; x < argc; ++x ) { |
739 753 | if ( ! strcmp(argv[x], "--dbusname") ) { |
740 754 | ++x; |
741 755 | } else if ( strncmp( argv[x], "--server", 8 ) && |
742 756 | strncmp( argv[x], "--nogui", 7 ) && |
743 757 | strcmp( argv[x], "--persist" ) && |
744 758 | strcmp( argv[x], "--casapy" ) && |
745 759 | strcmp( argv[x], "--eso3d" ) && |
746 - | strncmp( argv[x],"--dbusname",10) ) |
760 + | strncmp( argv[x],"--dbusname",10) && |
761 + | strcmp( argv[x],"--xvfb-self-start") ) |
747 762 | args[numargs++] = strdup(argv[x]); |
748 763 | } |
749 764 | args[numargs] = 0; |
750 765 | |
751 766 | std::list<char*> files; |
752 767 | std::list<char*> others; |
753 768 | std::list<char*> flags; |
754 769 | struct stat statbuf; |
755 770 | for ( int x = 1; x < numargs; ++x ) { |
756 771 | if ( ! stat( args[x], &statbuf ) ) { |
768 783 | args[offset++] = *iter; |
769 784 | } |
770 785 | for ( std::list<char*>::iterator iter = others.begin( ); |
771 786 | iter != others.end( ); ++iter ) { |
772 787 | args[offset++] = *iter; |
773 788 | } |
774 789 | for ( std::list<char*>::iterator iter = flags.begin( ); |
775 790 | iter != flags.end( ); ++iter ) { |
776 791 | args[offset++] = *iter; |
777 792 | } |
793 + | |
778 794 | } |
779 795 | |
780 796 | void start_manager_root( const char *origname, int numargs, char **args, const char */*dbusname*/, |
781 - | bool without_gui, pid_t root_pid ) { |
797 + | bool without_gui, bool daemon, pid_t root_pid ) { |
798 + | |
782 799 | |
783 800 | char *display = 0; |
784 801 | char *authority = 0; |
785 802 | if ( without_gui ) { |
786 803 | manager_xvfb_pid = launch_xvfb( args[0], root_pid, display, authority ); |
787 804 | sleep(2); |
788 805 | } |
789 806 | |
790 807 | char *name = args[0]; |
791 808 | |
796 813 | putenv( authority ); |
797 814 | } |
798 815 | |
799 816 | char *new_name = (char*) malloc( sizeof(char)*(strlen(name)+25) ); |
800 817 | sprintf( new_name, "%d-%s-svr", root_pid, name ); |
801 818 | args[0] = new_name; |
802 819 | |
803 820 | free(name); |
804 821 | |
805 822 | char **newargs = 0; |
823 + | char xvfbb[124]; |
806 824 | if ( manager_xvfb_pid == 0 ) |
807 825 | newargs = args; |
808 826 | else { |
809 - | newargs = (char**) malloc( sizeof(char*)*(numargs+2) ); |
827 + | int newnumargs = numargs+2; |
828 + | newargs = (char**) malloc( sizeof(char*)*(newnumargs) ); |
810 829 | for (int i=0; i < numargs; ++i) |
811 830 | newargs[i] = args[i]; |
812 - | char xvfbb[124]; |
813 831 | sprintf( xvfbb, "--xvfb-pid=%u", manager_xvfb_pid ); |
814 832 | newargs[numargs] = xvfbb; |
815 833 | newargs[numargs+1] = 0; |
834 + | |
835 + | if (!daemon) { |
836 + | // let the next instance of this process know that it should kill xvfb when it exits |
837 + | newnumargs++; |
838 + | newargs = (char**) realloc( newargs, sizeof(char*)*(newnumargs) ); |
839 + | newargs[newnumargs-2] = "--xvfb-self-start"; |
840 + | newargs[newnumargs-1] = 0; |
841 + | } |
816 842 | } |
817 843 | |
818 844 | execvp( origname, newargs ); |
819 845 | } |
820 846 | |
821 847 | void launch_server( const char *origname, int numargs, char **args, |
822 848 | const char *dbusname, bool without_gui, |
823 849 | bool persistent, bool casapy_start ) { |
824 850 | |
825 851 | // ______________________________________________________________________________________________________ |
877 903 | // if ( setsid( ) == -1 ) { |
878 904 | // fprintf( stderr, "trying to do the setsid...%d...\n", getpid() ); |
879 905 | // perror( "setsid issue" ); |
880 906 | // } |
881 907 | |
882 908 | char buffer[50]; |
883 909 | sprintf( buffer,"%d", getpid() ); |
884 910 | write( vio[1], buffer, strlen(buffer) + 1 ); |
885 911 | close(vio[1]); |
886 912 | |
887 - | start_manager_root( origname, numargs, args, dbusname, without_gui, root_pid ); |
913 + | start_manager_root( origname, numargs, args, dbusname, without_gui, true, root_pid ); |
888 914 | fprintf( stderr, "start_manager_root( ) should not have returned...%d...\n", getpid() ); |
889 915 | exit(1); |
890 916 | } |
891 917 | |
892 918 | char buffer[50]; |
893 919 | close(vio[1]); |
894 920 | read( vio[0], buffer, 50 ); |
895 921 | manager_root_pid = (pid_t) atoi(buffer); |
896 922 | close(vio[0]); |
897 923 | |