Commits

C. Enrique Garcia Dabo authored 99cc55d6eb6 Merge
Merge branch 'master' into CAS-13437
No tags

casa5/code/display/apps/casaviewer/casaviewer.cc

Modified
98 98 #endif
99 99
100 100 #include <casa/namespace.h>
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 #ifndef NO_CRASH_REPORTER
250 250 CrashReporter::initializeFromApplication(argv[0]);
251 251 #endif
252 252 #if ! defined(CASATOOLS)
253 253 casa::dbus::diagnostic.argv( argc, argv );
254 254 #endif
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 + #ifndef AIPS_DARWIN
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 + #else
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 + #endif
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 -#ifndef AIPS_DARWIN
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 -#else
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 -#endif
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

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut