/************ * * This file is part of the vector graphics language Asymptote * Copyright (C) 2004 Andy Hammerlindl, John C. Bowman, Tom Prince * https://asymptote.sourceforge.io * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * *************/ #ifdef __CYGWIN__ #define _POSIX_C_SOURCE 200809L #endif #include #include #include #include #if !defined(_WIN32) #include #endif #include "common.h" #ifdef HAVE_LIBSIGSEGV #include #endif #define GC_PTHREAD_SIGMASK_NEEDED #ifdef HAVE_LSP #include "lspserv.h" #endif #include "exithandlers.h" #include "errormsg.h" #include "fpu.h" #include "settings.h" #include "locate.h" #include "interact.h" #include "fileio.h" #include "stack.h" #ifdef HAVE_LIBFFTW3 #include "fftw++.h" #endif #if defined(_WIN32) #include #endif #include "stack.h" using namespace settings; using interact::interactive; namespace gl { extern bool glexit; } namespace run { void purge(); } #ifdef PROFILE namespace vm { extern void dumpProfile(); }; #endif #ifdef HAVE_LIBSIGSEGV void stackoverflow_handler (int, stackoverflow_context_t) { em.runtime(vm::getPos()); cerr << "Stack overflow" << endl; abort(); } int sigsegv_handler (void *, int emergency) { if(!emergency) return 0; // Really a stack overflow em.runtime(vm::getPos()); #ifdef HAVE_GL if(gl::glthread) cerr << "Stack overflow or segmentation fault: rerun with -nothreads" << endl; else #endif cerr << "Segmentation fault" << endl; abort(); } #endif void setsignal(void (*handler)(int)) { #ifdef HAVE_LIBSIGSEGV char mystack[16384]; stackoverflow_install_handler(&stackoverflow_handler, mystack,sizeof (mystack)); sigsegv_install_handler(&sigsegv_handler); #endif #if !defined(_WIN32) Signal(SIGBUS,handler); #endif Signal(SIGFPE,handler); } struct Args { int argc; char **argv; Args(int argc, char **argv) : argc(argc), argv(argv) {} }; void *asymain(void *A) { setsignal(signalHandler); Args *args=(Args *) A; fpu_trap(trap()); #ifdef HAVE_LIBFFTW3 fftwpp::wisdomName=".wisdom"; #endif #if defined(_WIN32) // see https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecuteexa CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); #endif if(interactive) { Signal(SIGINT,interruptHandler); #ifdef HAVE_LSP if (getSetting("lsp")) { AsymptoteLsp::LspLog log; auto jsonHandler=std::make_shared(); auto endpoint=std::make_shared(log); unique_ptr asylsp; if(getSetting("lspport") != "") { asylsp=make_unique( (std::string)getSetting("lsphost").c_str(), (std::string)getSetting("lspport").c_str(), jsonHandler, endpoint, log); } else { asylsp=make_unique(jsonHandler, endpoint, log); } asylsp->start(); } else #endif processPrompt(); } else if (getSetting("listvariables") && numArgs()==0) { try { doUnrestrictedList(); } catch(handled_error const&) { em.statusError(); } } else { int n=numArgs(); if(n == 0) { int inpipe=intcast(settings::getSetting("inpipe")); bool hasInpipe=inpipe >= 0; if(hasInpipe) { #if !defined(_WIN32) Signal(SIGHUP,hangup_handler); #endif camp::openpipeout(); fprintf(camp::pipeout,"\n"); fflush(camp::pipeout); } for(;;) { processFile("-",true); try { setOptions(args->argc,args->argv); } catch(handled_error const&) { em.statusError(); } if(inpipe < 0) break; } } else { for(int ind=0; ind < n; ind++) { string name=(getArg(ind)); string prefix=stripExt(name); if(name == prefix+".v3d") { interact::uptodate=false; runString("import v3d; defaultfilename=\""+stripDir(prefix)+ "\"; importv3d(\""+name+"\");"); } else processFile(name,n > 1); try { if(ind < n-1) setOptions(args->argc,args->argv); } catch(handled_error const&) { em.statusError(); } } } } #ifdef PROFILE vm::dumpProfile(); #endif if(getSetting("wait")) { #if defined(_WIN32) #pragma message("TODO: wait option not implement yet") #else int status; while(wait(&status) > 0); #endif } #ifdef HAVE_GL #ifdef HAVE_PTHREAD if(gl::glthread) { #ifdef __MSDOS__ // Signals are unreliable in MSWindows gl::glexit=true; #else pthread_kill(gl::mainthread,SIGURG); pthread_join(gl::mainthread,NULL); #endif } #endif #endif exit(returnCode()); } int main(int argc, char *argv[]) { #ifdef HAVE_LIBGSL #if defined(_WIN32) _putenv("GSL_RNG_SEED="); _putenv("GSL_RNG_TYPE="); #else unsetenv("GSL_RNG_SEED"); unsetenv("GSL_RNG_TYPE"); #endif #endif setsignal(signalHandler); try { setOptions(argc,argv); } catch(handled_error const&) { em.statusError(); } Args args(argc,argv); #ifdef HAVE_GL #if defined(__APPLE__) || defined(_WIN32) #if defined(_WIN32) #pragma message("TODO: Check if (1) we need detach-based gl renderer") #endif bool usethreads=true; #else bool usethreads=view(); #endif gl::glthread=usethreads ? getSetting("threads") : false; #if HAVE_PTHREAD #ifndef HAVE_LIBOSMESA if(gl::glthread) { pthread_t thread; try { #if defined(_WIN32) auto asymainPtr = [](void* args) -> void* { #if defined(USEGC) GC_stack_base gsb {}; GC_get_stack_base(&gsb); GC_register_my_thread(&gsb); #endif auto* ret = asymain(args); #if defined(USEGC) GC_unregister_my_thread(); #endif return reinterpret_cast(ret); }; #else auto* asymainPtr = asymain; #endif if(pthread_create(&thread,NULL,asymainPtr,&args) == 0) { gl::mainthread=pthread_self(); #if !defined(_WIN32) sigset_t set; sigemptyset(&set); sigaddset(&set, SIGCHLD); pthread_sigmask(SIG_BLOCK, &set, NULL); #endif for(;;) { #if !defined(_WIN32) Signal(SIGURG,exitHandler); #endif camp::glrenderWrapper(); gl::initialize=true; } } else gl::glthread=false; } catch(std::bad_alloc&) { outOfMemory(); } } #endif #endif gl::glthread=false; #endif asymain(&args); }