~brianaker/libmemcached/1164440

« back to all changes in this revision

Viewing changes to libtest/cmdline.cc

  • Committer: Continuous Integration
  • Date: 2012-10-22 05:56:09 UTC
  • mfrom: (1086.1.8 libmemcached-1.0)
  • Revision ID: ci@tangent.org-20121022055609-cbooaw9bcdal4qge
Merge lp:~tangent-org/libmemcached/1.0-build Build: jenkins-Libmemcached-1.0-87

Show diffs side-by-side

added added

removed removed

Lines of Context:
59
59
static char **environ= NULL;
60
60
#endif
61
61
 
62
 
extern "C" {
63
 
  static int exited_successfully(int status)
64
 
  {
65
 
    if (status == 0)
66
 
    {
67
 
      return EXIT_SUCCESS;
68
 
    }
69
 
 
70
 
    if (WIFEXITED(status) == true)
71
 
    {
72
 
      return WEXITSTATUS(status);
73
 
    }
74
 
    else if (WIFSIGNALED(status) == true)
75
 
    {
76
 
      return WTERMSIG(status);
77
 
    }
78
 
 
79
 
    return EXIT_FAILURE;
80
 
  }
81
 
}
 
62
#ifndef FD_CLOEXEC
 
63
# define FD_CLOEXEC 0
 
64
#endif
82
65
 
83
66
namespace {
84
67
 
115
98
    switch (arg)
116
99
    {
117
100
    case 127:
118
 
      return Application::INVALID;
 
101
      return Application::INVALID_POSIX_SPAWN;
119
102
 
120
103
    case 0:
121
104
      return Application::SUCCESS;
122
105
 
123
 
    default:
124
106
    case 1:
125
107
      return Application::FAILURE;
 
108
 
 
109
    default:
 
110
      return Application::UNKNOWN;
126
111
    }
127
112
  }
128
113
}
140
125
  stdin_fd(STDIN_FILENO),
141
126
  stdout_fd(STDOUT_FILENO),
142
127
  stderr_fd(STDERR_FILENO),
143
 
  _pid(-1)
 
128
  _pid(-1),
 
129
  _status(0),
 
130
  _app_exit_state(UNINITIALIZED)
144
131
  { 
145
132
    if (_use_libtool)
146
133
    {
195
182
  posix_spawnattr_t spawnattr;
196
183
  posix_spawnattr_init(&spawnattr);
197
184
 
198
 
  sigset_t set;
199
 
  sigemptyset(&set);
200
 
  fatal_assert(posix_spawnattr_setsigmask(&spawnattr, &set) == 0);
 
185
  short flags= 0;
 
186
 
 
187
  // Child should not block signals
 
188
  flags |= POSIX_SPAWN_SETSIGMASK;
 
189
 
 
190
  sigset_t mask;
 
191
  sigemptyset(&mask);
 
192
 
 
193
  fatal_assert(posix_spawnattr_setsigmask(&spawnattr, &mask) == 0);
 
194
 
 
195
#if defined(POSIX_SPAWN_USEVFORK) || defined(__linux__)
 
196
  // Use USEVFORK on linux
 
197
  flags |= POSIX_SPAWN_USEVFORK;
 
198
#endif
 
199
 
 
200
  flags |= POSIX_SPAWN_SETPGROUP;
 
201
  fatal_assert(posix_spawnattr_setpgroup(&spawnattr, 0) == 0);
 
202
 
 
203
  fatal_assert(posix_spawnattr_setflags(&spawnattr, flags) == 0);
201
204
  
202
205
  create_argv(args);
203
206
 
254
257
  }
255
258
  else
256
259
  {
257
 
 
258
 
    if (_use_libtool)
259
 
    {
260
 
      spawn_ret= posix_spawn(&_pid, built_argv[0], &file_actions, &spawnattr, &built_argv[0], NULL);
261
 
    }
262
 
    else
263
 
    {
264
 
      spawn_ret= posix_spawnp(&_pid, built_argv[0], &file_actions, &spawnattr, &built_argv[0], NULL);
265
 
    }
 
260
    spawn_ret= posix_spawn(&_pid, built_argv[0], &file_actions, &spawnattr, &built_argv[0], NULL);
266
261
  }
267
262
 
268
263
  posix_spawn_file_actions_destroy(&file_actions);
279
274
      Error << strerror(spawn_ret) << "(" << spawn_ret << ")";
280
275
    }
