1 /*
2  * Copyright 2014-2018, Björn Ståhl
3  * License: 3-Clause BSD, see COPYING file in arcan source repository.
4  * Reference: http://arcan-fe.com
5  */
6 
7 /*
8  * This file should define the generic types (and possibly header files) needed
9  * for building / porting to a different platform. A working combination of all
10  * platform/.h defined headers are needed for system integration.
11  */
12 #ifndef HAVE_PLATFORM_HEADER
13 #define HAVE_PLATFORM_HEADER
14 
15 #include "platform_types.h"
16 #include "agp_platform.h"
17 #include "video_platform.h"
18 #include "fsrv_platform.h"
19 #include "os_platform.h"
20 #include "event_platform.h"
21 
22 /*
23  * Retrieve the current time (in milliseconds or microseconds) based on some
24  * unknown system defined epoch. Invoked frequently.
25  */
26 unsigned long long arcan_timemillis();
27 unsigned long long arcan_timemicros();
28 
29 /*
30  * Both these functions expect [argv / envv] to be modifiable and their
31  * internal contents dynamically allocated (hence will possible replace / free
32  * existing ones due to platform specific expansion rules
33  */
34 
35 /*
36  * Updated in the conductor stage with the latest known timestamp, Checked in
37  * the platform/posix/psep_open and is used to either send SIGINT (first) then
38  * if another timeout arrives, SIGKILL.
39  *
40  * The SIGINT is used in arcan_lua.c and used to trigger wraperr, which in turn
41  * will log the event and rebuild the VM.
42  *
43  * This serves to protect against livelocks in general, but in particular for
44  * the worst sinners, lua scripts getting stuck in while- loops from bad
45  * programming, and complex interactions in the egl-dri platform.
46  */
47 extern _Atomic uint64_t* volatile arcan_watchdog_ping;
48 #define WATCHDOG_ANR_TIMEOUT_MS 5000
49 
50 /*
51  * default, probed / replaced on some systems
52  */
53 extern int system_page_size;
54 
55 /*
56  * Execute and wait- for completion for the specified target.  This will shut
57  * down as much engine- locked resources as possible while still possible to
58  * revert to the state- pre exection.
59  *
60  * It returns the time spent waiting (in milliseconds) and the
61  * return-code/exit-status in exitc.
62  */
63 struct arcan_strarr;
64 struct arcan_evctx;
65 
66 unsigned long arcan_target_launch_external(
67 	const char* fname,
68 	struct arcan_strarr* argv,
69 	struct arcan_strarr* env,
70 	struct arcan_strarr* libs,
71 	int* exitc
72 );
73 
74 /*
75  * Launch the specified program and bind its resources and control to the
76  * returned frameserver instance (NULL if spawn was not possible for some
77  * reason, e.g. missing binaries).
78  */
79 struct arcan_frameserver;
80 struct arcan_frameserver* arcan_target_launch_internal(
81 	const char* fname,
82 	struct arcan_strarr* argv,
83 	struct arcan_strarr* env,
84 	struct arcan_strarr* libs
85 );
86 
87 /*
88  * Used by event and video platforms to query for configuration keys according
89  * to some implementation defined mechanism.
90  *
91  * Returns true if the key was found. If the key carried some associated value,
92  * *val (if provided) will be set to a dynamically allocated string that the
93  * caller assumes responsibility for, otherwise NULL.
94  *
95  * For keys that have multiple set values, [ind] can be walked and is assumed
96  * to be densly packed (first failed index means that there are no more values)
97  *
98  * [tag] must match the value provided by platform_config_lookup.
99  */
100 typedef bool (*cfg_lookup_fun)(
101 	const char* const key, unsigned short ind, char** val, uintptr_t tag);
102 
103 /*
104  * Retrieve a pointer to a function that can be used to query for key=val string
105  * packed arguments according with shmif_arg- style packing, along with a token
106  * that the caller is expected to provide when doing lookups. If no [tag] store
107  * is provided, the returned function will be NULL.
108  */
109 cfg_lookup_fun platform_config_lookup(uintptr_t* tag);
110 
111 /*
112  * return a string (can be empty) matching the existing and allowed frameserver
113  * archetypes (a filtered version of the FRAMSESERVER_MODESTRING buildtime var.
114  * and which ones that resolve to valid and existing executables)
115  */
116 const char* arcan_frameserver_atypes();
117 
118 /* estimated time-waster in milisecond resolution, little reason for this
119  * to be exact, but undershooting rather than overshooting is important */
120 void arcan_timesleep(unsigned long);
121 
122 /* [BLOCKING, THREAD_SAFE]
123  * Generate [sz] cryptographically secure pseudo-random bytes and store
124  * into [dst].
125  */
126 void arcan_random(uint8_t* dst, size_t sz);
127 
128 /*
129  * A lot of frameserver/client communication is on the notion that we can
130  * push and fetch some kind of context handle between processes. The exact
131  * means and mechanics vary with operating system, but typically through a
132  * special socket or as a member of the event queue.
133  */
134 file_handle arcan_fetchhandle(int insock, bool block);
135 bool arcan_pushhandle(int fd, int channel);
136 
137 /*
138  * This is a nasty little function, but used as a safe-guard in the fork()+
139  * exec() case ONLY. There should be no risk of syslog or other things
140  * corrupting future descriptors. On linux etc. this is implemented as an empty
141  * poll on a rlimit- full set and using that to close()
142  */
143 void arcan_closefrom(int num);
144 
145 /*
146  * Update the process title to better identify the current process
147  */
148 void arcan_process_title(const char* new_title);
149 
150 /*
151  * Don't have much need for more fine-grained data model in regards to the
152  * filesystem other than 'is it possible that this, at the moment, refers
153  * to a file (loadable resource) or a container of files? Trace calls to this
154  * function for verifying against TOCTU vulns.
155  * Depending on how the windows platform develops, we should consider moving
156  * this in hardening phase to return descriptor to dir/file instead
157  */
158 bool arcan_isfile(const char*);
159 bool arcan_isdir(const char*);
160 
161 /*
162  * implemented in <platform>/warning.c regular fprintf(stderr, style trace
163  * output logging.  slated for REDESIGN/REFACTOR.
164  */
165 void arcan_warning(const char* msg, ...);
166 void arcan_fatal(const char* msg, ...);
167 
168 /* replace the thread_local logging output destination with outf.
169  * This can be null (and by default is null) in order to disable log output */
170 void arcan_log_destination(FILE* outf, int minlevel);
171 
172 /*
173  * returns a [caller-managed COPY] of a OS- specific safe (read/writeable) path
174  * to the database to use unless one has been provided at the command-line.
175  */
176 char* platform_dbstore_path();
177 
178 /*
179  * On some platforms, this is simply a wrapper around open() - and for others
180  * there might be an intermediate process that act as a device proxy.
181  */
182 int platform_device_open(const char* identifier, int flags);
183 
184 /*
185  * special devices, typically gpu nodes and ttys, need and explicit privilege
186  * side release- action as well. The idhint is special for TTY-swap
187  */
188 void platform_device_release(const char* identifier, int idhint);
189 
190 /*
191  * detects if any new devices have appeared, and stores a copy into identifier
192  * (caller assumes ownership) that can then be used in conjunction with _open
193  * in order to get a handle to the device.
194  *
195  * -1 : discovery not possible, connection severed
196  *  0 : no new device events
197  *  1 : new input device provided in identifier
198  *  2 : display device event pending (monitor hotplug)
199  *  3 : suspend/release
200  *  4 : restore/rebuild
201  *  5 : terminate
202  */
203 int platform_device_poll(char** identifier);
204 
205 /*
206  * retrieve a handle that can be used to I/O multiplex device discovery
207  * instead of periodically calling _poll and checking the return state.
208  */
209 int platform_device_pollfd();
210 
211 /*
212  * run before any other platform function, make sure that we are in a state
213  * where we can negotiate access to device nodes for the event and video layers
214  */
215 void platform_device_init();
216 
217 /*
218  * Used by the conductor to determine the dominant clock to use for
219  * scheduling. The cost_us is an estimate of the overhead of a timesleep
220  * or other yield- like actions. In time.c
221  */
222 struct platform_timing platform_hardware_clockcfg();
223 
224 /*
225  * Support function for implementing threaded platform devices.
226  * This will return a non-blocking read-end of a pipe where arcan_events
227  * can be read from.
228  *
229  * [infd]      data source descriptor
230  * [block_sz]  desired fixed-size event chunk (if applicable, or 0)
231  * [callback]  bool (int out_fd, uint8_t* in_buf, size_t nb, void* tag)
232  * [tag]       caller provided data, passed to tag
233  *
234  * If callback returns [false], the thread will be closed and resources
235  * freed. If callback is provided a NULL [in_buf] it means the [infd] has
236  * failed and the thread will terminate.
237  */
238 int platform_producer_thread(int infd,
239 	size_t block_sz, bool(*callback)(int, uint8_t*, size_t, void*), void* tag);
240 #endif
241