]> git.vomp.tv Git - vompclient.git/blob - main.cc
OSDOpenVG: Render on demand: Fix backing out of a view render race
[vompclient.git] / main.cc
1 /*
2     Copyright 2004-2020 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <signal.h>
24
25 // For open
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29
30 #include <thread>
31 #include <string>
32
33
34 #ifndef WIN32
35   #include <unistd.h>
36   #include <endian.h>
37 #endif
38
39 #include "defines.h"
40
41 #ifdef HANDLE_VT_SWITCHING
42   #include <sys/ioctl.h>
43   #include <linux/vt.h>
44 #endif
45
46 #include "log.h"
47 #include "util.h"
48 #include "control.h"
49
50 #ifdef VOMP_PLATTFORM_NMT
51   #include "lednmt.h"
52   #include "osddirectfb.h"
53   #include "audionmt.h"
54   #include "videonmt.h"
55 #endif
56
57
58 #ifndef WIN32 // FIXME do we need any if WIN32 stuff in here? windows has own winmain file
59 void threadSignalReceiverFunction();
60 #endif
61
62 void shutdown(int code);
63 const std::string& getCommandLineServer();
64
65 Log* logger;
66 Control* control;
67
68 // Temporary, will move to Config system NCONFIG
69 std::string argvServer;
70
71 #ifdef HANDLE_VT_SWITCHING
72 int fdtty;
73 struct vt_mode old_vtmode;
74 #endif
75
76 // Linux main function and sighandler
77 #ifndef WIN32
78 int main(int argc, char** argv)
79 {
80   bool daemonize = true;
81   bool debugEnabled = false;
82   bool crashed = false;
83   int c;
84
85   while ((c = getopt(argc, argv, "cdns:")) != -1)
86   {
87     switch (c)
88     {
89       case 'c':
90         crashed = true;
91         break;
92       case 'd':
93         debugEnabled = true; // and...
94         [[fallthrough]];
95       case 'n':
96         daemonize = false;
97         break;
98       case 's':
99         argvServer = optarg;
100         break;
101       case '?':
102         printf("Unknown option\n");
103         return 1;
104       default:
105         printf("Option error\n");
106         return 1;
107     }
108   }
109
110   // Start Log --------------------------------------------------------------------------------------------------
111   logger = new Log();
112   if (!logger)
113   {
114     printf("Failed to create Log object\n");
115     shutdown(1);
116   }
117
118   if (!logger->init(Log::DEBUG, "dummy", debugEnabled ? 1 : 0)) // NCONFIG x2
119   {
120     printf("Could not initialise log object. Aborting.\n");
121     shutdown(1);
122   }
123
124   logger->log("Main", Log::INFO, "Starting up...");
125
126   // Daemonize --------------------------------------------------------------------------------------------------
127
128   if (daemonize)
129   {
130     // Fork away
131     pid_t forkTest = fork();
132     if (forkTest == -1)
133     { printf("Cannot fork (1).\n"); exit(1); }
134     if (forkTest != 0) _exit(0); // PID returned, I am the parent
135     // otherwise, I am the child
136     setsid();
137     forkTest = fork();
138     if (forkTest == -1)
139     { printf("Cannot fork (2).\n"); exit(1); }
140     if (forkTest != 0) _exit(0); // PID returned, I am the parent
141     // otherwise, I am the child
142     close(0);
143     close(1);
144     close(2);
145   }
146
147   // Set up signal handling ------------------------------------------------------------------------------------------
148
149   // Block all signals
150   sigset_t set;
151   sigfillset(&set);
152   int sigBlockResult = pthread_sigmask(SIG_SETMASK, &set, NULL);
153   if (sigBlockResult)
154   {
155     logger->log("Main", Log::EMERG, "Could not block signals: %i", sigBlockResult);
156     shutdown(1);
157   }
158
159   // Start signal receiver thread
160   std::thread threadSignalReceiver(threadSignalReceiverFunction);
161   threadSignalReceiver.detach();
162
163   logger->log("Main", Log::INFO, "Signal handlers set up successfully");
164
165   // VT Switching -----------------------------------------------------------------------------------------------
166
167 #ifdef HANDLE_VT_SWITCHING
168   if (
169
170
171     (fdtty = open("/dev/tty", O_WRONLY),0) == -1   // FIXME. Why the ,0 ? Surely this kills the log line below
172
173
174   )
175   {
176     logger->log("Main", Log::EMERG, "Could not open /dev/tty. Please change permissions");
177   }
178   else
179   {
180     int free_vt;
181     if (ioctl(fdtty, VT_OPENQRY, &free_vt) == -1 || free_vt == -1)
182     {
183       logger->log("Main", Log::EMERG, "Could not retrieve free virtual console, please change permissions");
184     }
185     else
186     {
187       ioctl(fdtty, VT_ACTIVATE, free_vt);
188       ioctl(fdtty, VT_WAITACTIVE, free_vt);
189       ioctl(fdtty, VT_LOCKSWITCH, 1);
190     }
191   }
192 #endif
193
194   // Run control ----------------------------------------------------------------------------------------------------
195
196   control = new Control();
197   if (!control)
198   {
199     logger->log("Main", Log::EMERG, "Control module failed to create");
200     shutdown(1);
201   }
202
203   if (!control->init(crashed))
204   {
205     logger->log("Main", Log::EMERG, "Control module failed to initialise");
206     delete control;
207     control = NULL;
208     shutdown(1);
209   }
210
211   control->run();
212   control->shutdown();
213
214   shutdown(0);
215   return 0;
216 }
217
218 // -------------------------------------------------------------------------------------------------------------------
219
220 void threadSignalReceiverFunction()
221 {
222   int sig;
223   sigset_t set;
224   sigfillset(&set);
225   while(1)
226   {
227     if(sigwait(&set, &sig))
228     {
229       logger->log("Main", Log::CRIT, "Sigwait returned fail - signal handler exiting");
230       return;
231     }
232
233     logger->log("Main", Log::NOTICE, "Signal received: %i", sig);
234
235     if ((sig == SIGINT) || (sig == SIGTERM)) control->stop();
236   }
237 }
238
239 #endif
240
241 // -------------------------------------------------------------------------------------------------------------------
242
243 void shutdown(int code)
244 {
245   // FIXME, send a del all to boxstack first, then get rid of it after control?
246   if (control) // shut down control here in case views have posted messages
247   {
248     delete control;
249     control = NULL;
250     logger->log("Main", Log::NOTICE, "Control module shut down");
251   }
252
253 #ifdef HANDLE_VT_SWITCHING
254   ioctl(fdtty, VT_UNLOCKSWITCH, 1);
255   close(fdtty);
256 #endif
257
258   if (logger)
259   {
260     logger->log("Main", Log::NOTICE, "Log module shutting down... bye!\n\n");
261     logger->shutdown();
262     delete logger;
263   }
264
265   exit(code);
266 }
267
268 // -------------------------------------------------------------------------------------------------------------------
269
270 long long getTimeMS()
271 {
272   struct timespec ts;
273   clock_gettime(VOMP_LINUX_CLOCK, &ts);
274   return ts.tv_sec * 1000 + ts.tv_nsec / 1000000LL;
275 }
276
277 int getClockRealTime(struct timespec *tp) // FIXME - del if all goes chrono
278 {
279   return clock_gettime(CLOCK_REALTIME, tp);
280 }
281
282 const std::string& getCommandLineServer()
283 {
284   return argvServer;
285 }