tesseract  4.1.3
svutil.cpp
Go to the documentation of this file.
1 // File: svutil.cpp
3 // Description: ScrollView Utilities
4 // Author: Joern Wanke
5 //
6 // (C) Copyright 2007, Google Inc.
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 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
18 //
19 // SVUtil contains the SVSync and SVNetwork classes, which are used for
20 // thread/process creation & synchronization and network connection.
21 
22 // Include automatically generated configuration file if running autoconf.
23 #ifdef HAVE_CONFIG_H
24 # include "config_auto.h"
25 #endif
26 
27 #include "svutil.h"
28 #include <cstdio>
29 #include <cstdlib>
30 #include <cstring>
31 #include <iostream>
32 #include <memory>
33 #include <string>
34 #include <thread> // for std::this_thread
35 #include <vector>
36 
37 #ifdef _WIN32
38 #pragma comment(lib, "Ws2_32.lib")
39 # include <winsock2.h> // for fd_set, send, ..
40 # include <ws2tcpip.h> // for addrinfo
41 #else
42 #include <arpa/inet.h>
43 #include <netdb.h>
44 #include <netinet/in.h>
45 #include <pthread.h>
46 #include <semaphore.h>
47 #include <csignal>
48 #include <sys/select.h>
49 #include <sys/socket.h>
50 #ifdef __linux__
51 #include <sys/prctl.h>
52 #endif
53 #include <unistd.h>
54 #endif
55 
57 #ifdef _WIN32
58  mutex_ = CreateMutex(0, FALSE, 0);
59 #else
60  pthread_mutex_init(&mutex_, nullptr);
61 #endif
62 }
63 
65 #ifdef _WIN32
66  CloseHandle(mutex_);
67 #else
68  pthread_mutex_destroy(&mutex_);
69 #endif
70 }
71 
72 void SVMutex::Lock() {
73 #ifdef _WIN32
74  WaitForSingleObject(mutex_, INFINITE);
75 #else
76  pthread_mutex_lock(&mutex_);
77 #endif
78 }
79 
81 #ifdef _WIN32
82  ReleaseMutex(mutex_);
83 #else
84  pthread_mutex_unlock(&mutex_);
85 #endif
86 }
87 
88 // Create new thread.
89 void SVSync::StartThread(void* (*func)(void*), void* arg) {
90 #ifdef _WIN32
91  LPTHREAD_START_ROUTINE f = (LPTHREAD_START_ROUTINE)func;
92  DWORD threadid;
93  CreateThread(nullptr, // default security attributes
94  0, // use default stack size
95  f, // thread function
96  arg, // argument to thread function
97  0, // use default creation flags
98  &threadid); // returns the thread identifier
99 #else
100  pthread_t helper;
101  pthread_attr_t attr;
102  pthread_attr_init(&attr);
103  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
104  pthread_create(&helper, &attr, func, arg);
105 #endif
106 }
107 
108 #ifndef GRAPHICS_DISABLED
109 
110 const int kMaxMsgSize = 4096;
111 
112 // Signals a thread to exit.
114 #ifdef _WIN32
115  // ExitThread(0);
116 #else
117  pthread_exit(nullptr);
118 #endif
119 }
120 
121 // Starts a new process.
122 void SVSync::StartProcess(const char* executable, const char* args) {
123  std::string proc;
124  proc.append(executable);
125  proc.append(" ");
126  proc.append(args);
127  std::cout << "Starting " << proc << std::endl;
128 #ifdef _WIN32
129  STARTUPINFO start_info;
130  PROCESS_INFORMATION proc_info;
131  GetStartupInfo(&start_info);
132  if (!CreateProcess(nullptr, const_cast<char*>(proc.c_str()), nullptr, nullptr, FALSE,
133  CREATE_NO_WINDOW | DETACHED_PROCESS, nullptr, nullptr,
134  &start_info, &proc_info))
135  return;
136 #else
137  int pid = fork();
138  if (pid != 0) { // The father process returns
139  } else {
140 #ifdef __linux__
141  // Make sure the java process terminates on exit, since its
142  // broken socket detection seems to be useless.
143  prctl(PR_SET_PDEATHSIG, 2, 0, 0, 0);
144 #endif
145  char* mutable_args = strdup(args);
146  int argc = 1;
147  for (int i = 0; mutable_args[i]; ++i) {
148  if (mutable_args[i] == ' ') {
149  ++argc;
150  }
151  }
152  std::unique_ptr<char*[]> argv(new char*[argc + 2]);
153  argv[0] = strdup(executable);
154  argv[1] = mutable_args;
155  argc = 2;
156  bool inquote = false;
157  for (int i = 0; mutable_args[i]; ++i) {
158  if (!inquote && mutable_args[i] == ' ') {
159  mutable_args[i] = '\0';
160  argv[argc++] = mutable_args + i + 1;
161  } else if (mutable_args[i] == '"') {
162  inquote = !inquote;
163  mutable_args[i] = ' ';
164  }
165  }
166  argv[argc] = nullptr;
167  execvp(executable, argv.get());
168  free(argv[0]);
169  free(argv[1]);
170  }
171 #endif
172 }
173 
175 #ifdef _WIN32
176  semaphore_ = CreateSemaphore(0, 0, 10, 0);
177 #elif defined(__APPLE__)
178  char name[50];
179  snprintf(name, sizeof(name), "%ld", random());
180  sem_unlink(name);
181  semaphore_ = sem_open(name, O_CREAT , S_IWUSR, 0);
182  if (semaphore_ == SEM_FAILED) {
183  perror("sem_open");
184  }
185 #else
186  sem_init(&semaphore_, 0, 0);
187 #endif
188 }
189 
191 #ifdef _WIN32
192  CloseHandle(semaphore_);
193 #elif defined(__APPLE__)
194  sem_close(semaphore_);
195 #else
196  sem_close(&semaphore_);
197 #endif
198 }
199 
201 #ifdef _WIN32
202  ReleaseSemaphore(semaphore_, 1, nullptr);
203 #elif defined(__APPLE__)
204  sem_post(semaphore_);
205 #else
206  sem_post(&semaphore_);
207 #endif
208 }
209 
211 #ifdef _WIN32
212  WaitForSingleObject(semaphore_, INFINITE);
213 #elif defined(__APPLE__)
214  sem_wait(semaphore_);
215 #else
216  sem_wait(&semaphore_);
217 #endif
218 }
219 
220 // Place a message in the message buffer (and flush it).
221 void SVNetwork::Send(const char* msg) {
222  mutex_send_.Lock();
223  msg_buffer_out_.append(msg);
224  mutex_send_.Unlock();
225 }
226 
227 // Send the whole buffer.
229  mutex_send_.Lock();
230  while (!msg_buffer_out_.empty()) {
231  int i = send(stream_, msg_buffer_out_.c_str(), msg_buffer_out_.length(), 0);
232  msg_buffer_out_.erase(0, i);
233  }
234  mutex_send_.Unlock();
235 }
236 
237 // Receive a message from the server.
238 // This will always return one line of char* (denoted by \n).
240  char* result = nullptr;
241 #if defined(_WIN32) || defined(__CYGWIN__)
242  if (has_content) { result = strtok (nullptr, "\n"); }
243 #else
244  if (buffer_ptr_ != nullptr) { result = strtok_r(nullptr, "\n", &buffer_ptr_); }
245 #endif
246 
247  // This means there is something left in the buffer and we return it.
248  if (result != nullptr) { return result;
249  // Otherwise, we read from the stream_.
250  } else {
251  buffer_ptr_ = nullptr;
252  has_content = false;
253 
254  // The timeout length is not really important since we are looping anyway
255  // until a new message is delivered.
256  struct timeval tv;
257  tv.tv_sec = 10;
258  tv.tv_usec = 0;
259 
260  // Set the flags to return when the stream_ is ready to be read.
261  fd_set readfds;
262  FD_ZERO(&readfds);
263  FD_SET(stream_, &readfds);
264 
265  int i = select(stream_+1, &readfds, nullptr, nullptr, &tv);
266 
267  // The stream_ died.
268  if (i == 0) { return nullptr; }
269 
270  // Read the message buffer.
271  i = recv(stream_, msg_buffer_in_, kMaxMsgSize, 0);
272 
273  // Server quit (0) or error (-1).
274  if (i <= 0) { return nullptr; }
275  msg_buffer_in_[i] = '\0';
276  has_content = true;
277 #ifdef _WIN32
278  return strtok(msg_buffer_in_, "\n");
279 #else
280  // Setup a new string tokenizer.
281  return strtok_r(msg_buffer_in_, "\n", &buffer_ptr_);
282 #endif
283  }
284 }
285 
286 // Close the connection to the server.
288 #ifdef _WIN32
289  closesocket(stream_);
290 #else
291  close(stream_);
292 #endif
293  // Mark stream_ as invalid.
294  stream_ = -1;
295 }
296 
297 
298 // The program to invoke to start ScrollView
299 static const char* ScrollViewProg() {
300 #ifdef _WIN32
301  const char* prog = "java -Xms512m -Xmx1024m";
302 #else
303  const char* prog = "sh";
304 #endif
305  return prog;
306 }
307 
308 
309 // The arguments to the program to invoke to start ScrollView
310 static std::string ScrollViewCommand(std::string scrollview_path) {
311  // The following ugly ifdef is to enable the output of the java runtime
312  // to be sent down a black hole on non-windows to ignore all the
313  // exceptions in piccolo. Ideally piccolo would be debugged to make
314  // this unnecessary.
315  // Also the path has to be separated by ; on windows and : otherwise.
316 #ifdef _WIN32
317  const char cmd_template[] = "-Djava.library.path=%s -jar %s/ScrollView.jar";
318 
319 #else
320  const char cmd_template[] =
321  "-c \"trap 'kill %%1' 0 1 2 ; java "
322  "-Xms1024m -Xmx2048m -jar %s/ScrollView.jar"
323  " & wait\"";
324 #endif
325  size_t cmdlen = sizeof(cmd_template) + 2 * scrollview_path.size() + 1;
326  std::vector<char> cmd(cmdlen);
327  const char* sv_path = scrollview_path.c_str();
328 #ifdef _WIN32
329  snprintf(&cmd[0], cmdlen, cmd_template, sv_path, sv_path);
330 #else
331  snprintf(&cmd[0], cmdlen, cmd_template, sv_path);
332 #endif
333  std::string command(&cmd[0]);
334  return command;
335 }
336 
337 // Set up a connection to a ScrollView on hostname:port.
338 SVNetwork::SVNetwork(const char* hostname, int port) {
339  msg_buffer_in_ = new char[kMaxMsgSize + 1];
340  msg_buffer_in_[0] = '\0';
341 
342  has_content = false;
343  buffer_ptr_ = nullptr;
344 
345  struct addrinfo *addr_info = nullptr;
346  char port_str[40];
347  snprintf(port_str, 40, "%d", port);
348 #ifdef _WIN32
349  // Initialize Winsock
350  WSADATA wsaData;
351  int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
352  if (iResult != 0) {
353  std::cerr << "WSAStartup failed: " << iResult << std::endl;
354  }
355 #endif // _WIN32
356 
357  if (getaddrinfo(hostname, port_str, nullptr, &addr_info) != 0) {
358  std::cerr << "Error resolving name for ScrollView host "
359  << std::string(hostname) << ":" << port << std::endl;
360 #ifdef _WIN32
361  WSACleanup();
362 #endif // _WIN32
363  }
364 
365  stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
366  addr_info->ai_protocol);
367 
368  if (stream_ < 0) {
369  std::cerr << "Failed to open socket" << std::endl;
370  } else if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) < 0) {
371  // If server is not there, we will start a new server as local child process.
372  const char* scrollview_path = getenv("SCROLLVIEW_PATH");
373  if (scrollview_path == nullptr) {
374 #ifdef SCROLLVIEW_PATH
375 #define _STR(a) #a
376 #define _XSTR(a) _STR(a)
377  scrollview_path = _XSTR(SCROLLVIEW_PATH);
378 #undef _XSTR
379 #undef _STR
380 #else
381  scrollview_path = ".";
382 #endif
383  }
384  const char *prog = ScrollViewProg();
385  std::string command = ScrollViewCommand(scrollview_path);
386  SVSync::StartProcess(prog, command.c_str());
387 
388  // Wait for server to show up.
389  // Note: There is no exception handling in case the server never turns up.
390 
391  Close();
392  for (;;) {
393  stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
394  addr_info->ai_protocol);
395  if (stream_ >= 0) {
396  if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) == 0) {
397  break;
398  }
399 
400  Close();
401 
402  std::cout << "ScrollView: Waiting for server...\n";
403  std::this_thread::sleep_for(std::chrono::seconds(1));
404  }
405  }
406  }
407 #ifdef _WIN32
408  // WSACleanup(); // This cause ScrollView windows is not displayed
409 #endif // _WIN32
410  freeaddrinfo(addr_info);
411 }
412 
414  Close();
415  delete[] msg_buffer_in_;
416 }
417 
418 #endif // GRAPHICS_DISABLED
void Lock()
Locks on a mutex.
Definition: svutil.cpp:72
void Unlock()
Unlocks on a mutex.
Definition: svutil.cpp:80
#define FALSE
Definition: capi.h:52
~SVMutex()
Destroys the mutex.
Definition: svutil.cpp:64
void Signal()
Signal a semaphore.
Definition: svutil.cpp:200
void Flush()
Flush the buffer.
Definition: svutil.cpp:228
char * Receive()
Definition: svutil.cpp:239
static void StartThread(void *(*func)(void *), void *arg)
Create new thread.
Definition: svutil.cpp:89
const int kMaxMsgSize
Definition: svutil.cpp:110
SVSemaphore()
Sets up a semaphore.
Definition: svutil.cpp:174
static void StartProcess(const char *executable, const char *args)
Starts a new process.
Definition: svutil.cpp:122
void Wait()
Wait on a semaphore.
Definition: svutil.cpp:210
SVMutex()
Sets up a new mutex.
Definition: svutil.cpp:56
static void ExitThread()
Signals a thread to exit.
Definition: svutil.cpp:113
void Close()
Close the connection to the server.
Definition: svutil.cpp:287
~SVSemaphore()
Cleans up the mutex.
Definition: svutil.cpp:190
~SVNetwork()
Destructor.
Definition: svutil.cpp:413
SVNetwork(const char *hostname, int port)
Set up a connection to hostname on port.
Definition: svutil.cpp:338
void Send(const char *msg)
Put a message in the messagebuffer to the server and try to send it.
Definition: svutil.cpp:221