diff --git a/CHANGELOG b/CHANGELOG index 4fd13a98..67f4af1c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -52,6 +52,10 @@ Unlike previous GLVis releases, this version requires a C++17 compiler. - Color palettes defined in an external file can now also be specified in scripts and streams using the keyword 'palette_file'. +- Generalized and unified processing of stream commands for glvis-js to support + all commands. + + Version 4.4 released on May 1, 2025 =================================== diff --git a/CMakeLists.txt b/CMakeLists.txt index 673d491d..a9f1ee7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -258,9 +258,9 @@ if (NOT EMSCRIPTEN) endif (GLVIS_USE_EGL) # Find CGL - if (GLVIS_USE_CGL) + if (GLVIS_USE_CGL AND NOT EMSCRIPTEN) list(APPEND _glvis_compile_defs "GLVIS_USE_CGL") - endif (GLVIS_USE_CGL) + endif (GLVIS_USE_CGL AND NOT EMSCRIPTEN) # Find threading library find_package(Threads REQUIRED) diff --git a/lib/aux_js.cpp b/lib/aux_js.cpp index 71240fab..8bdabfd6 100644 --- a/lib/aux_js.cpp +++ b/lib/aux_js.cpp @@ -42,7 +42,7 @@ namespace js using namespace mfem; /// Display a new stream -void display(std::stringstream & commands, const int w, const int h) +void display(StreamCollection streams, const int w, const int h) { // reset antialiasing if (win.wnd) @@ -50,39 +50,21 @@ void display(std::stringstream & commands, const int w, const int h) win.wnd->getRenderer().setAntialiasing(0); } - std::string word, keys; - double minv = 0.0, maxv = 0.0; - while (commands >> word) - { - if (word == "keys") - { - std::cout << "parsing 'keys'" << std::endl; - commands >> keys; - } - else if (word == "valuerange") - { - std::cout << "parsing 'valuerange'" << std::endl; - commands >> minv >> maxv; - } - else - { - std::cout << "unknown command '" << word << "'" << std::endl; - } - } - win.window_title = "glvis"; win.window_x = 0.; win.window_y = 0.; win.window_w = w; win.window_h = h; - if (!win.GLVisInitVis({})) { return; } + if (!win.GLVisInitVis(std::move(streams))) { return; } - CallKeySequence(keys.c_str()); - - if (minv || maxv) + while (win.comm_thread->process_one()) { - win.vs->SetValueRange(minv, maxv); + if (win.glvis_command->Execute() < 0) + { + // GLVisCommand signalled exit! + break; + } } SendExposeEvent(); @@ -96,61 +78,48 @@ void display(std::stringstream & commands, const int w, const int h) // each string in streams must start with `parallel ' // using StringArray = std::vector; -void processParallelStreams(DataState & state, - const StringArray & streams, - std::stringstream * commands = nullptr) +StreamCollection processParallelStreams(DataState & state, + const StringArray & streams) { // std::cerr << "got " << streams.size() << " streams" << std::endl; - // HACK: match unique_ptr interface for ReadStreams: - std::vector sstreams(streams.size()); StreamCollection istreams(streams.size()); for (int i = 0; i < streams.size(); ++i) { - sstreams[i] = std::stringstream(streams[i]); + istreams[i] = std::unique_ptr(new std::stringstream(streams[i])); // pull off the first list std::string word; int nproc, rank; - sstreams[i] >> word >> nproc >> rank; - // std::cerr << "packing " << rank+1 << "/" << nproc << std::endl; - istreams[i] = std::unique_ptr(&sstreams[i]); + *istreams[i] >> word >> nproc >> rank; } StreamReader reader(state); reader.ReadStreams(istreams); - if (commands) - { - commands->seekg(istreams[0]->tellg()); - } - - // HACK: don't let unique_ptr free the data - for (int i = 0; i < streams.size(); ++i) - { - istreams[i].release(); - } - last_stream_nproc = streams.size(); + + return istreams; } void displayParallelStreams(const StringArray & streams, const int w, const int h) { - std::stringstream commands(streams[0]); - processParallelStreams(win.data_state, streams, &commands); + StreamCollection sc = processParallelStreams(win.data_state, streams); - display(commands, w, h); + display(std::move(sc), w, h); } void displayStream(const std::string & stream, const int w, const int h) { - std::stringstream ss(stream); + std::unique_ptr ss(new std::istringstream(stream)); std::string data_type; - ss >> data_type; + *ss >> data_type; StreamReader reader(win.data_state); - reader.ReadStream(ss, data_type); + reader.ReadStream(*ss, data_type); - display(ss, w, h); + StreamCollection sc; + sc.emplace_back(std::move(ss)); + display(std::move(sc), w, h); } // diff --git a/lib/aux_vis.cpp b/lib/aux_vis.cpp index 7b82c0a8..5aa0b5aa 100644 --- a/lib/aux_vis.cpp +++ b/lib/aux_vis.cpp @@ -523,7 +523,6 @@ void InitIdleFuncs() } } -#ifndef __EMSCRIPTEN__ bool CommunicationIdleFunc() { int status = glvis_command->Execute(); @@ -539,12 +538,11 @@ bool CommunicationIdleFunc() } return false; } -#endif bool MainIdleFunc() { bool sleep = true; -#ifndef __EMSCRIPTEN__ + if (glvis_command && visualize == 1 && !(IdleFuncs.Size() > 0 && use_idle)) { @@ -567,24 +565,8 @@ bool MainIdleFunc() sleep = false; } use_idle = !use_idle; -#else - if (IdleFuncs.Size() > 0) - { - LastIdleFunc = (LastIdleFunc + 1) % IdleFuncs.Size(); - if (IdleFuncs[LastIdleFunc]) - { - (*IdleFuncs[LastIdleFunc])(); - } - // Continue executing idle functions - sleep = false; - } -#endif + return sleep; - LastIdleFunc = (LastIdleFunc + 1) % IdleFuncs.Size(); - if (IdleFuncs[LastIdleFunc]) - { - (*IdleFuncs[LastIdleFunc])(); - } } void AddIdleFunc(void (*Func)(void)) @@ -1376,9 +1358,7 @@ void ThreadsPauseFunc(SDL_Keymod state) { if (state & KMOD_CTRL) { -#ifndef __EMSCRIPTEN__ glvis_command->ToggleAutopause(); -#endif } else { diff --git a/lib/sdl/sdl.cpp b/lib/sdl/sdl.cpp index 641ce482..3dab1594 100644 --- a/lib/sdl/sdl.cpp +++ b/lib/sdl/sdl.cpp @@ -436,7 +436,10 @@ void SdlWindow::signalLoop() lock_guard evt_guard{event_mutex}; call_idle_func = true; } - events_available.notify_all(); + if (is_multithreaded) + { + events_available.notify_all(); + } } void SdlWindow::getWindowSize(int& w, int& h) const diff --git a/lib/threads.cpp b/lib/threads.cpp index e7ea1ca1..f0575d85 100644 --- a/lib/threads.cpp +++ b/lib/threads.cpp @@ -972,21 +972,29 @@ ThreadCommands::ThreadCommands() communication_thread::communication_thread(StreamCollection _is, GLVisCommand* cmd, - bool end_quit_) - : is(std::move(_is)), glvis_command(cmd), end_quit(end_quit_) + bool end_quit_, bool multithread) + : is(std::move(_is)), glvis_command(cmd), end_quit(end_quit_), + is_multithread(multithread) { - new_m = NULL; - new_g = NULL; - - if (is.size() > 0) + if (is_multithread && is.size() > 0) { tid = std::thread(&communication_thread::execute, this); } } +bool communication_thread::process_one() +{ + if (!is[0]->good()) { return false; } + std::string word; + *is[0] >> ws; + if (!is[0]->good()) { return false; } + *is[0] >> word; + return execute_one(word); +} + communication_thread::~communication_thread() { - if (is.size() > 0) + if (is_multithread && is.size() > 0) { terminate_thread = true; tid.join(); @@ -1003,618 +1011,625 @@ void communication_thread::print_commands() } } -void communication_thread::execute() +bool communication_thread::execute_one(std::string ident) { - while (1) + // new solution handled by StreamReader + if (StreamReader::SupportsDataType(ident)) { - *is[0] >> ws; - // thread cancellation point - if (terminate_thread) { break; } + DataState tmp; + tmp.fix_elem_orient = glvis_command->FixElementOrientations(); + StreamReader reader(tmp); + reader.ReadStream(*is[0], ident); - *is[0] >> ident; - if (!(*is[0])) + // cout << "Stream: new solution" << endl; + + if (glvis_command->NewMeshAndSolution(std::move(tmp))) { - break; + return false; } - - // new solution handled by StreamReader - if (StreamReader::SupportsDataType(ident)) + if (!tmp.keys.empty()) { - DataState tmp; - tmp.fix_elem_orient = glvis_command->FixElementOrientations(); - StreamReader reader(tmp); - reader.ReadStream(*is[0], ident); - if (!(*is[0])) - { - break; - } - - // cout << "Stream: new solution" << endl; - - if (glvis_command->NewMeshAndSolution(std::move(tmp))) + if (glvis_command->KeyCommands(tmp.keys.c_str())) { - goto comm_terminate; + return false; } - if (!tmp.keys.empty()) - { - if (glvis_command->KeyCommands(tmp.keys.c_str())) - { - goto comm_terminate; - } - } - continue; } + return true; + } - auto it = find(commands.begin(), commands.end(), ident); - if (it == commands.end()) - { - cout << "Stream: unknown command: " << ident << endl; - print_commands(); - goto comm_terminate; - } + auto it = find(commands.begin(), commands.end(), ident); + if (it == commands.end()) + { + cout << "Stream: unknown command: " << ident << endl; + print_commands(); + return false; + } - const ThreadCommand cmd = (ThreadCommand)(it - commands.begin()); - switch (cmd) + const ThreadCommand cmd = (ThreadCommand)(it - commands.begin()); + switch (cmd) + { + case ThreadCommand::Parallel: { - case ThreadCommand::Parallel: + unsigned int proc, nproc, np = 0; + do { - unsigned int proc, nproc, np = 0; - do - { - istream &isock = *is[np]; - isock >> nproc >> proc >> ws; + istream &isock = *is[np]; + isock >> nproc >> proc >> ws; #ifdef GLVIS_DEBUG - cout << "connection[" << np << "]: parallel " << nproc << ' ' - << proc << endl; + cout << "connection[" << np << "]: parallel " << nproc << ' ' + << proc << endl; #endif - if (nproc != is.size()) - { - cout << "Unexpected number of processors: " << nproc - << ", expected: " << is.size() << endl; - mfem_error(); - } - if (proc >= nproc) - { - cout << "Invalid processor rank: " << proc - << ", number of processors: " << nproc << endl; - mfem_error(); - } - np++; - if (np == nproc) - { - break; - } - *is[np] >> ident >> ws; // "parallel" - if (ident != "parallel") - { - cout << "Expected keyword \"parallel\", got \"" << ident - << '"' << endl; - mfem_error(); - } + if (nproc != is.size()) + { + cout << "Unexpected number of processors: " << nproc + << ", expected: " << is.size() << endl; + mfem_error(); } - while (1); - - DataState tmp; - tmp.fix_elem_orient = glvis_command->FixElementOrientations(); - tmp.keep_attr = glvis_command->KeepAttrib(); - StreamReader reader(tmp); - reader.ReadStreams(is); - - // cout << "Stream: new solution" << endl; - - if (glvis_command->NewMeshAndSolution(std::move(tmp))) + if (proc >= nproc) { - goto comm_terminate; + cout << "Invalid processor rank: " << proc + << ", number of processors: " << nproc << endl; + mfem_error(); } - } - break; - case ThreadCommand::Screenshot: - { - string filename; - - *is[0] >> ws >> filename; - - // all processors sent the screenshot command - for (size_t i = 1; i < is.size(); i++) + np++; + if (np == nproc) { - *is[i] >> ws >> ident; // 'screenshot' - *is[i] >> ws >> ident; // filename + break; } - - if (glvis_command->Screenshot(filename.c_str())) + *is[np] >> ident >> ws; // "parallel" + if (ident != "parallel") { - goto comm_terminate; + cout << "Expected keyword \"parallel\", got \"" << ident + << '"' << endl; + mfem_error(); } } - break; - case ThreadCommand::Keys: - { - string keys; + while (1); - *is[0] >> ws >> keys; + DataState tmp; + tmp.fix_elem_orient = glvis_command->FixElementOrientations(); + tmp.keep_attr = glvis_command->KeepAttrib(); + StreamReader reader(tmp); + reader.ReadStreams(is); - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'keys' - *is[i] >> ws >> ident; // keys - } + // cout << "Stream: new solution" << endl; - if (glvis_command->KeyCommands(keys.c_str())) - { - goto comm_terminate; - } + if (glvis_command->NewMeshAndSolution(std::move(tmp))) + { + return false; } - break; - case ThreadCommand::WindowSize: + } + break; + case ThreadCommand::Screenshot: + { + string filename; + + *is[0] >> ws >> filename; + + // all processors sent the screenshot command + for (size_t i = 1; i < is.size(); i++) { - int w, h, t; + *is[i] >> ws >> ident; // 'screenshot' + *is[i] >> ws >> ident; // filename + } - *is[0] >> w >> h; + if (glvis_command->Screenshot(filename.c_str())) + { + return false; + } + } + break; + case ThreadCommand::Keys: + { + string keys; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'window_size' - *is[i] >> t >> t; - } + *is[0] >> ws >> keys; - if (glvis_command->WindowSize(w, h)) - { - goto comm_terminate; - } + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) + { + *is[i] >> ws >> ident; // 'keys' + *is[i] >> ws >> ident; // keys } - break; - case ThreadCommand::WindowGeometry: + + if (glvis_command->KeyCommands(keys.c_str())) { - int x, y, w, h, t; + return false; + } + } + break; + case ThreadCommand::WindowSize: + { + int w, h, t; - *is[0] >> x >> y >> w >> h; + *is[0] >> w >> h; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'window_geometry' - *is[i] >> t >> t >> t >> t; - } - - if (glvis_command->WindowGeometry(x, y, w, h)) - { - goto comm_terminate; - } + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) + { + *is[i] >> ws >> ident; // 'window_size' + *is[i] >> t >> t; } - break; - case ThreadCommand::WindowTitle: + + if (glvis_command->WindowSize(w, h)) { - char c; - string title; + return false; + } + } + break; + case ThreadCommand::WindowGeometry: + { + int x, y, w, h, t; - // read the opening char - *is[0] >> ws >> c; - // use the opening char as termination as well - getline(*is[0], title, c); + *is[0] >> x >> y >> w >> h; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'window_title' - *is[i] >> ws >> c; - getline(*is[i], ident, c); - } + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) + { + *is[i] >> ws >> ident; // 'window_geometry' + *is[i] >> t >> t >> t >> t; + } - if (glvis_command->WindowTitle(title.c_str())) - { - goto comm_terminate; - } + if (glvis_command->WindowGeometry(x, y, w, h)) + { + return false; } - break; - case ThreadCommand::PlotCaption: + } + break; + case ThreadCommand::WindowTitle: + { + char c; + string title; + + // read the opening char + *is[0] >> ws >> c; + // use the opening char as termination as well + getline(*is[0], title, c); + + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - char c; - string caption; + *is[i] >> ws >> ident; // 'window_title' + *is[i] >> ws >> c; + getline(*is[i], ident, c); + } - // read the opening char - *is[0] >> ws >> c; - // use the opening char as termination as well - getline(*is[0], caption, c); + if (glvis_command->WindowTitle(title.c_str())) + { + return false; + } + } + break; + case ThreadCommand::PlotCaption: + { + char c; + string caption; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'plot_caption' - *is[i] >> ws >> c; - getline(*is[i], ident, c); - } + // read the opening char + *is[0] >> ws >> c; + // use the opening char as termination as well + getline(*is[0], caption, c); - if (glvis_command->PlotCaption(caption.c_str())) - { - goto comm_terminate; - } + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) + { + *is[i] >> ws >> ident; // 'plot_caption' + *is[i] >> ws >> c; + getline(*is[i], ident, c); } - break; - case ThreadCommand::AxisLabels: - { - char c; - string label_x, label_y, label_z; - - // read the opening char - *is[0] >> ws >> c; - // use the opening char as termination as well - getline(*is[0], label_x, c); - *is[0] >> ws >> c; - getline(*is[0], label_y, c); - *is[0] >> ws >> c; - getline(*is[0], label_z, c); - - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'axis_label' - *is[i] >> ws >> c; - getline(*is[i], ident, c); - *is[i] >> ws >> c; - getline(*is[i], ident, c); - *is[i] >> ws >> c; - getline(*is[i], ident, c); - } - if (glvis_command->AxisLabels(label_x.c_str(), - label_y.c_str(), - label_z.c_str())) - { - goto comm_terminate; - } + if (glvis_command->PlotCaption(caption.c_str())) + { + return false; } - break; - case ThreadCommand::Pause: + } + break; + case ThreadCommand::AxisLabels: + { + char c; + string label_x, label_y, label_z; + + // read the opening char + *is[0] >> ws >> c; + // use the opening char as termination as well + getline(*is[0], label_x, c); + *is[0] >> ws >> c; + getline(*is[0], label_y, c); + *is[0] >> ws >> c; + getline(*is[0], label_z, c); + + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'pause' - } + *is[i] >> ws >> ident; // 'axis_label' + *is[i] >> ws >> c; + getline(*is[i], ident, c); + *is[i] >> ws >> c; + getline(*is[i], ident, c); + *is[i] >> ws >> c; + getline(*is[i], ident, c); + } - if (glvis_command->Pause()) - { - goto comm_terminate; - } + if (glvis_command->AxisLabels(label_x.c_str(), + label_y.c_str(), + label_z.c_str())) + { + return false; } - break; - case ThreadCommand::View: + } + break; + case ThreadCommand::Pause: + { + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - double theta, phi, a; + *is[i] >> ws >> ident; // 'pause' + } - *is[0] >> theta >> phi; + if (glvis_command->Pause()) + { + return false; + } + } + break; + case ThreadCommand::View: + { + double theta, phi, a; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'view' - *is[i] >> a >> a; - } + *is[0] >> theta >> phi; - if (glvis_command->ViewAngles(theta, phi)) - { - goto comm_terminate; - } - } - break; - case ThreadCommand::Zoom: + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - double factor, a; + *is[i] >> ws >> ident; // 'view' + *is[i] >> a >> a; + } - *is[0] >> factor; + if (glvis_command->ViewAngles(theta, phi)) + { + return false; + } + } + break; + case ThreadCommand::Zoom: + { + double factor, a; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'zoom' - *is[i] >> a; - } + *is[0] >> factor; - if (glvis_command->Zoom(factor)) - { - goto comm_terminate; - } - } - break; - case ThreadCommand::Subdivisions: + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - int tot, bdr, a; + *is[i] >> ws >> ident; // 'zoom' + *is[i] >> a; + } - *is[0] >> tot >> bdr; + if (glvis_command->Zoom(factor)) + { + return false; + } + } + break; + case ThreadCommand::Subdivisions: + { + int tot, bdr, a; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'subdivisions' - *is[i] >> a >> a; - } + *is[0] >> tot >> bdr; - if (glvis_command->Subdivisions(tot, bdr)) - { - goto comm_terminate; - } - } - break; - case ThreadCommand::Valuerange: + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - double minv, maxv, a; + *is[i] >> ws >> ident; // 'subdivisions' + *is[i] >> a >> a; + } - *is[0] >> minv >> maxv; + if (glvis_command->Subdivisions(tot, bdr)) + { + return false; + } + } + break; + case ThreadCommand::Valuerange: + { + double minv, maxv, a; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'valuerange' - *is[i] >> a >> a; - } + *is[0] >> minv >> maxv; - if (glvis_command->ValueRange(minv, maxv)) - { - goto comm_terminate; - } - } - break; - case ThreadCommand::Levellines: + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - double minv, maxv, a; - int num, b; + *is[i] >> ws >> ident; // 'valuerange' + *is[i] >> a >> a; + } - *is[0] >> minv >> maxv >> num; + if (glvis_command->ValueRange(minv, maxv)) + { + return false; + } + } + break; + case ThreadCommand::Levellines: + { + double minv, maxv, a; + int num, b; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'levellines' - *is[i] >> a >> a >> b; - } + *is[0] >> minv >> maxv >> num; - if (glvis_command->Levellines(minv, maxv, num)) - { - goto comm_terminate; - } - } - break; - case ThreadCommand::AxisNumberFormat: + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - char c; - string formatting; + *is[i] >> ws >> ident; // 'levellines' + *is[i] >> a >> a >> b; + } - // read the opening char - *is[0] >> ws >> c; - // read formatting string & use c for termination - getline(*is[0], formatting, c); + if (glvis_command->Levellines(minv, maxv, num)) + { + return false; + } + } + break; + case ThreadCommand::AxisNumberFormat: + { + char c; + string formatting; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'axis_numberformat' - *is[i] >> ws >> c; - getline(*is[i], ident, c); - } + // read the opening char + *is[0] >> ws >> c; + // read formatting string & use c for termination + getline(*is[0], formatting, c); - if (glvis_command->AxisNumberFormat(formatting)) - { - goto comm_terminate; - } - } - break; - case ThreadCommand::ColorbarNumberFormat: + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - char c; - string formatting; + *is[i] >> ws >> ident; // 'axis_numberformat' + *is[i] >> ws >> c; + getline(*is[i], ident, c); + } - // read the opening char - *is[0] >> ws >> c; - // read formatting string & use c for termination - getline(*is[0], formatting, c); + if (glvis_command->AxisNumberFormat(formatting)) + { + return false; + } + } + break; + case ThreadCommand::ColorbarNumberFormat: + { + char c; + string formatting; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'colorbar_numberformat' - *is[i] >> ws >> c; - getline(*is[i], ident, c); - } + // read the opening char + *is[0] >> ws >> c; + // read formatting string & use c for termination + getline(*is[0], formatting, c); - if (glvis_command->ColorbarNumberFormat(formatting)) - { - goto comm_terminate; - } - } - break; - case ThreadCommand::Shading: + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - string shd; + *is[i] >> ws >> ident; // 'colorbar_numberformat' + *is[i] >> ws >> c; + getline(*is[i], ident, c); + } - *is[0] >> ws >> shd; + if (glvis_command->ColorbarNumberFormat(formatting)) + { + return false; + } + } + break; + case ThreadCommand::Shading: + { + string shd; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'shading' - *is[i] >> ws >> ident; - } + *is[0] >> ws >> shd; - if (glvis_command->SetShading(shd.c_str())) - { - goto comm_terminate; - } - } - break; - case ThreadCommand::Viewcenter: + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - double x, y, a; + *is[i] >> ws >> ident; // 'shading' + *is[i] >> ws >> ident; + } - *is[0] >> x >> y; + if (glvis_command->SetShading(shd.c_str())) + { + return false; + } + } + break; + case ThreadCommand::Viewcenter: + { + double x, y, a; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'viewcenter' - *is[i] >> a >> a; - } + *is[0] >> x >> y; - if (glvis_command->ViewCenter(x, y)) - { - goto comm_terminate; - } - } - break; - case ThreadCommand::Autoscale: + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - string mode; + *is[i] >> ws >> ident; // 'viewcenter' + *is[i] >> a >> a; + } - *is[0] >> ws >> mode; + if (glvis_command->ViewCenter(x, y)) + { + return false; + } + } + break; + case ThreadCommand::Autoscale: + { + string mode; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'autoscale' - *is[i] >> ws >> ident; - } + *is[0] >> ws >> mode; - if (glvis_command->Autoscale(mode.c_str())) - { - goto comm_terminate; - } - } - break; - case ThreadCommand::Palette: + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - int pal, a; + *is[i] >> ws >> ident; // 'autoscale' + *is[i] >> ws >> ident; + } - *is[0] >> pal; + if (glvis_command->Autoscale(mode.c_str())) + { + return false; + } + } + break; + case ThreadCommand::Palette: + { + int pal, a; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'palette' - *is[i] >> a; - } + *is[0] >> pal; - if (glvis_command->Palette(pal)) - { - goto comm_terminate; - } + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) + { + *is[i] >> ws >> ident; // 'palette' + *is[i] >> a; } - break; - case ThreadCommand::PaletteFile: + + if (glvis_command->Palette(pal)) { - std::string filename, a; + return false; + } + } + break; + case ThreadCommand::PaletteFile: + { + std::string filename, a; - *is[0] >> ws; - std::getline(*is[0], filename); + *is[0] >> ws; + std::getline(*is[0], filename); - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'palette_file' - *is[i] >> a; - } + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) + { + *is[i] >> ws >> ident; // 'palette_file' + *is[i] >> a; + } - if (glvis_command->PaletteFile(filename)) - { - goto comm_terminate; - } + if (glvis_command->PaletteFile(filename)) + { + return false; } - break; - case ThreadCommand::PaletteName: + } + break; + case ThreadCommand::PaletteName: + { + std::string palname, a; + + *is[0] >> palname; + + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) { - std::string palname, a; + *is[i] >> ws >> ident; // 'palette_name' + *is[i] >> a; + } - *is[0] >> palname; + if (glvis_command->PaletteName(palname)) + { + return false; + } + } + break; + case ThreadCommand::PaletteRepeat: + { + int n, a; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'palette_name' - *is[i] >> a; - } + *is[0] >> n; - if (glvis_command->PaletteName(palname)) - { - goto comm_terminate; - } + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) + { + *is[i] >> ws >> ident; // 'palette_repeat' + *is[i] >> a; } - break; - case ThreadCommand::PaletteRepeat: + + if (glvis_command->PaletteRepeat(n)) { - int n, a; + return false; + } + } + break; + case ThreadCommand::Camera: + { + double cam[9], a; - *is[0] >> n; + for (int i = 0; i < 9; i++) + { + *is[0] >> cam[i]; + } - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) + { + *is[i] >> ws >> ident; // 'camera' + for (int j = 0; j < 9; j++) { - *is[i] >> ws >> ident; // 'palette_repeat' *is[i] >> a; } - - if (glvis_command->PaletteRepeat(n)) - { - goto comm_terminate; - } } - break; - case ThreadCommand::Camera: + + if (glvis_command->Camera(cam)) { - double cam[9], a; + return false; + } + } + break; + case ThreadCommand::Autopause: + { + string mode; - for (int i = 0; i < 9; i++) - { - *is[0] >> cam[i]; - } + *is[0] >> ws >> mode; - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'camera' - for (int j = 0; j < 9; j++) - { - *is[i] >> a; - } - } + // all processors sent the command + for (size_t i = 1; i < is.size(); i++) + { + *is[i] >> ws >> ident; // 'autopause' + *is[i] >> ws >> ident; + } - if (glvis_command->Camera(cam)) - { - goto comm_terminate; - } + if (glvis_command->Autopause(mode.c_str())) + { + return false; } + } + break; + case ThreadCommand::Max: //dummy break; - case ThreadCommand::Autopause: - { - string mode; + } - *is[0] >> ws >> mode; + return true; +} - // all processors sent the command - for (size_t i = 1; i < is.size(); i++) - { - *is[i] >> ws >> ident; // 'autopause' - *is[i] >> ws >> ident; - } +void communication_thread::execute() +{ + std::string ident; + bool status = true; - if (glvis_command->Autopause(mode.c_str())) - { - goto comm_terminate; - } - } + while (status) + { + *is[0] >> ws; + // thread cancellation point + if (terminate_thread) { break; } + + *is[0] >> ident; + if (!(*is[0])) + { break; - case ThreadCommand::Max: //dummy - break; } - } - cout << "Stream: end of input." << endl; + status = execute_one(ident); + } - if (end_quit) + if (status) { - glvis_command->Quit(); + cout << "Stream: end of input." << endl; + if (end_quit) + { + glvis_command->Quit(); + } } -comm_terminate: for (size_t i = 0; i < is.size(); i++) { socketstream *isock = dynamic_cast(is[i].get()); diff --git a/lib/threads.hpp b/lib/threads.hpp index 2178da66..8b3248ef 100644 --- a/lib/threads.hpp +++ b/lib/threads.hpp @@ -164,11 +164,6 @@ class communication_thread GLVisCommand* glvis_command; - // data that may be dynamically allocated by the thread - std::unique_ptr new_m; - std::unique_ptr new_g; - std::string ident; - // thread object std::thread tid; // signal for thread cancellation @@ -177,12 +172,18 @@ class communication_thread // flag for closing the window at the end of stream bool end_quit; + // flag for parallel commands execution thread + bool is_multithread; + static void print_commands(); + bool execute_one(std::string word); void execute(); public: communication_thread(StreamCollection _is, GLVisCommand* cmd, - bool end_quit = false); + bool end_quit = false, bool mulithread = true); + + bool process_one(); ~communication_thread(); }; diff --git a/lib/visual.hpp b/lib/visual.hpp index c91db030..9a7fcf83 100644 --- a/lib/visual.hpp +++ b/lib/visual.hpp @@ -22,9 +22,7 @@ #include "vssolution3d.hpp" #include "vsvector.hpp" #include "vsvector3d.hpp" -#ifndef __EMSCRIPTEN__ #include "threads.hpp" -#endif #include "gl/types.hpp" #endif // GLVIS_VISUAL_HPP diff --git a/lib/vsdata.cpp b/lib/vsdata.cpp index 8eced894..c43d4dc6 100644 --- a/lib/vsdata.cpp +++ b/lib/vsdata.cpp @@ -19,9 +19,7 @@ #include "aux_vis.hpp" #include "material.hpp" #include "palettes.hpp" -#ifndef __EMSCRIPTEN__ #include "threads.hpp" -#endif using namespace std; using namespace mfem; diff --git a/lib/vssolution.cpp b/lib/vssolution.cpp index 43f21756..2c848987 100644 --- a/lib/vssolution.cpp +++ b/lib/vssolution.cpp @@ -9,7 +9,9 @@ // terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. -#include "visual.hpp" +#include "vssolution.hpp" + +#include "threads.hpp" #include "palettes.hpp" #include "gltf.hpp" diff --git a/lib/vssolution3d.cpp b/lib/vssolution3d.cpp index 3a9d4d2b..2383fb3e 100644 --- a/lib/vssolution3d.cpp +++ b/lib/vssolution3d.cpp @@ -9,15 +9,15 @@ // terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. +#include "vssolution3d.hpp" + #include #include #include #include -#include - +#include "threads.hpp" #include "palettes.hpp" -#include "visual.hpp" using namespace std; using namespace mfem; diff --git a/lib/vsvector.cpp b/lib/vsvector.cpp index 2c47c41d..ba006d28 100644 --- a/lib/vsvector.cpp +++ b/lib/vsvector.cpp @@ -9,13 +9,14 @@ // terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. +#include "vsvector.hpp" + #include #include #include #include -#include -#include "visual.hpp" +#include "threads.hpp" using namespace mfem; using namespace std; diff --git a/lib/vsvector3d.cpp b/lib/vsvector3d.cpp index 348100af..244ceb01 100644 --- a/lib/vsvector3d.cpp +++ b/lib/vsvector3d.cpp @@ -9,12 +9,14 @@ // terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. +#include "vsvector3d.hpp" + #include #include #include #include -#include "visual.hpp" +#include "threads.hpp" using namespace mfem; using namespace std; diff --git a/lib/window.cpp b/lib/window.cpp index 9a11dffe..eea18226 100644 --- a/lib/window.cpp +++ b/lib/window.cpp @@ -58,19 +58,24 @@ bool Window::GLVisInitVis(StreamCollection input_streams) return false; } -#ifndef __EMSCRIPTEN__ if (input_streams.size() > 0) { +#ifndef __EMSCRIPTEN__ if (!headless) { wnd->setOnKeyDown(SDLK_SPACE, ThreadsPauseFunc); } +#endif internal.glvis_command.reset(new GLVisCommand(*this)); SetGLVisCommand(glvis_command.get()); +#ifndef __EMSCRIPTEN__ + constexpr bool multithreaded = true; +#else + constexpr bool multithreaded = false; +#endif internal.comm_thread.reset(new communication_thread(std::move(input_streams), - glvis_command.get(), headless)); + glvis_command.get(), headless, multithreaded)); } -#endif locwin = this; @@ -175,14 +180,12 @@ void Window::GLVisStartVis() RunVisualization(); internal.vs.reset(); internal.wnd.reset(); -#ifndef __EMSCRIPTEN__ if (glvis_command) { glvis_command->Terminate(); internal.comm_thread.reset(); internal.glvis_command.reset(); } -#endif std::cout << "GLVis window closed." << std::endl; } diff --git a/lib/window.hpp b/lib/window.hpp index b417e875..6943251d 100644 --- a/lib/window.hpp +++ b/lib/window.hpp @@ -29,20 +29,16 @@ struct Window { std::unique_ptr wnd; std::unique_ptr vs; -#ifndef __EMSCRIPTEN__ std::unique_ptr comm_thread; std::unique_ptr glvis_command; -#endif } internal; public: DataState data_state; const std::unique_ptr &wnd{internal.wnd}; const std::unique_ptr &vs{internal.vs}; -#ifndef __EMSCRIPTEN__ const std::unique_ptr &comm_thread {internal.comm_thread}; const std::unique_ptr &glvis_command{internal.glvis_command}; -#endif int window_x = 0; // not a command line option int window_y = 0; // not a command line option diff --git a/makefile b/makefile index 6827a74c..2fe2e491 100644 --- a/makefile +++ b/makefile @@ -279,8 +279,8 @@ ALL_SOURCE_FILES = \ lib/vsvector.cpp lib/vsvector3d.cpp lib/window.cpp OBJC_SOURCE_FILES = $(if $(NOTMAC),,lib/sdl/sdl_mac.mm) DESKTOP_ONLY_SOURCE_FILES = \ - lib/gl/renderer_ff.cpp lib/threads.cpp lib/gl2ps.c \ - lib/script_controller.cpp lib/sdl/sdl_x11.cpp + lib/gl/renderer_ff.cpp lib/gl2ps.c lib/script_controller.cpp \ + lib/sdl/sdl_x11.cpp WEB_ONLY_SOURCE_FILES = lib/aux_js.cpp LOGO_FILE = share/logo.rgba LOGO_FILE_CPP = $(LOGO_FILE).bin.cpp @@ -321,7 +321,7 @@ BYTECODE_FILES = $(WEB_SOURCE_FILES:.cpp=.bc) $(CCC) -o $@ -c $< %.bc: %.cpp - $(EMCC) $(EMCC_OPTS) $(GLVIS_FLAGS) -c $< -o $@ + $(EMCC) $(EMCC_OPTS) $(filter-out ${CGL_OPTS},${GLVIS_FLAGS}) -c $< -o $@ glvis: glvis.cpp lib/libglvis.a $(CONFIG_MK) $(MFEM_LIB_FILE) $(CCC) -o glvis glvis.cpp -Llib -lglvis $(LIBS)