1 /*
2     Copyright (c) 2005-2021 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 // Header guard and namespace names follow rml conventions.
18 
19 #ifndef __RML_rml_base_H
20 #define __RML_rml_base_H
21 
22 #include <cstddef>
23 
24 #if _WIN32||_WIN64
25 #include <windows.h>
26 #endif /* _WIN32||_WIN64 */
27 
28 #ifdef RML_PURE_VIRTUAL_HANDLER
29 #define RML_PURE(T) {RML_PURE_VIRTUAL_HANDLER(); return (T)0;}
30 #else
31 #define RML_PURE(T) = 0;
32 #endif
33 
34 namespace rml {
35 
36 class server;
37 
38 class versioned_object {
39 public:
40     //! A version number
41     typedef unsigned version_type;
42 
~versioned_object()43     virtual ~versioned_object() {}
44 
45     //! Get version of this object
46     /** The version number is incremented when a incompatible change is introduced.
47         The version number is invariant for the lifetime of the object. */
48     virtual version_type version() const RML_PURE(version_type)
49 
50 };
51 
52 //! Represents a client's job for an execution context.
53 /** A job object is constructed by the client.
54     Not derived from versioned_object because version is same as for client. */
55 class job {
56     friend class server;
57 };
58 
59 //! Information that client provides to server when asking for a server.
60 /** The instance must endure at least until acknowledge_close_connection is called. */
61 class client: public versioned_object {
62 public:
63     //! Typedef for convenience of derived classes in other namespaces.
64     typedef ::rml::job job;
65 
66     //! Index of a job in a job pool
67     typedef unsigned size_type;
68 
69     //! Maximum number of threads that client can exploit profitably if nothing else is running on the machine.
70     /** The returned value should remain invariant for the lifetime of the connection.  [idempotent] */
71     virtual size_type max_job_count() const RML_PURE(size_type)
72 
73     //! Minimum stack size for each job.  0 means to use default stack size. [idempotent]
74     virtual std::size_t min_stack_size() const RML_PURE(std::size_t)
75 
76     //! Server calls this routine when it needs client to create a job object.
77     virtual job* create_one_job() RML_PURE(job*)
78 
79     //! Acknowledge that all jobs have been cleaned up.
80     /** Called by server in response to request_close_connection
81         after cleanup(job) has been called for each job. */
82     virtual void acknowledge_close_connection() RML_PURE(void)
83 
84     //! Inform client that server is done with *this.
85     /** Client should destroy the job.
86         Not necessarily called by execution context represented by *this.
87         Never called while any other thread is working on the job. */
88     virtual void cleanup( job& ) RML_PURE(void)
89 
90     // In general, we should not add new virtual methods, because that would
91     // break derived classes.  Think about reserving some vtable slots.
92 };
93 
94 // Information that server provides to client.
95 // Virtual functions are routines provided by the server for the client to call.
96 class server: public versioned_object {
97 public:
98     //! Typedef for convenience of derived classes.
99     typedef ::rml::job job;
100 
101 #if _WIN32||_WIN64
102     typedef void* execution_resource_t;
103 #endif
104 
105     //! Request that connection to server be closed.
106     /** Causes each job associated with the client to have its cleanup method called,
107         possibly by a thread different than the thread that created the job.
108         This method can return before all cleanup methods return.
109         Actions that have to wait after all cleanup methods return should be part of
110         client::acknowledge_close_connection.
111         Pass true as exiting if request_close_connection() is called because exit() is
112         called. In that case, it is the client's responsibility to make sure all threads
113         are terminated. In all other cases, pass false.  */
114     virtual void request_close_connection( bool exiting = false ) = 0;
115 
116     //! Called by client thread when it reaches a point where it cannot make progress until other threads do.
117     virtual void yield() = 0;
118 
119     //! Called by client to indicate a change in the number of non-RML threads that are running.
120     /** This is a performance hint to the RML to adjust how many threads it should let run
121         concurrently.  The delta is the change in the number of non-RML threads that are running.
122         For example, a value of 1 means the client has started running another thread, and a value
123         of -1 indicates that the client has blocked or terminated one of its threads. */
124     virtual void independent_thread_number_changed( int delta ) = 0;
125 
126     //! Default level of concurrency for which RML strives when there are no non-RML threads running.
127     /** Normally, the value is the hardware concurrency minus one.
128         The "minus one" accounts for the thread created by main(). */
129     virtual unsigned default_concurrency() const = 0;
130 };
131 
132 class factory {
133 public:
134     //! status results
135     enum status_type {
136         st_success=0,
137         st_connection_exists,
138         st_not_found,
139         st_incompatible
140     };
141 
142 protected:
143     //! Pointer to routine that waits for server to indicate when client can close itself.
144     status_type (*my_wait_to_close_routine)( factory& );
145 
146 public:
147     //! Library handle for use by RML.
148 #if _WIN32||_WIN64
149     HMODULE library_handle;
150 #else
151     void* library_handle;
152 #endif /* _WIN32||_WIN64 */
153 
154     //! Special marker to keep dll from being unloaded prematurely
155     static const std::size_t c_dont_unload = 1;
156 };
157 
158 //! Typedef for callback functions to print server info
159 typedef void (*server_info_callback_t)( void* arg, const char* server_info );
160 
161 } // namespace rml
162 
163 #endif /* __RML_rml_base_H */
164