281
276
    _pid= -1;
282
 
    return Application::INVALID;
283
 
  }
 
277
    return Application::INVALID_POSIX_SPAWN;
 
278
  }
 
279
 
 
280
  assert(_pid != -1);
 
281
  if (_pid == -1)
 
282
  {
 
283
    return Application::INVALID_POSIX_SPAWN;
 
284
  }
 
285
 
 
286
#if 0
 
287
  app_thread_st* _app_thread= new app_thread_st(_pid, _status, built_argv[0], _app_exit_state);
 
288
  int error;
 
289
  if ((error= pthread_create(&_thread, NULL, &app_thread, _app_thread)) != 0)
 
290
  {
 
291
    Error << "pthread_create() died during pthread_create(" << strerror(error) << ")";
 
292
    return Application::FAILURE;
 
293
  }
 
294
#endif
284
295
 
285
296
  return Application::SUCCESS;
286
297
}
302
313
    int count= 5;
303
314
    while ((count--) > 0 and check())
304
315
    {
305
 
      int kill_ret= kill(_pid, SIGTERM);
306
 
      if (kill_ret == 0)
 
316
      if (kill(_pid, SIGTERM) == 0)
307
317
      {
308
 
        int status= 0;
309
 
        pid_t waitpid_ret;
310
 
        if ((waitpid_ret= waitpid(_pid, &status, WNOHANG)) == -1)
311
 
        {
312
 
          switch (errno)
313
 
          {
314
 
          case ECHILD:
315
 
          case EINTR:
316
 
            break;
317
 
 
318
 
          default:
319
 
            Error << "waitpid() failed after kill with error of " << strerror(errno);
320
 
            break;
321
 
          }
322
 
        }
323
 
 
324
 
        if (waitpid_ret == 0)
325
 
        {
326
 
          libtest::dream(1, 0);
327
 
        }
 
318
        join();
328
319
      }
329
320
      else
330
321
      {
338
329
    // If for whatever reason it lives, kill it hard
339
330
    if (check())
340
331
    {
 
332
      Error << "using SIGKILL, things will likely go poorly from this point";
341
333
      (void)kill(_pid, SIGKILL);
342
334
    }
343
335
  }
409
401
  return data_was_read;
410
402
}
411
403
 
412
 
Application::error_t Application::wait(bool nohang)
413
 
{
414
 
  if (_pid == -1)
415
 
  {
416
 
    return Application::INVALID;
417
 
  }
418
 
 
419
 
  slurp();
420
 
 
421
 
  error_t exit_code= FAILURE;
422
 
  {
423
 
    int status= 0;
424
 
    pid_t waited_pid;
425
 
    if ((waited_pid= waitpid(_pid, &status, nohang ? WNOHANG : 0)) == -1)
426
 
    {
427
 
      switch (errno)
428
 
      {
429
 
      case ECHILD:
430
 
        exit_code= Application::SUCCESS;
431
 
        break;
432
 
 
433
 
      case EINTR:
434
 
        break;
435
 
 
436
 
      default:
437
 
        Error << "Error occured while waitpid(" << strerror(errno) << ") on pid " << int(_pid);
438
 
        break;
439
 
      }
440
 
    }
441
 
    else if (waited_pid == 0)
442
 
    {
443
 
      exit_code= Application::SUCCESS;
444
 
    }
445
 
    else
446
 
    {
447
 
      if (waited_pid != _pid)
448
 
      {
449
 
        throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "Pid mismatch, %d != %d", int(waited_pid), int(_pid));
450
 
      }
451
 
      exit_code= int_to_error_t(exited_successfully(status));
452
 
    }
453
 
  }
454
 
 
455
 
  slurp();
456
 
 
457
 
#if 0
458
 
  if (exit_code == Application::INVALID)
459
 
  {
460
 
    Error << print_argv(built_argv, _argc);
461
 
  }
462
 
#endif
463
 
 
464
 
  return exit_code;
