Hello,

    While porting a pthread-application from Linux to Cygwin I found
out that pthread_kill() behaves differently on Linux and Cygwin. It
looks like with Cygwin pthread_kill() sends a signal to the caller
thread instead of the thread specified in the argument list. I have
attached a test program and the output on Linux and on Cygwin with
this E-mail (in the included output you can see that I ran the test
program once on Cygwin, and four times on Linux).

Regards,

Bart Van Assche.
#include <cassert>
#include <cerrno>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>


#if defined NDEBUG
#define VERIFY(e) do { (e); } while (0)
#else
#define VERIFY(e) do { assert(e); } while (0)
#endif


static pthread_mutex_t s_Mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  s_Cond  = PTHREAD_COND_INITIALIZER;

static void EmptySignalHandler(int)
{ }

static void* ThreadEntry(void*)
{
  // Let the main thread know that the created thread started.
  VERIFY(pthread_mutex_lock(&s_Mutex) == 0);
  VERIFY(pthread_cond_signal(&s_Cond) == 0);
  VERIFY(pthread_mutex_unlock(&s_Mutex) == 0);
  // Wait until this thread is interrupted by pthread_kill().
  timeval tvDelay = { 1000, 0 };
  int const iResult = select(0, 0, 0, 0, &tvDelay);
  assert(iResult < 0 && errno == EINTR);
  return 0;
}

int main()
{
  // Make sure that SIGALRM does not terminate the process.
  struct sigaction SA;
  memset(&SA, 0, sizeof(SA));
  SA.sa_handler = &EmptySignalHandler;
  sigemptyset(&SA.sa_mask);
  sigaction(SIGALRM, &SA, 0);

  // Create a thread.
  pthread_t TID = 0;
  VERIFY(pthread_mutex_lock(&s_Mutex) == 0);
  VERIFY(pthread_create(&TID, 0, ThreadEntry, 0) == 0);
  assert(TID != 0);
  VERIFY(pthread_cond_wait(&s_Cond, &s_Mutex) == 0);
  // Delay for 300 ms, in order to ensure that the thread is inside select()
  // when pthread_kill() is called from this thread.
  timeval tvDelay;
  tvDelay.tv_sec  = 0;
  tvDelay.tv_usec = 300 * 1000;
  VERIFY(select(0, 0, 0, 0, &tvDelay) == 0);
  // Query the wall clock time before calling select().
  timeval tvStart;
  gettimeofday(&tvStart, 0);
  // Interrupt any OS call the thread is doing by sending SIGALRM to it.
  VERIFY(pthread_kill(TID, SIGALRM) == 0);
  // Call select() with a timeout of 1s.
  tvDelay.tv_sec  = 1;
  tvDelay.tv_usec = 0;
  int const iResult = select(0, 0, 0, 0, &tvDelay);
  // Again query the wall clock time.
  timeval tvEnd;
  gettimeofday(&tvEnd, 0);
  timeval tvElapsed;
  timersub(&tvEnd, &tvStart, &tvElapsed);
  double const dElapsed = tvElapsed.tv_sec + tvElapsed.tv_usec * 1e-6;
  printf("select() returned after %f s with result %d / errno = %d\n",
         dElapsed, iResult, errno);
  assert(iResult == 0);
  // At least one second must have elapsed during the select() call.
  assert(dElapsed >= 0.99);
  VERIFY(pthread_join(TID, 0) == 0);
  VERIFY(pthread_mutex_unlock(&s_Mutex) == 0);
  return 0;
}

/*
  Local variables:
  compile-command: "g++ -Wall -W ptk.cpp -o ptk -lpthread"
  End:
*/
select() returned after 0.999753 s with result 0 / errno = 0
select() returned after 0.999751 s with result 0 / errno = 0
select() returned after 0.999749 s with result 0 / errno = 0
select() returned after 1.000750 s with result 0 / errno = 0
select() returned after 0.000000 s with result -1 / errno = 4
assertion "iResult == 0" failed: file "ptk.cpp", line 76
Aborted (core dumped)

Attachment: cygcheck.out
Description: Binary data

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/

Reply via email to