bool R3DSurfaceGenProcess::runSurfaceGenProcess(R3DProject::Surface *pSurface) { R3DProject *pProject = R3DProject::getInstance(); R3DProjectPaths paths; if(!pProject->getProjectPathsSrf(paths, pSurface)) return false; pSurface_ = pSurface; beginTime_ = wxDateTime::UNow(); #if wxCHECK_VERSION(2, 9, 0) env_.cwd = paths.absoluteProjectPath_; // Set PATH/LD_LIBRARY_PATH/DYLD_LIBRARY_PATH environment variable #if defined(R3D_WIN32) wxString envVarName(wxT("PATH")); #elif defined(R3D_MACOSX) wxString envVarName(wxT("DYLD_LIBRARY_PATH")); #else wxString envVarName(wxT("LD_LIBRARY_PATH")); #endif wxEnvVariableHashMap envVars; if(wxGetEnvMap(&envVars)) { wxString concatPaths; const wxArrayString &exePaths = R3DExternalPrograms::getInstance().getAllPaths(); for(size_t i = 0; i < exePaths.GetCount(); i++) { const wxString &curPath = exePaths[i]; if(!concatPaths.IsEmpty()) #if defined(R3D_WIN32) concatPaths.Append(wxT(";")); #else concatPaths.Append(wxT(":")); #endif concatPaths.Append(curPath); } wxEnvVariableHashMap::iterator iter = envVars.find(envVarName); if(iter != envVars.end()) { wxString val = iter->second; if(!val.IsEmpty()) #if defined(R3D_WIN32) val.Append(wxT(";")); #else val.Append(wxT(":")); #endif val.Append(concatPaths); envVars[envVarName] = val; } else { envVars[envVarName] = concatPaths; } env_.env = envVars; } #endif cmds_.Clear(); progressTexts_.Clear(); wxString relativeSurfacePath(paths.relativeSurfacePath_.c_str(), wxConvLibc); wxString relativeSurfaceFilename; // Used for texturing if(pSurface->surfaceType_ == R3DProject::STPoissonRecon) { wxString poissonReconExe = R3DExternalPrograms::getInstance().getPoissonReconPath(); wxString surfaceTrimmerExe = R3DExternalPrograms::getInstance().getSurfaceTrimmerPath(); wxString texreconExe = R3DExternalPrograms::getInstance().getTexReconPath(); wxString poissonReconCmd = poissonReconExe + wxT(" --in ") + wxString(paths.relativeDenseModelName_.c_str(), wxConvLibc) + wxT(" --out ") + relativeSurfacePath + wxT("/model_surface.ply") + wxString::Format(wxT(" --depth %d --pointWeight %g --samplesPerNode %g"), pSurface->poissonDepth_, pSurface->poissonPointWeight_, pSurface->poissonSamplesPerNode_); if(pSurface->poissonTrimThreshold_ > 0) poissonReconCmd.Append(wxT(" --density")); poissonReconCmd.Append(wxT(" --verbose")); cmds_.Add(poissonReconCmd); progressTexts_.Add(wxT("Generating surface (PoissonRecon)")); wxString surfaceFilename(wxT("model_surface.ply")); if(pSurface->poissonTrimThreshold_ > 0) { cmds_.Add(surfaceTrimmerExe + wxT(" --in ") + relativeSurfacePath + wxT("/model_surface.ply ") + wxString::Format(wxT("--trim %g"), pSurface->poissonTrimThreshold_) + wxT(" --out ") + relativeSurfacePath + wxT("/model_surface_trim.ply")); progressTexts_.Add(wxT("Trimming surface")); surfaceFilename = wxT("model_surface_trim.ply"); } // Store for later, will either be overwritten (texture case) or used as input (colorizing vertices case) pSurface->finalSurfaceFilename_ = surfaceFilename; if(pSurface->colorizationType_ == R3DProject::CTTextures) { wxFileName surfaceFN(relativeSurfacePath, surfaceFilename); relativeSurfaceFilename = surfaceFN.GetFullPath(); pSurface->finalSurfaceFilename_ = wxT("model_surface_text.obj"); } } else if(pSurface->surfaceType_ == R3DProject::STFSSRecon) { wxString fssReconExe = R3DExternalPrograms::getInstance().getFSSReconPath(); wxString meshcleanExe = R3DExternalPrograms::getInstance().getMeshCleanPath(); wxString surfaceModelName(wxT("surface_model.ply")); wxString cleanedSurfaceModelName(wxT("surface_clean_model.ply")); wxFileName surfaceModelFN(wxString(paths.relativeSurfacePath_.c_str(), wxConvLibc), surfaceModelName); wxFileName cleanedSurfaceModelFN(wxString(paths.relativeSurfacePath_.c_str(), wxConvLibc), cleanedSurfaceModelName); cmds_.Add(fssReconExe + wxString::Format(wxT(" --scale-factor=%g --refine-octree=%d "), pSurface->fssrScaleFactorMultiplier_, pSurface->fssrRefineOctreeLevels_) + wxString(paths.relativeDenseModelName_.c_str(), wxConvLibc) + wxT(" ") + surfaceModelFN.GetFullPath()); progressTexts_.Add(wxT("Generating surface (FSSR)")); cmds_.Add(meshcleanExe + wxString::Format(wxT(" --threshold=%g --component-size=%d "), pSurface->fssrConfidenceThreshold_, pSurface->fssrMinComponentSize_) + surfaceModelFN.GetFullPath() + wxT(" ") + cleanedSurfaceModelFN.GetFullPath()); progressTexts_.Add(wxT("Cleaning mesh (FSSR)")); relativeSurfaceFilename = cleanedSurfaceModelFN.GetFullPath(); // Used only in case of colored vertices pSurface->finalSurfaceFilename_ = cleanedSurfaceModelName; } if(pSurface->colorizationType_ == R3DProject::CTTextures) { wxString texreconExe = R3DExternalPrograms::getInstance().getTexReconPath(); wxString texreconCmd(texreconExe + wxT(" ")); if(pSurface->textGeometricVisibilityTest_ == false) texreconCmd += wxT("--skip_geometric_visibility_test "); if(pSurface->textGlobalSeamLeveling_ == false) texreconCmd += wxT("--skip_global_seam_leveling "); if(pSurface->textLocalSeamLeveling_ == false) texreconCmd += wxT("--skip_local_seam_leveling "); if(pSurface->textOutlierRemovalType_ == 1) texreconCmd += wxT("--outlier_removal=gauss_clamping "); if(pSurface->textOutlierRemovalType_ == 2) texreconCmd += wxT("--outlier_removal=gauss_damping "); texreconCmd += wxT("--no_intermediate_results "); texreconCmd += wxString(paths.relativeMVESceneDir_.c_str(), wxConvLibc) + wxT("::undistorted ") + relativeSurfaceFilename + wxT(" ") + relativeSurfacePath + wxT("/model_surface_text"); cmds_.Add(texreconCmd); progressTexts_.Add(wxT("Generating texture (texrecon)")); pSurface->finalSurfaceFilename_ = wxT("model_surface_text.obj"); } else if(pSurface->colorizationType_ == R3DProject::CTColoredVertices) { // No external program, this case is handled in Regard3DMainFrame::OnSurfaceGenFinished } runSingleCommand(); return (processId_ > 0); }
// wxExecute: the real worker function long wxExecute(char **argv, int flags, wxProcess *process, const wxExecuteEnv *env) { // for the sync execution, we return -1 to indicate failure, but for async // case we return 0 which is never a valid PID // // we define this as a macro, not a variable, to avoid compiler warnings // about "ERROR_RETURN_CODE value may be clobbered by fork()" #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0) wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") ); #if wxUSE_THREADS // fork() doesn't mix well with POSIX threads: on many systems the program // deadlocks or crashes for some reason. Probably our code is buggy and // doesn't do something which must be done to allow this to work, but I // don't know what yet, so for now just warn the user (this is the least we // can do) about it wxASSERT_MSG( wxThread::IsMain(), wxT("wxExecute() can be called only from the main thread") ); #endif // wxUSE_THREADS #if defined(__DARWIN__) && !defined(__WXOSX_IPHONE__) // wxMacLaunch() only executes app bundles and only does it asynchronously. // It returns false if the target is not an app bundle, thus falling // through to the regular code for non app bundles. if ( !(flags & wxEXEC_SYNC) && wxMacLaunch(argv) ) { // we don't have any PID to return so just make up something non null return -1; } #endif // __DARWIN__ // this struct contains all information which we use for housekeeping wxScopedPtr<wxExecuteData> execDataPtr(new wxExecuteData); wxExecuteData& execData = *execDataPtr; execData.flags = flags; execData.process = process; // create pipes for inter process communication wxPipe pipeIn, // stdin pipeOut, // stdout pipeErr; // stderr if ( process && process->IsRedirected() ) { if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() ) { wxLogError( _("Failed to execute '%s'\n"), *argv ); return ERROR_RETURN_CODE; } } // priority: we need to map wxWidgets priority which is in the range 0..100 // to Unix nice value which is in the range -20..19. As there is an odd // number of elements in our range and an even number in the Unix one, we // have to do it in this rather ugly way to guarantee that: // 1. wxPRIORITY_{MIN,DEFAULT,MAX} map to -20, 0 and 19 respectively. // 2. The mapping is monotonously increasing. // 3. The mapping is onto the target range. int prio = process ? int(process->GetPriority()) : int(wxPRIORITY_DEFAULT); if ( prio <= 50 ) prio = (2*prio)/5 - 20; else if ( prio < 55 ) prio = 1; else prio = (2*prio)/5 - 21; // fork the process // // NB: do *not* use vfork() here, it completely breaks this code for some // reason under Solaris (and maybe others, although not under Linux) // But on OpenVMS we do not have fork so we have to use vfork and // cross our fingers that it works. #ifdef __VMS pid_t pid = vfork(); #else pid_t pid = fork(); #endif if ( pid == -1 ) // error? { wxLogSysError( _("Fork failed") ); return ERROR_RETURN_CODE; } else if ( pid == 0 ) // we're in child { // NB: we used to close all the unused descriptors of the child here // but this broke some programs which relied on e.g. FD 1 being // always opened so don't do it any more, after all there doesn't // seem to be any real problem with keeping them opened #if !defined(__VMS) if ( flags & wxEXEC_MAKE_GROUP_LEADER ) { // Set process group to child process' pid. Then killing -pid // of the parent will kill the process and all of its children. setsid(); } #endif // !__VMS #if defined(HAVE_SETPRIORITY) if ( prio && setpriority(PRIO_PROCESS, 0, prio) != 0 ) { wxLogSysError(_("Failed to set process priority")); } #endif // HAVE_SETPRIORITY // redirect stdin, stdout and stderr if ( pipeIn.IsOk() ) { if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 || dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 || dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 ) { wxLogSysError(_("Failed to redirect child process input/output")); } pipeIn.Close(); pipeOut.Close(); pipeErr.Close(); } // Close all (presumably accidentally) inherited file descriptors to // avoid descriptor leaks. This means that we don't allow inheriting // them purposefully but this seems like a lesser evil in wx code. // Ideally we'd provide some flag to indicate that none (or some?) of // the descriptors do not need to be closed but for now this is better // than never closing them at all as wx code never used FD_CLOEXEC. // TODO: Iterating up to FD_SETSIZE is both inefficient (because it may // be quite big) and incorrect (because in principle we could // have more opened descriptions than this number). Unfortunately // there is no good portable solution for closing all descriptors // above a certain threshold but non-portable solutions exist for // most platforms, see [http://stackoverflow.com/questions/899038/ // getting-the-highest-allocated-file-descriptor] for ( int fd = 0; fd < (int)FD_SETSIZE; ++fd ) { if ( fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO ) { close(fd); } } // Process additional options if we have any if ( env ) { // Change working directory if it is specified if ( !env->cwd.empty() ) wxSetWorkingDirectory(env->cwd); // Change environment if needed. // // NB: We can't use execve() currently because we allow using // non full paths to wxExecute(), i.e. we want to search for // the program in PATH. However it just might be simpler/better // to do the search manually and use execve() envp parameter to // set up the environment of the child process explicitly // instead of doing what we do below. if ( !env->env.empty() ) { wxEnvVariableHashMap oldenv; wxGetEnvMap(&oldenv); // Remove unwanted variables wxEnvVariableHashMap::const_iterator it; for ( it = oldenv.begin(); it != oldenv.end(); ++it ) { if ( env->env.find(it->first) == env->env.end() ) wxUnsetEnv(it->first); } // And add the new ones (possibly replacing the old values) for ( it = env->env.begin(); it != env->env.end(); ++it ) wxSetEnv(it->first, it->second); } } execvp(*argv, argv); fprintf(stderr, "execvp("); for ( char **a = argv; *a; a++ ) fprintf(stderr, "%s%s", a == argv ? "" : ", ", *a); fprintf(stderr, ") failed with error %d!\n", errno); // there is no return after successful exec() _exit(-1); // some compilers complain about missing return - of course, they // should know that exit() doesn't return but what else can we do if // they don't? // // and, sure enough, other compilers complain about unreachable code // after exit() call, so we can just always have return here... #if defined(__VMS) || defined(__INTEL_COMPILER) return 0; #endif } else // we're in parent { // prepare for IO redirection #if HAS_PIPE_STREAMS if ( process && process->IsRedirected() ) { // Avoid deadlocks which could result from trying to write to the // child input pipe end while the child itself is writing to its // output end and waiting for us to read from it. if ( !pipeIn.MakeNonBlocking(wxPipe::Write) ) { // This message is not terrible useful for the user but what // else can we do? Also, should we fail here or take the risk // to continue and deadlock? Currently we choose the latter but // it might not be the best idea. wxLogSysError(_("Failed to set up non-blocking pipe, " "the program might hang.")); #if wxUSE_LOG wxLog::FlushActive(); #endif } wxOutputStream *inStream = new wxPipeOutputStream(pipeIn.Detach(wxPipe::Write)); const int fdOut = pipeOut.Detach(wxPipe::Read); wxPipeInputStream *outStream = new wxPipeInputStream(fdOut); const int fdErr = pipeErr.Detach(wxPipe::Read); wxPipeInputStream *errStream = new wxPipeInputStream(fdErr); process->SetPipeStreams(outStream, inStream, errStream); if ( flags & wxEXEC_SYNC ) { execData.bufOut.Init(outStream); execData.bufErr.Init(errStream); execData.fdOut = fdOut; execData.fdErr = fdErr; } } #endif // HAS_PIPE_STREAMS if ( pipeIn.IsOk() ) { pipeIn.Close(); pipeOut.Close(); pipeErr.Close(); } if ( !(flags & wxEXEC_SYNC) ) { // Ensure that the housekeeping data is kept alive, it will be // destroyed only when the child terminates. execDataPtr.release(); } // Put the housekeeping data into the child process lookup table. // Note that when running asynchronously, if the child has already // finished this call will delete the execData and call any // wxProcess's OnTerminate() handler immediately. execData.OnStart(pid); // For the asynchronous case we don't have to do anything else, just // let the process run (if not already finished). if ( !(flags & wxEXEC_SYNC) ) return pid; // If we don't need to dispatch any events, things are relatively // simple and we don't need to delegate to wxAppTraits. if ( flags & wxEXEC_NOEVENTS ) { return BlockUntilChildExit(execData); } // If we do need to dispatch events, enter a local event loop waiting // until the child exits. As the exact kind of event loop depends on // the sort of application we're in (console or GUI), we delegate this // to wxAppTraits which virtualizes all the differences between the // console and the GUI programs. return wxApp::GetValidTraits().WaitForChild(execData); } #if !defined(__VMS) && !defined(__INTEL_COMPILER) return ERROR_RETURN_CODE; #endif }
// wxExecute: the real worker function long wxExecute(char **argv, int flags, wxProcess *process, const wxExecuteEnv *env) { // for the sync execution, we return -1 to indicate failure, but for async // case we return 0 which is never a valid PID // // we define this as a macro, not a variable, to avoid compiler warnings // about "ERROR_RETURN_CODE value may be clobbered by fork()" #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0) wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") ); #if wxUSE_THREADS // fork() doesn't mix well with POSIX threads: on many systems the program // deadlocks or crashes for some reason. Probably our code is buggy and // doesn't do something which must be done to allow this to work, but I // don't know what yet, so for now just warn the user (this is the least we // can do) about it wxASSERT_MSG( wxThread::IsMain(), wxT("wxExecute() can be called only from the main thread") ); #endif // wxUSE_THREADS #if defined(__WXCOCOA__) || ( defined(__WXOSX_MAC__) && wxOSX_USE_COCOA_OR_CARBON ) // wxMacLaunch() only executes app bundles and only does it asynchronously. // It returns false if the target is not an app bundle, thus falling // through to the regular code for non app bundles. if ( !(flags & wxEXEC_SYNC) && wxMacLaunch(argv) ) { // we don't have any PID to return so just make up something non null return -1; } #endif // __DARWIN__ // this struct contains all information which we use for housekeeping wxExecuteData execData; execData.flags = flags; execData.process = process; // create pipes if ( !execData.pipeEndProcDetect.Create() ) { wxLogError( _("Failed to execute '%s'\n"), *argv ); return ERROR_RETURN_CODE; } // pipes for inter process communication wxPipe pipeIn, // stdin pipeOut, // stdout pipeErr; // stderr if ( process && process->IsRedirected() ) { if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() ) { wxLogError( _("Failed to execute '%s'\n"), *argv ); return ERROR_RETURN_CODE; } } // fork the process // // NB: do *not* use vfork() here, it completely breaks this code for some // reason under Solaris (and maybe others, although not under Linux) // But on OpenVMS we do not have fork so we have to use vfork and // cross our fingers that it works. #ifdef __VMS pid_t pid = vfork(); #else pid_t pid = fork(); #endif if ( pid == -1 ) // error? { wxLogSysError( _("Fork failed") ); return ERROR_RETURN_CODE; } else if ( pid == 0 ) // we're in child { // NB: we used to close all the unused descriptors of the child here // but this broke some programs which relied on e.g. FD 1 being // always opened so don't do it any more, after all there doesn't // seem to be any real problem with keeping them opened #if !defined(__VMS) && !defined(__EMX__) if ( flags & wxEXEC_MAKE_GROUP_LEADER ) { // Set process group to child process' pid. Then killing -pid // of the parent will kill the process and all of its children. setsid(); } #endif // !__VMS // redirect stdin, stdout and stderr if ( pipeIn.IsOk() ) { if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 || dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 || dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 ) { wxLogSysError(_("Failed to redirect child process input/output")); } pipeIn.Close(); pipeOut.Close(); pipeErr.Close(); } // Close all (presumably accidentally) inherited file descriptors to // avoid descriptor leaks. This means that we don't allow inheriting // them purposefully but this seems like a lesser evil in wx code. // Ideally we'd provide some flag to indicate that none (or some?) of // the descriptors do not need to be closed but for now this is better // than never closing them at all as wx code never used FD_CLOEXEC. // Note that while the reading side of the end process detection pipe // can be safely closed, we should keep the write one opened, it will // be only closed when the process terminates resulting in a read // notification to the parent const int fdEndProc = execData.pipeEndProcDetect.Detach(wxPipe::Write); execData.pipeEndProcDetect.Close(); // TODO: Iterating up to FD_SETSIZE is both inefficient (because it may // be quite big) and incorrect (because in principle we could // have more opened descriptions than this number). Unfortunately // there is no good portable solution for closing all descriptors // above a certain threshold but non-portable solutions exist for // most platforms, see [http://stackoverflow.com/questions/899038/ // getting-the-highest-allocated-file-descriptor] for ( int fd = 0; fd < (int)FD_SETSIZE; ++fd ) { if ( fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO && fd != fdEndProc ) { close(fd); } } // Process additional options if we have any if ( env ) { // Change working directory if it is specified if ( !env->cwd.empty() ) wxSetWorkingDirectory(env->cwd); // Change environment if needed. // // NB: We can't use execve() currently because we allow using // non full paths to wxExecute(), i.e. we want to search for // the program in PATH. However it just might be simpler/better // to do the search manually and use execve() envp parameter to // set up the environment of the child process explicitly // instead of doing what we do below. if ( !env->env.empty() ) { wxEnvVariableHashMap oldenv; wxGetEnvMap(&oldenv); // Remove unwanted variables wxEnvVariableHashMap::const_iterator it; for ( it = oldenv.begin(); it != oldenv.end(); ++it ) { if ( env->env.find(it->first) == env->env.end() ) wxUnsetEnv(it->first); } // And add the new ones (possibly replacing the old values) for ( it = env->env.begin(); it != env->env.end(); ++it ) wxSetEnv(it->first, it->second); } } execvp(*argv, argv); fprintf(stderr, "execvp("); for ( char **a = argv; *a; a++ ) fprintf(stderr, "%s%s", a == argv ? "" : ", ", *a); fprintf(stderr, ") failed with error %d!\n", errno); // there is no return after successful exec() _exit(-1); // some compilers complain about missing return - of course, they // should know that exit() doesn't return but what else can we do if // they don't? // // and, sure enough, other compilers complain about unreachable code // after exit() call, so we can just always have return here... #if defined(__VMS) || defined(__INTEL_COMPILER) return 0; #endif } else // we're in parent { // save it for WaitForChild() use execData.pid = pid; if (execData.process) execData.process->SetPid(pid); // and also in the wxProcess // prepare for IO redirection #if HAS_PIPE_STREAMS // the input buffer bufOut is connected to stdout, this is why it is // called bufOut and not bufIn wxStreamTempInputBuffer bufOut, bufErr; if ( process && process->IsRedirected() ) { // Avoid deadlocks which could result from trying to write to the // child input pipe end while the child itself is writing to its // output end and waiting for us to read from it. if ( !pipeIn.MakeNonBlocking(wxPipe::Write) ) { // This message is not terrible useful for the user but what // else can we do? Also, should we fail here or take the risk // to continue and deadlock? Currently we choose the latter but // it might not be the best idea. wxLogSysError(_("Failed to set up non-blocking pipe, " "the program might hang.")); #if wxUSE_LOG wxLog::FlushActive(); #endif } wxOutputStream *inStream = new wxPipeOutputStream(pipeIn.Detach(wxPipe::Write)); const int fdOut = pipeOut.Detach(wxPipe::Read); wxPipeInputStream *outStream = new wxPipeInputStream(fdOut); const int fdErr = pipeErr.Detach(wxPipe::Read); wxPipeInputStream *errStream = new wxPipeInputStream(fdErr); process->SetPipeStreams(outStream, inStream, errStream); bufOut.Init(outStream); bufErr.Init(errStream); execData.bufOut = &bufOut; execData.bufErr = &bufErr; execData.fdOut = fdOut; execData.fdErr = fdErr; } #endif // HAS_PIPE_STREAMS if ( pipeIn.IsOk() ) { pipeIn.Close(); pipeOut.Close(); pipeErr.Close(); } // we want this function to work even if there is no wxApp so ensure // that we have a valid traits pointer wxConsoleAppTraits traitsConsole; wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; if ( !traits ) traits = &traitsConsole; return traits->WaitForChild(execData); } #if !defined(__VMS) && !defined(__INTEL_COMPILER) return ERROR_RETURN_CODE; #endif }