465
 
}
466
 
 
467
404
Application::error_t Application::join()
468
405
{
469
 
  if (_pid == -1)
470
 
  {
471
 
    return Application::INVALID;
472
 
  }
473
 
 
474
 
  slurp();
475
 
 
476
 
  error_t exit_code= FAILURE;
477
 
  {
478
 
    int status= 0;
479
 
    pid_t waited_pid;
480
 
    do {
481
 
      waited_pid= waitpid(_pid, &status, 0);
482
 
    } while (waited_pid == -1 and (errno == EINTR or errno == EAGAIN));
483
 
 
484
 
    if (waited_pid == -1)
485
 
    {
486
 
      switch (errno)
 
406
  pid_t waited_pid= waitpid(_pid, &_status, 0);
 
407
 
 
408
  if (waited_pid == _pid and WIFEXITED(_status) == false)
 
409
  {
 
410
    /*
 
411
      What we are looking for here is how the exit status happened.
 
412
      - 127 means that posix_spawn() itself had an error.
 
413
      - If WEXITSTATUS is positive we need to see if it is a signal that we sent to kill the process. If not something bad happened in the process itself. 
 
414
      - Finally something has happened that we don't currently understand.
 
415
    */
 
416
    if (WEXITSTATUS(_status) == 127)
 
417
    {
 
418
      _app_exit_state= Application::INVALID_POSIX_SPAWN;
 
419
      std::string error_string("posix_spawn() failed pid:");
 
420
      error_string+= _pid;
 
421
      error_string+= " name:";
 
422
      error_string+= built_argv[0];
 
423
      throw std::logic_error(error_string);
 
424
    }
 
425
    else if WIFSIGNALED(_status)
 
426
    {
 
427
      // memcached will die with SIGHUP
 
428
      if (WTERMSIG(_status) != SIGTERM and WTERMSIG(_status) != SIGHUP)
487
429
      {
488
 
      case ECHILD:
489
 
        exit_code= Application::SUCCESS;
490
 
        break;
491
 
 
492
 
      case EINTR:
493
 
        break;
494
 
 
495
 
      default:
496
 
        Error << "Error occured while waitpid(" << strerror(errno) << ") on pid " << int(_pid);
497
 
        break;
 
430
        _app_exit_state= Application::INVALID_POSIX_SPAWN;
 
431
        std::string error_string(built_argv[0]);
 
432
        error_string+= " was killed by signal ";
 
433
        error_string+= strsignal(WTERMSIG(_status));
 
434
        throw std::runtime_error(error_string);
498
435
      }
499
 
    }
500
 
    else if (waited_pid == 0)
501
 
    {
502
 
      exit_code= Application::SUCCESS;
 
436
 
 
437
      _app_exit_state= Application::SIGTERM_KILLED;
 
438
      Error << "waitpid() application terminated at request"
 
439
        << " pid:" << _pid 
 
440
        << " name:" << built_argv[0];
503
441
    }
504
442
    else
505
443
    {
506
 
      if (waited_pid != _pid)
507
 
      {
508
 
        throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "Pid mismatch, %d != %d", int(waited_pid), int(_pid));
509
 
      }
510
 
 
511
 
      exit_code= int_to_error_t(exited_successfully(status));
 
444
      _app_exit_state= Application::UNKNOWN;
 
445
      Error << "Unknown logic state at exit:" << WEXITSTATUS(_status) 
 
446
        << " pid:" << _pid
 
447
        << " name:" << built_argv[0];
512
448
    }
513
449
  }
514
 
 
515
 
  slurp();
516
 
 
517
 
#if 0
518
 
  if (exit_code == Application::INVALID)
519
 
  {
520
 
    Error << print_argv(built_argv, _argc);
521
 
  }
522
 
#endif
523
 
 
524
 
  return exit_code;
 
450
  else if (waited_pid == _pid and WIFEXITED(_status))
 
451
  {
 
452
    _app_exit_state= int_to_error_t(WEXITSTATUS(_status));
 
453
  }
 
454
  else if (waited_pid == -1)
 
455
  {
 
456
    _app_exit_state= Application::UNKNOWN;
 
457
    Error << "waitpid() returned errno:" << strerror(errno);
 
458
  }
 
459
  else
 
460
  {
 
461
    _app_exit_state= Application::UNKNOWN;
 
462
    throw std::logic_error("waitpid() returned an unknown value");
 
463
  }
 
464
 
 
465
  return _app_exit_state;
525
466
}
526
467
 
527
468
void Application::add_long_option(const std::string& name, const std::string& option_value)
604
545
 
605
546
void Application::Pipe::nonblock()
606
547
{
607
 
  int ret;
608
 
  if ((ret= fcntl(_pipe_fd[READ], F_GETFL, 0)) == -1)
 
548
  int flags;
 
549
  {
 
550
    flags= fcntl(_pipe_fd[READ], F_GETFL, 0);
 
551
  } while (flags == -1 and (errno == EINTR or errno == EAGAIN));
 
552
 
 
553
  if (flags == -1)
609
554
  {
610
555
    Error << "fcntl(F_GETFL) " << strerror(errno);
611
556
    throw strerror(errno);
612
557
  }
613
558
 
614
 
  if ((ret= fcntl(_pipe_fd[READ], F_SETFL, ret | O_NONBLOCK)) == -1)
 
559
  int rval;
 
560
  do
 
561
  {
 
562
    rval= fcntl(_pipe_fd[READ], F_SETFL, flags | O_NONBLOCK);
 
563
  } while (rval == -1 and (errno == EINTR or errno == EAGAIN));
 
564
 
 
565
  if (rval == -1)
615
566
  {
616
567
    Error << "fcntl(F_SETFL) " << strerror(errno);
617
568
    throw strerror(errno);
624
575
  close(WRITE);
625
576
 
626
577
#if defined(HAVE_PIPE2) && HAVE_PIPE2
627
 
  if (pipe2(_pipe_fd, O_NONBLOCK) == -1)
 
578
  if (pipe2(_pipe_fd, O_NONBLOCK|O_CLOEXEC) == -1)
628
579
#else
629
580
  if (pipe(_pipe_fd) == -1)
630
581
#endif
634
585
  _open[0]= true;
635
586
  _open[1]= true;
636
587
 
637
 
  if (true)
 
588
#if defined(HAVE_PIPE2) && HAVE_PIPE2
638
589
  {
639
590
    nonblock();
640
591
    cloexec();
641
592
  }
 
593
#endif
642
594
}
643
595
 
644
596
void Application::Pipe::cloexec()
645
597
{
646
 
  int ret;
647
 
  if ((ret= fcntl(_pipe_fd[WRITE], F_GETFD, 0)) == -1)
648
 
  {
649
 
    Error << "fcntl(F_GETFD) " << strerror(errno);
650
 
    throw strerror(errno);
651
 
  }
652
 
 
653
 
  if ((ret= fcntl(_pipe_fd[WRITE], F_SETFD, ret | FD_CLOEXEC)) == -1)
654
 
  {
655
 
    Error << "fcntl(F_SETFD) " << strerror(errno);
656
 
    throw strerror(errno);
 
598
  //if (SOCK_CLOEXEC == 0)
 
599
  {
 
600
    if (FD_CLOEXEC) 
 
601
    {
 
602
      int flags;
 
603
      do 
 
604
      {
 
605
        flags= fcntl(_pipe_fd[WRITE], F_GETFD, 0);
 
606
      } while (flags == -1 and (errno == EINTR or errno == EAGAIN));
 
607
 
 
608
      if (flags == -1)
 
609
      {
 
610
        Error << "fcntl(F_GETFD) " << strerror(errno);
 
611
        throw strerror(errno);
 
612
      }
 
613
 
 
614
      int rval;
 
615
      do
 
616
      { 
 
617
        rval= fcntl(_pipe_fd[WRITE], F_SETFD, flags | FD_CLOEXEC);
 
618
      } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
 
619
 
 
620
      if (rval == -1)
 
621
      {
 
622
        Error << "fcntl(F_SETFD) " << strerror(errno);
 
623
        throw strerror(errno);
 
624
      }
 
625
    }
657
626
  }
658
627
}
659
628
 
716
685
  if (_use_valgrind)
717
686
  {
718
687
    /*
719
 
      valgrind --error-exitcode=1 --leak-check=yes --show-reachable=yes --track-fds=yes --malloc-fill=A5 --free-fill=DE
 
688
      valgrind --error-exitcode=1 --leak-check=yes --track-fds=yes --malloc-fill=A5 --free-fill=DE
720
689
    */
721
690
    built_argv.push_back(strdup("valgrind"));
722
691
    built_argv.push_back(strdup("--error-exitcode=1"));
723
692
    built_argv.push_back(strdup("--leak-check=yes"));
 
693
#if 0
724
694
    built_argv.push_back(strdup("--show-reachable=yes"));
 
695
#endif
725
696
    built_argv.push_back(strdup("--track-fds=yes"));
726
697
#if 0
727
698
    built_argv[x++]= strdup("--track-origin=yes");