blob: 4265d0c27f415b0d85a36071e666404eab17b7c7 [file] [log] [blame]
/************************************************************************
*
* alarm.cpp - definitions of testsuite helpers
*
* $Id$
*
************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 2005-2006 Rogue Wave Software.
*
**************************************************************************/
// expand _TEST_EXPORT macros
#define _RWSTD_TEST_SRC
// including <time.h> first works around a SunPro/SunOS bug (PR #26255)
#include <time.h> // for time_t
#include <assert.h> // for assert()
#include <stdio.h> // for sprintf()
#include <rw_alarm.h> // for rw_alarm()
#include <rw_printf.h> // for rw_fprintf()
// avoid re-declaring the constants below extern exported to prevent
// MSVC error: object must have external linkage in order to be
// exported/imported
/* extern _TEST_EXPORT */ rw_signal_handler_t* const
rw_sig_dfl = (rw_signal_handler_t*)0;
/* extern _TEST_EXPORT */ rw_signal_handler_t* const
rw_sig_ign = (rw_signal_handler_t*)1;
/* extern _TEST_EXPORT */ rw_signal_handler_t* const
rw_sig_hold = (rw_signal_handler_t*)2;
/* extern _TEST_EXPORT */ rw_signal_handler_t* const
rw_sig_restore = (rw_signal_handler_t*)3;
// may point to a user-defined handler for the alarm
static rw_signal_handler_t*
_rw_alarm_handler;
#ifdef _WIN32
#include <windows.h>
// CygWin doesn't seem to define alarm()...
// thread procedure
static DWORD WINAPI
_rw_alarm_proc (LPVOID arg /* seconds */)
{
Sleep (1000U * (ULONG)arg);
rw_fprintf (rw_stderr, "%s:%d alarm expired\n", __FILE__, __LINE__);
if (_rw_alarm_handler)
_rw_alarm_handler (0);
else
abort (); // no SIGALRM on Win32
return 0;
}
// rough equivalent of POSIX alarm
_TEST_EXPORT
unsigned int
rw_alarm (unsigned int nsec, rw_signal_handler_t* handler /* = 0 */)
{
static HANDLE thread = 0; // thread handle (one alarm per process)
static unsigned pending = 0; // previous alarm() argument
static time_t t0 = 0; // start of previous alarm()
time_t unslept = 0; // seconds until previous alarm expires
if (thread) {
// previous alarm is still pending, cancel it
unslept = pending - (time (0) - t0);
TerminateThread (thread, 0);
CloseHandle (thread);
thread = 0;
}
pending = nsec;
if (nsec) {
time (&t0); // keep track of when countdown started
if (handler) {
// take care not to overwrite any previously set handler
_rw_alarm_handler = handler;
}
DWORD tid; // dummy (not used, required on Win95)
thread = CreateThread (0, 0, _rw_alarm_proc, (LPVOID)nsec, 0, &tid);
// thread handle will leak unless alarm (0) is called
}
return unsigned (unslept);
}
#else // ifndef _WIN32
# include <signal.h> // for SIGALRM, signal()
# include <unistd.h> // for alarm(), write()
// define macros in case they aren't #defined by
// the system headers e.g., when using pure libc headers
# ifndef SIGALRM
# define SIGALRM 14 /* e.g., Solaris */
# endif
# ifndef SIG_DFL
# define SIG_DFL (rw_signal_handler_t*)0
# endif // SIG_DFL
# ifndef SIG_IGN
# define SIG_IGN (rw_signal_handler_t*)1
# endif // SIG_IGN
# ifndef SIG_HOLD
# define SIG_HOLD (rw_signal_handler_t*)2
# endif // SIG_HOLD
extern "C" {
static void
_rw_handle_sigalrm (int signo)
{
assert (SIGALRM == signo);
char buffer [1024];
// fprintf() is not async-signal safe...
const int len =
sprintf (buffer, "%s:%d: alarm expired\n", __FILE__, __LINE__);
// ...use write() instead
write (STDERR_FILENO, buffer, size_t (len));
if (_rw_alarm_handler)
_rw_alarm_handler (signo);
}
} // extern "C"
_TEST_EXPORT
unsigned
rw_alarm (unsigned int nsec, rw_signal_handler_t* handler /* = 0 */)
{
static rw_signal_handler_t* saved_handler = 0;
static unsigned saved_nsec = 0;
if (rw_sig_hold == handler) {
// hold and save the current SIGALRM handler
// and just retrieve the current alarm
saved_handler = signal (SIGALRM, (rw_signal_handler_t*)SIG_HOLD);
saved_nsec = alarm (0);
alarm (saved_nsec);
return saved_nsec;
}
if (rw_sig_restore == handler) {
// restore the previously saved SIGALRM handler
// and set a new alarm to go off approximately
// after (saved_nsec - nsec) seconds
if (saved_handler) {
signal (SIGALRM, saved_handler);
if (nsec < saved_nsec)
nsec = saved_nsec - nsec;
else
nsec = 1;
alarm (nsec);
// return the new timeout
return nsec;
}
// return 0 to indicate that no alarm was set
return 0;
}
if (rw_sig_dfl == handler) {
signal (SIGALRM, (rw_signal_handler_t*)SIG_DFL);
}
else if (rw_sig_ign == handler) {
signal (SIGALRM, (rw_signal_handler_t*)SIG_IGN);
}
else if (handler) {
// take care not to overwrite any previously set handler
_rw_alarm_handler = handler;
signal (SIGALRM, _rw_handle_sigalrm);
}
return alarm (nsec);
}
#endif // _WIN32