File: ComputeThread.hh

package info (click to toggle)
cadabra2 2.4.3.2-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 78,732 kB
  • sloc: ansic: 133,450; cpp: 92,064; python: 1,530; javascript: 203; sh: 184; xml: 182; objc: 53; makefile: 51
file content (147 lines) | stat: -rw-r--r-- 5,199 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

#pragma once

#include <signal.h>
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/client.hpp>
#include <websocketpp/common/thread.hpp>
#include <websocketpp/common/functional.hpp>
#include <thread>
#include <set>
#include <glibmm/spawn.h>

typedef websocketpp::client<websocketpp::config::asio_client> WSClient;
typedef websocketpp::config::asio_client::message_type::ptr message_ptr;
typedef websocketpp::lib::lock_guard<websocketpp::lib::mutex> scoped_lock;

#include "DataCell.hh"

namespace cadabra {

	class GUIBase;
	class DocumentThread;

	/// \ingroup clientserver
	///
	/// Base class which talks to the server and sends Action objects back to the
	/// DocumentThread.
	///
	/// ComputeThread is the base class which takes care of doing actual
	/// computations with the cells in a document. It handles talking to
	/// the server backend. It knows how to pass cells to the server and
	/// ask them to be executed. Results are reported back to the GUI by
	/// putting ActionBase objects onto its todo stack. ComputeThread never
	/// directly modifies the document tree.

	class ComputeThread {
		public:
			/// If the ComputeThread is constructed with a null pointer to the
			/// gui, there will be no gui updates, just DTree updates.

			ComputeThread(int server_port=0, std::string token="", std::string ip_address="127.0.0.1");
			ComputeThread(const ComputeThread& )=delete; // You cannot copy this object
			~ComputeThread();

			/// Determine the objects that this compute thread should be
			/// talking to.
			void set_master(GUIBase *, DocumentThread *);

			/// Main entry point, which will connect to the server and
			/// then start an event loop to handle communication with the
			/// server. Only terminates when the connection drops, so run
			/// your GUI on a different thread.

			void run();

			/// In order to execute code on the server, call the
			/// following from the GUI thread.  This method returns as
			/// soon as the request has been put on the network queue. If
			/// no communication with the server is necessary, this
			/// returns immediately. The ComputeThread will report the
			/// result of the computation/processing by adding actions to
			/// the DocumentThread owned pending_actions stack, by
			/// calling queue_action. It will never modify the cell
			/// directly, and will also never modify any other cells in
			/// the document tree.

			void execute_cell(DTree::iterator);

			void execute_interactive(uint64_t id, const std::string& code);

			/// Stop the current cell execution on the server and remove
			/// all other cells from the run queue as well.

			void stop();

			/// Restart the kernel.

			void restart_kernel();

			/// Request completion of a string. Returns `false` if the current
			/// cell cannot be completed, in which case the TAB which led to
			/// the request should be interpreted literally and used for spacing.
			/// The `alternative` argument is the serial number of the requested
			/// completion, in case there is more than one possible completion.

			bool complete(DTree::iterator, int pos, int alternative);

			// Determine if there are still cells running on the server.
			// FIXME: this does not guarantee thread-safety but at the moment
			// is only used for updating status bars etc.
			// FIXME: can be moved to DocumentThread.

			int number_of_cells_executing(void) const;

			/// Terminate the compute thread, in preparation for shutting
			/// down the client altogether.

			void terminate();

		private:
			GUIBase        *gui;
			DocumentThread *docthread;

			// For debugging purposes, we keep record of the gui thread id,
			// so that we can flag when code runs on the wrong thread.
			// Gets initialised in the ComputeThread constructor.
			std::thread::id  gui_thread_id;

			// Keeping track of cells which are running on the server, in
			// a form which allows us to look them up quickly based only
			// on the id (which is all that the server knows about).

			// FIXME: moving this away into documentthread, so that we only need to refer to id's.
			std::map<DataCell::id_t, DTree::iterator> running_cells;

			// WebSocket++ things.
			WSClient wsclient;
			bool     connection_is_open, restarting_kernel;
			WSClient::connection_ptr    connection;
			websocketpp::connection_hdl our_connection_hdl;
			void init();
			void try_connect();
			void try_spawn_server();
			void on_open(websocketpp::connection_hdl hdl);
			void on_fail(websocketpp::connection_hdl hdl);
			void on_close(websocketpp::connection_hdl hdl);
			void on_message(websocketpp::connection_hdl hdl, message_ptr msg);

			void cell_finished_running(DataCell::id_t);

			/// Set all cells to be non-running (e.g. after a kernel failure) and
			/// report the status of each cell to the GUI.
			void all_cells_nonrunning();

			std::set<uint64_t> interactive_cells;

			// Self-started server
			Glib::Pid       server_pid;
			int             server_stdout, server_stderr;
			unsigned short  port;
			std::string     authentication_token;
			int             forced_server_port;
			std::string     forced_server_token;
			std::string     forced_server_ip_address;
		};

	}