RDK Documentation (Open Sourced RDK Components)
main.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 #include <QCoreApplication>
20 #include <QDebug>
21 #include "crashingthread.h"
22 #include <sys/poll.h>
23 #include <sys/types.h>
24 #include <signal.h>
25 #include <unistd.h>
26 
27 #if defined(USE_GOOGLE_BREAKPAD)
28 #include "client/linux/handler/exception_handler.h"
29 #include "client/linux/crash_generation/crash_generation_server.h"
30 #include "common/linux/eintr_wrapper.h"
31 #include "common/linux/linux_libc_support.h"
32 #include "third_party/lss/linux_syscall_support.h"
33 
34 using namespace google_breakpad;
35 using google_breakpad::CrashGenerationServer;
36 
37 static int server_fd = -1, client_fd = -1;
38 #endif
39 
40 namespace
41 {
42 #if defined(USE_GOOGLE_BREAKPAD)
43 /*
44  bool breakpadCallback(const MinidumpDescriptor& descriptor,void* context, bool succeeded)
45  {
46  Q_UNUSED(descriptor);
47  Q_UNUSED(context);
48 
49  write(1, descriptor.path(), 50);
50  write(1, "\n", 2);
51 
52  kill(-server_pid, SIGTERM);
53  sleep(2);
54  kill(-server_pid, SIGKILL);
55  return succeeded;
56  }
57 */
58  void setupSignalHandlers()
59  {
60  new ExceptionHandler(MinidumpDescriptor("/opt/minidumps"),
61  NULL,
62  NULL, //MinidumpCallback is useless
63  NULL,
64  true,
65  client_fd);
66  }
67 
68  bool setup_pipe()
69  {
70  // Setup client/server sockets
71  if (!CrashGenerationServer::CreateReportChannel(&server_fd, &client_fd))
72  {
73  qDebug() << "Client: CreateReportChannel failed!\n";
74  return false;
75  }
76  return true;
77  }
78 
79 
80  bool start_server(const char* server_path_str)
81  {
82  qDebug() << "Client: entering startServer\n";
83 
84  // Launch handler
85  int fds[2];
86  if (pipe(fds) == -1)
87  {
88  qDebug() << "Client: pipe failed!\n";
89  return false;
90  }
91 
92  pid_t server_pid = fork();
93  if (server_pid == 0)
94  {
95  qDebug() << "Client: in child after fork\n";
96  // Pass the pipe fd and server fd as arguments.
97  char pipe_fd_string[8];
98  sprintf(pipe_fd_string, "%d", fds[1]);
99 
100  char server_fd_string[8];
101  sprintf(server_fd_string, "%d", server_fd);
102 
103  char* const argv[] = {strdup(server_path_str),
104  pipe_fd_string,
105  server_fd_string,
106  NULL
107  };
108 
109  execv(server_path_str, argv);
110  qDebug() << "Client: execv failed\n";
111  exit(1);
112  }
113 
114  // Wait for server to unblock us.
115  struct pollfd pfd;
116  memset(&pfd, 0, sizeof(pfd));
117  pfd.fd = fds[0];
118  pfd.events = POLLIN | POLLERR;
119 
120  int r = HANDLE_EINTR(poll(&pfd, 1, 5000));
121  if (r != 1 || (pfd.revents & POLLIN) != POLLIN)
122  {
123  qDebug() << "Client: poll failed?\n";
124  if (pfd.revents & POLLERR)
125  {
126  qDebug() << "Client: POLLERR\n";
127  }
128  if (pfd.revents & POLLHUP)
129  {
130  qDebug() << "Client: POLLHUP\n";
131  }
132  if (pfd.revents & POLLNVAL)
133  {
134  qDebug() << "Client: POLLNVAL\n";
135  }
136  return false;
137  }
138 
139  qDebug() << "Client: Poll result: " << r << "\n";
140  uint8_t junk;
141  read(fds[0], &junk, sizeof(junk));
142  close(fds[0]);
143 
144  qDebug() << "Client: exiting startServer\n";
145 
146  return true;
147  }
148 
149 #else
150  void signalHandler(int signum)
151  {
152  switch (signum)
153  {
154  #define ONCASE(x) case x: qDebug() << "Caught signal" << #x; break
155  ONCASE(SIGINT);
156  ONCASE(SIGQUIT);
157  ONCASE(SIGILL);
158  ONCASE(SIGABRT);
159  ONCASE(SIGFPE);
160  ONCASE(SIGSEGV);
161  ONCASE(SIGTERM);
162  #undef ONCASE
163  default: qDebug() << "Caught unknown signal %d" << signum; break;
164  }
165  QCoreApplication *coreApp = QCoreApplication::instance();
166  if( NULL != coreApp )
167  coreApp->exit( signum );
168  // restore default handler
169  signal(signum, SIG_DFL);
170  // send the signal to the default signal handler, to allow a debugger to trap it
171  kill(getpid(), signum);
172  }
173 
174  void setupSingalHandlers()
175  {
176  signal(SIGINT, signalHandler);
177  signal(SIGQUIT, signalHandler);
178  signal(SIGTERM, signalHandler);
179  signal(SIGILL, signalHandler);
180  signal(SIGABRT, signalHandler);
181  signal(SIGFPE, signalHandler);
182  signal(SIGSEGV, signalHandler);
183  }
184 #endif
185 }
186 
187 
188 int main(int argc, char *argv[])
189 {
190  QCoreApplication app(argc, argv);
191 
192  qDebug() << "Client: started\n";
193 
194 #if defined(USE_GOOGLE_BREAKPAD)
195  if (!setup_pipe())
196  {
197  qDebug() << "Client: Pipe setup failed!\n";
198  return 1;
199  }
200 
201  //TODO: change into env variable
202  //"-pc" - is a suffix for PC build
203  QString app_path = app.applicationDirPath()+"/server-pc";
204  if (!start_server(app_path.toLocal8Bit().data()))
205  {
206  qDebug() << "Client: Server did not start!\n";
207  return 1;
208  }
209 #endif
210 
211  setupSignalHandlers();
212 
213  //TODO: change into app input parameter
214  const int NUMBER_OF_THREADS = 50;
215 
216  QList<CrashingThread*> threads;
217  for (int i = 1; i <= NUMBER_OF_THREADS; ++i)
218  {
219  CrashingThread *thread = new CrashingThread(&app);
220  thread->setThreadNumber(i);
221  threads << thread;
222  }
223 
224  foreach (CrashingThread *thread, threads)
225  {
226  thread->start();
227  }
228 
229  foreach (CrashingThread *thread, threads)
230  {
231  thread->wait();
232  }
233 
234  return app.exec();
235 }
CrashingThread
Definition: crashingthread.h:24