Skip to content

Commit cb163eb

Browse files
author
Kasper Peeters
committed
Add restart-and-run button. Fix update of server status line.
1 parent 7e4d289 commit cb163eb

9 files changed

Lines changed: 139 additions & 26 deletions

File tree

client_server/ComputeThread.cc

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,17 @@ void ComputeThread::all_cells_nonrunning()
124124

125125
void ComputeThread::on_fail(const boost::beast::error_code& ec)
126126
{
127-
std::cerr << "cadabra-client: connection to server on port " << port << " failed, " << ec.message() << std::endl;
127+
if(!restarting_kernel) {
128+
std::cerr << "cadabra-client: connection to server on port " << port << " failed, " << ec.message() << std::endl;
129+
}
128130
connection_is_open=false;
129131
all_cells_nonrunning();
130132
if(gui && server_pid!=0) {
133+
// When a kernel restart is in progress, server_pid will be zero
134+
// and this block never runs.
131135
close(server_stdout);
132136
// close(server_stderr);
137+
// std::cerr << "closing connetion to terminated server" << std::endl;
133138
Glib::spawn_close_pid(server_pid);
134139
// kill(server_pid, SIGKILL);
135140
server_pid=0;
@@ -460,7 +465,8 @@ void ComputeThread::on_message(const std::string& msg)
460465
std::make_shared<ActionPositionCursor>(parent_id, ActionPositionCursor::Position::in);
461466
docthread->queue_action(actionpos);
462467

463-
// FIXME: iterate over all cells and set the running flag to false.
468+
// Action has stopped, so mark all cells as non-running.
469+
all_cells_nonrunning();
464470
}
465471
else if (msg_type == "image_png") {
466472
DataCell result(cell_id, DataCell::CellType::image_png, content["output"].get<std::string>());
@@ -525,7 +531,7 @@ void ComputeThread::execute_interactive(uint64_t id, const std::string& code)
525531
std::ostringstream oss;
526532
oss << req << std::endl;
527533
if(getenv("CADABRA_SHOW_SENT")) {
528-
std::cerr << "SEND: " << req.dump(3) << std::endl;
534+
std::cerr << "SENT: " << req.dump(3) << std::endl;
529535
}
530536
wsclient.send(oss.str());
531537
interactive_cells.insert(id);
@@ -593,7 +599,7 @@ void ComputeThread::execute_cell(DTree::iterator it, std::string no_assign, std:
593599
std::ostringstream str;
594600
str << req << std::endl;
595601
if(getenv("CADABRA_SHOW_SENT")) {
596-
std::cerr << "SEND: " << req.dump(3) << std::endl;
602+
std::cerr << "SENT: " << req.dump(3) << std::endl;
597603
}
598604
wsclient.send(str.str());
599605
// NOTE: we can get a return message in on_message at any point after this,
@@ -628,7 +634,7 @@ void ComputeThread::update_variable_on_server(std::string variable, double value
628634
std::ostringstream str;
629635
str << req << std::endl;
630636
if(getenv("CADABRA_SHOW_SENT")) {
631-
std::cerr << "SEND: " << req.dump(3) << std::endl;
637+
std::cerr << "SENT: " << req.dump(3) << std::endl;
632638
}
633639
wsclient.send(str.str());
634640
}
@@ -644,6 +650,8 @@ void ComputeThread::stop()
644650
if(connection_is_open==false)
645651
return;
646652

653+
// std::cerr << "stopping existing kernel" << std::endl;
654+
647655
nlohmann::json req, header, content;
648656
header["uuid"]="none";
649657
header["msg_type"]="execute_interrupt";
@@ -657,10 +665,12 @@ void ComputeThread::stop()
657665

658666
server_pid=0;
659667
if(getenv("CADABRA_SHOW_SENT")) {
660-
std::cerr << "SEND: " << req.dump(3) << std::endl;
668+
std::cerr << "SENT: " << req.dump(3) << std::endl;
661669
}
662670
wsclient.send(str.str());
663-
all_cells_nonrunning();
671+
// Do not yet mark cells non-running, otherwise we are unable to
672+
// process any error messages. Do this once the stop comes through.
673+
// all_cells_nonrunning();
664674
}
665675

666676
void ComputeThread::restart_kernel()
@@ -689,7 +699,7 @@ void ComputeThread::restart_kernel()
689699
// std::cerr << str.str() << std::endl;
690700

691701
if(getenv("CADABRA_SHOW_SENT")) {
692-
std::cerr << "SEND: " << req.dump(3) << std::endl;
702+
std::cerr << "SENT: " << req.dump(3) << std::endl;
693703
}
694704
wsclient.send(str.str());
695705
docthread->on_interactive_output(req);

client_server/DocumentThread.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,16 +290,16 @@ void DocumentThread::run_cells_referencing_variable(std::string variable, double
290290

291291
void DocumentThread::process_action_queue()
292292
{
293-
// FIXME: we certainly do not want any two threads to run this at the same time,
294-
// but that is not guaranteed. Actions should always be run on the GUI thread.
295-
// This absolutely has to be run on the main GUI thread.
293+
// This routine *absolutely* has to be run on the main GUI thread. Anything
294+
// else is a bug.
296295

297296
if(main_thread_id != std::this_thread::get_id())
298297
std::cerr << "INTERNAL ERROR: DocumentThread::process_action_queue not running on main thread."
299298
<< std::endl;
300299

301300
stack_mutex.lock();
302301
while(pending_actions.size()>0) {
302+
// std::cerr << "pending_actions.size() == " << pending_actions.size() << std::endl;
303303
std::shared_ptr<ActionBase> ab = pending_actions.front();
304304
// Unlock the action queue while we are processing this particular action,
305305
// so that other actions can be added which we run.

client_server/Server.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -327,9 +327,9 @@ void Server::on_close(websocket_server::id_type ws_id)
327327

328328
int quit(void *)
329329
{
330-
std::cerr << "Server: setting python interrupt." << std::endl;
330+
// std::cerr << "Server: setting python interrupt." << std::endl;
331331
PyErr_SetInterrupt();
332-
std::cerr << "Server: python interrupt set." << std::endl;
332+
// std::cerr << "Server: python interrupt set." << std::endl;
333333
return -1;
334334
}
335335

@@ -441,7 +441,7 @@ void Server::wait_for_job()
441441
void Server::stop_block()
442442
{
443443
// interrupt_block=true;
444-
std::cerr << "Server: sending SIGINT to python thread." << std::endl;
444+
// std::cerr << "Server: sending SIGINT to python thread." << std::endl;
445445
PyErr_SetInterrupt();
446446

447447
// PyGILState_STATE state = PyGILState_Ensure();
@@ -533,12 +533,12 @@ void Server::dispatch_message(websocket_server::id_type ws_id, const std::string
533533
}
534534
else if(msg_type=="execute_interrupt") {
535535
std::unique_lock<std::mutex> lock(block_available_mutex);
536-
std::cerr << "Server: requesting python thread stop." << std::endl;
536+
// std::cerr << "Server: requesting python thread stop." << std::endl;
537537
stop_block();
538-
std::cerr << "Server: clearing block queue." << std::endl;
538+
// std::cerr << "Server: clearing block queue." << std::endl;
539539
std::queue<Block> empty;
540540
std::swap(block_queue, empty);
541-
std::cerr << "Server: block queue cleared." << std::endl;
541+
// std::cerr << "Server: block queue cleared." << std::endl;
542542
//snoop::log(snoop::warn) << "Job stop requested." << snoop::flush;
543543
}
544544
else if(msg_type=="init") {

frontend/gtkmm/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ set(CDBICONS
250250
cdb-copy-all
251251
cdb-open
252252
cdb-restart
253+
cdb-restart-and-run-all
253254
cdb-run
254255
cdb-save-as
255256
cdb-save

frontend/gtkmm/NotebookWindow.cc

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ NotebookWindow::NotebookWindow(Cadabra *c, bool ro, std::string geometry, std::s
7373
, tex_running(false), tex_need_width(0)
7474
, last_find_location(doc.end(), std::string::npos)
7575
, is_configured(false)
76-
76+
, run_all_after_restart(false)
7777
{
7878
}
7979

@@ -287,6 +287,7 @@ void NotebookWindow::on_realize()
287287

288288
// Kernel menu actions.
289289
actiongroup->add_action( "KernelRestart", sigc::mem_fun(*this, &NotebookWindow::on_kernel_restart) );
290+
actiongroup->add_action( "KernelRestartRun", sigc::mem_fun(*this, &NotebookWindow::on_kernel_restart_and_run_all) );
290291

291292
// Tools menu actions.
292293
actiongroup->add_action( "CompareFile", sigc::mem_fun(*this, &NotebookWindow::compare_to_file) );
@@ -579,6 +580,10 @@ void NotebookWindow::on_realize()
579580
" <attribute name='label'>Restart kernel</attribute>"
580581
" <attribute name='action'>cdb.KernelRestart</attribute>"
581582
" </item>"
583+
" <item>"
584+
" <attribute name='label'>Restart kernel and run notebook</attribute>"
585+
" <attribute name='action'>cdb.KernelRestartRun</attribute>"
586+
" </item>"
582587
" </section>"
583588
" </submenu>"
584589
" <submenu>"
@@ -708,6 +713,13 @@ void NotebookWindow::on_realize()
708713
false));
709714
tool_restart.get_accessible()->set_name("Restart kernel");
710715

716+
// Restart-and-run-all button.
717+
tool_restart_and_run_all.add(*Gtk::make_managed<ImageArea>(
718+
40/display_scale, display_scale,
719+
install_prefix()+"/share/cadabra2/cdb-icons/cdb-restart-and-run-all"+ICONEXT,
720+
false));
721+
tool_restart_and_run_all.get_accessible()->set_name("Restart kernel and run notebook");
722+
711723
// Open button.
712724
tool_open.add(*Gtk::make_managed<ImageArea>(
713725
40/display_scale, display_scale,
@@ -732,13 +744,15 @@ void NotebookWindow::on_realize()
732744
tool_stop.set_size_request(70/display_scale, 70/display_scale);
733745
tool_run.set_size_request(70/display_scale, 70/display_scale);
734746
tool_restart.set_size_request(70/display_scale, 70/display_scale);
747+
tool_restart_and_run_all.set_size_request(70/display_scale, 70/display_scale);
735748
tool_open.set_size_request(70/display_scale, 70/display_scale);
736749
tool_save.set_size_request(70/display_scale, 70/display_scale);
737750
tool_save_as.set_size_request(70/display_scale, 70/display_scale);
738751

739752
tool_run.set_tooltip_text("Execute all cells");
740753
tool_stop.set_tooltip_text("Stop execution");
741754
tool_restart.set_tooltip_text("Restart kernel");
755+
tool_restart_and_run_all.set_tooltip_text("Restart kernel and run entire notebook");
742756
tool_open.set_tooltip_text("Open notebook...");
743757
tool_save.set_tooltip_text("Save notebook");
744758
tool_save_as.set_tooltip_text("Save notebook as...");
@@ -750,6 +764,7 @@ void NotebookWindow::on_realize()
750764
toolbar.pack_start(tool_run, Gtk::PACK_SHRINK);
751765
toolbar.pack_start(tool_stop, Gtk::PACK_SHRINK);
752766
toolbar.pack_start(tool_restart, Gtk::PACK_SHRINK);
767+
toolbar.pack_start(tool_restart_and_run_all, Gtk::PACK_SHRINK);
753768
toolbar.pack_start(top_label);
754769
toolbar.pack_end(kernel_spinner, Gtk::PACK_SHRINK);
755770
kernel_spinner.set_size_request(50/display_scale, 50/display_scale);
@@ -766,6 +781,7 @@ void NotebookWindow::on_realize()
766781
tool_run.signal_clicked().connect(sigc::mem_fun(*this, &NotebookWindow::run_all_cells));
767782
tool_stop.signal_clicked().connect(sigc::mem_fun(*this, &NotebookWindow::on_run_stop));
768783
tool_restart.signal_clicked().connect(sigc::mem_fun(*this, &NotebookWindow::on_kernel_restart));
784+
tool_restart_and_run_all.signal_clicked().connect(sigc::mem_fun(*this, &NotebookWindow::on_kernel_restart_and_run_all));
769785

770786
//
771787
// Gtk::Widget *toolbar=0;
@@ -1144,16 +1160,19 @@ void NotebookWindow::set_stop_sensitive(bool s)
11441160

11451161
void NotebookWindow::process_data()
11461162
{
1163+
// std::cerr << "process_data() called" << std::endl;
11471164
dispatcher.emit();
11481165
}
11491166

11501167

11511168
void NotebookWindow::on_connect()
11521169
{
1170+
// std::cerr << "kernel connected" << std::endl;
1171+
11531172
std::lock_guard<std::mutex> guard(status_mutex);
11541173
kernel_string = "connected";
11551174
progress_string = "Idle";
1156-
dispatcher.emit();
1175+
// dispatcher.emit();
11571176
dispatch_update_status.emit();
11581177
console.initialize();
11591178
// prefs.python_path might end in a backslash which will raise an EOF syntax error, so we add a
@@ -1163,10 +1182,17 @@ void NotebookWindow::on_connect()
11631182
if (!name.empty()) {
11641183
console.send_input("sys.path.insert(0, '''" + escape_backslashes(name.substr(0, name.find_last_of("\\/"))) + "''')");
11651184
}
1185+
1186+
if(run_all_after_restart) {
1187+
run_all_after_restart=false;
1188+
std::shared_ptr<ActionBase> action = std::make_shared<ActionRunCell>();
1189+
queue_action(action);
1190+
}
11661191
}
11671192

11681193
void NotebookWindow::on_disconnect(const std::string& reason)
11691194
{
1195+
// std::cerr << "***** kernel disconnected" << std::endl;
11701196
std::lock_guard<std::mutex> guard(status_mutex);
11711197
kernel_string = reason;
11721198
dispatcher.emit();
@@ -1191,6 +1217,7 @@ void NotebookWindow::on_kernel_runstatus(bool running)
11911217
follow_last_cell=doc.end();
11921218
}
11931219
}
1220+
// FIXME: WHY would we need to process the queue here?
11941221
dispatcher.emit();
11951222
}
11961223

@@ -1251,6 +1278,8 @@ void NotebookWindow::process_todo_queue()
12511278
{
12521279
static bool running=false;
12531280

1281+
// std::cerr << "process_todo_queue, running=" << running << std::endl;
1282+
12541283
// Prevent from re-entering this from the process_action_queue entered below.
12551284
if(running) return;
12561285
running=true;
@@ -1631,6 +1660,7 @@ void NotebookWindow::set_progress(const std::string& msg, int cur_step, int tota
16311660
void NotebookWindow::update_status()
16321661
{
16331662
// This should only be called from dispatch_update_status!
1663+
// This will then run on the GUI thread, as it should.
16341664

16351665
// Update status and progress, kernel status is taken card of in process_action_queue
16361666
std::lock_guard<std::mutex> guard(status_mutex);
@@ -2831,6 +2861,8 @@ void NotebookWindow::on_run_stop()
28312861
void NotebookWindow::on_kernel_restart()
28322862
{
28332863
// FIXME: add warnings
2864+
kernel_string = "restarting";
2865+
update_status();
28342866
follow_last_cell=doc.end();
28352867

28362868
compute->restart_kernel();
@@ -2844,6 +2876,13 @@ void NotebookWindow::on_kernel_restart()
28442876
dispatch_update_status.emit();
28452877
}
28462878

2879+
void NotebookWindow::on_kernel_restart_and_run_all()
2880+
{
2881+
// Run all cells after the restart has completed.
2882+
run_all_after_restart=true;
2883+
on_kernel_restart();
2884+
}
2885+
28472886
void NotebookWindow::on_help() const
28482887
{
28492888
if(current_cell==doc.end()) return;

frontend/gtkmm/NotebookWindow.hh

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,13 @@ namespace cadabra {
5656

5757
void select_range(const DTree&, DTree::iterator, int start, int len);
5858

59+
// Implementations of the functions which the compute thread will
60+
// call directly. If these need to modify the GUI, they need to do
61+
// so by calling one of the dispatchers.
5962
virtual void on_connect() override;
6063
virtual void on_disconnect(const std::string&) override;
6164
virtual void on_network_error() override;
6265
virtual void on_kernel_runstatus(bool) override;
63-
6466
virtual void process_data() override;
6567

6668
// TeX stuff
@@ -146,7 +148,7 @@ namespace cadabra {
146148
Gtk::Box topbox;
147149
Gtk::Box toolbar;
148150
Gtk::Button tool_open, tool_save, tool_save_as;
149-
Gtk::Button tool_run, tool_run_to, tool_stop, tool_restart;
151+
Gtk::Button tool_run, tool_run_to, tool_stop, tool_restart, tool_restart_and_run_all;
150152
Gtk::Box supermainbox;
151153
Gtk::Paned dragbox;
152154
Gtk::Box mainbox;
@@ -184,7 +186,16 @@ namespace cadabra {
184186
std::string status_string, kernel_string, progress_string;
185187
double progress_frac;
186188
int status_line, status_col;
189+
190+
// Functions which get called on the compute thread can signal to
191+
// the GUI thread that elements need to be updated, by sending
192+
// signals using the following dispatchers.
187193
Glib::Dispatcher dispatch_update_status, dispatch_refresh, dispatch_tex_error;
194+
195+
// Update the status line and progress bar. This should only
196+
// be called on the GUI thread, so typically gets called
197+
// indirectly by calling `dispatch_update_status.emmit()`
198+
// from the compute thread, which calls this function.
188199
void update_status();
189200

190201
// Run the TeX engine on a separate thread, then call
@@ -248,6 +259,7 @@ namespace cadabra {
248259
void on_help() const;
249260

250261
void on_kernel_restart();
262+
void on_kernel_restart_and_run_all();
251263

252264
/// Search handling.
253265
void on_search_text_changed();
@@ -263,6 +275,8 @@ namespace cadabra {
263275
/// Todo deque processing logic. This gets called by the dispatcher, but it
264276
/// is also allowed to call this from within NotebookWindow itself. The important
265277
/// thing is that it is run on the GUI thread.
278+
/// This is a wrapper around `Document::process_action_queue`, to set the
279+
/// spinner status and handle crashes.
266280
void process_todo_queue();
267281

268282
/// Refresh the display after a TeX engine run has completed. The TeX
@@ -321,7 +335,8 @@ namespace cadabra {
321335
std::pair<DTree::iterator, size_t> last_find_location;
322336
std::string last_find_string;
323337

324-
bool is_configured;
338+
bool is_configured; // have received and handled a configure event
339+
bool run_all_after_restart; // queue notebook running when kernel comes back
325340

326341
// We keep references to a few menu actions so we can
327342
// enable/disable them at runtime.

0 commit comments

Comments
 (0)