4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Scheduler unit tests */
31 //#include "Scheduler.test.hh"
32 //#include "Scheduler.test.ih"
35 #include <sys/types.h>
39 #include <sys/socket.h>
44 #include <boost/bind.hpp>
46 #include "Scheduler.hh"
48 #include <senf/Utils/auto_unit_test.hh>
49 #include <boost/test/test_tools.hpp>
52 //-/////////////////////////////////////////////////////////////////////////////////////////////////
56 char const * SOCK_PATH = "/tmp/sched_test.sock";
58 void error(char const * fn, char const * proc="")
60 std::cerr << "\n" << proc << fn << ": " << strerror(errno) << std::endl;
63 void fail(char const * fn)
71 int sock = socket(PF_UNIX,SOCK_STREAM,0);
72 if (sock<0) fail("socket");
73 struct sockaddr_un sun;
74 memset(&sun,0,sizeof(sun));
75 sun.sun_family = AF_UNIX;
76 strcpy(sun.sun_path,SOCK_PATH);
77 if (bind(sock,(struct sockaddr*)&sun,sizeof(sun))<0) fail("bind");
78 if (listen(sock,1)<0) fail("listen");
79 int conn = accept(sock,0,0);
80 if (conn < 0) fail("accept");
82 //-/////////////////////////////////////////////////////////////////////////////////////////
84 if (write(conn,"READ",4)<0) fail("write");
86 int size = read(conn,buffer,1024);
87 if (size<0) fail("read");
90 if (strcmp(buffer,"WRITE")==0) {
91 if (write(conn,"OK",2)<0) fail("write");
93 if (write(conn,"FAIL",4)<0) fail("write");
95 if (write(conn,"FAIL",4)<0) fail("write");
97 //-/////////////////////////////////////////////////////////////////////////////////////////
108 signal(SIGCHLD, SIG_IGN);
116 signal(SIGCHLD, SIG_DFL);
118 sleep(1); // Wait for the server socket to be opened
122 bool stop_server(int pid)
124 sleep(1); // Wait for the server to terminate
125 if (kill(pid,SIGTERM)<0) {
130 if (waitpid(pid,&status,0)<0) {
135 if (WIFSIGNALED(status)) {
136 std::cerr << "\nserver terminated with signal " << WTERMSIG(status) << std::endl;
139 if (WEXITSTATUS(status)!=0) {
140 std::cerr << "\nserver terminated with exit status " << WEXITSTATUS(status) << std::endl;
150 void callback(int fd, int ev)
153 switch (event & senf::scheduler::FdEvent::EV_ALL) {
154 case senf::scheduler::FdEvent::EV_READ:
155 size = recv(fd,buffer,1024,0);
157 case senf::scheduler::FdEvent::EV_PRIO:
158 size = recv(fd,buffer,1024,MSG_OOB);
160 case senf::scheduler::FdEvent::EV_WRITE:
161 size = write(fd,buffer,size);
164 senf::scheduler::terminate();
167 bool timeoutCalled = false;
170 timeoutCalled = true;
171 senf::scheduler::terminate();
176 HandleWrapper(int fd,std::string const & tag) : fd_(fd), tag_(tag) {}
181 int retrieve_filehandle(HandleWrapper const & handle)
186 void handleCallback(HandleWrapper const & handle, int event)
188 if (handle.tag_ != "TheTag")
190 callback(handle.fd_,event);
193 bool is_close(senf::ClockService::clock_type a, senf::ClockService::clock_type b)
195 return (a<b ? b-a : a-b) < senf::ClockService::milliseconds(100);
198 senf::ClockService::clock_type sigtime (0);
200 void sigusr(siginfo_t const &)
202 sigtime = senf::ClockService::now();
203 senf::scheduler::terminate();
206 void delay(unsigned long milliseconds)
209 ts.tv_sec = milliseconds / 1000;
210 ts.tv_nsec = (milliseconds % 1000) * 1000000;
211 while (nanosleep(&ts,&ts) < 0 && errno == EINTR) ;
214 void blockingHandler()
217 senf::scheduler::terminate();
220 unsigned eventCount (0);
222 void eventeventhandler()
230 char const * enabled (getenv("SENF_TIMING_CRITICAL_TESTS"));
231 BOOST_WARN_MESSAGE(enabled, "Set SENF_TIMING_CRITICAL_TESTS to not skip timing critical tests");
233 int pid = start_server();
236 int sock = socket(PF_UNIX,SOCK_STREAM,0);
239 BOOST_FAIL("socket");
241 struct sockaddr_un sun;
242 memset(&sun,0,sizeof(sun));
243 sun.sun_family = AF_UNIX;
244 strcpy(sun.sun_path,SOCK_PATH);
246 if (connect(sock,(struct sockaddr*)&sun,sizeof(sun))<0) {
248 BOOST_FAIL("connect");
251 //-/////////////////////////////////////////////////////////////////////////////////////////////
253 senf::scheduler::EventHook evev ("eventCounter", eventeventhandler,
254 senf::scheduler::EventHook::PRE);
257 senf::scheduler::FdEvent fde1 ("testFdEvent", boost::bind(&callback, sock, _1),
258 sock, senf::scheduler::FdEvent::EV_READ);
259 event = senf::scheduler::FdEvent::EV_NONE;
260 SENF_CHECK_NO_THROW( senf::scheduler::process() );
261 BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_READ );
262 BOOST_REQUIRE_EQUAL( size, 4 );
264 BOOST_CHECK_EQUAL( buffer, "READ" );
266 HandleWrapper handle(sock,"TheTag");
267 senf::scheduler::FdEvent fde2 ("testFdEvent", boost::bind(&handleCallback,handle,_1),
268 handle, senf::scheduler::FdEvent::EV_WRITE);
269 strcpy(buffer,"WRITE");
271 event = senf::scheduler::FdEvent::EV_NONE;
272 SENF_CHECK_NO_THROW( senf::scheduler::process() );
273 BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_WRITE );
275 SENF_CHECK_NO_THROW( fde2.disable() );
276 event = senf::scheduler::FdEvent::EV_NONE;
278 SENF_CHECK_NO_THROW( senf::scheduler::process() );
279 BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_READ|senf::scheduler::FdEvent::EV_HUP );
280 BOOST_REQUIRE_EQUAL( size, 2 );
282 BOOST_CHECK_EQUAL( buffer, "OK" );
286 senf::scheduler::TimerEvent timer1 ("testTimer1", &timeout,
287 senf::ClockService::now()+senf::ClockService::milliseconds(200));
288 senf::scheduler::TimerEvent timer2 ("testTimer2", &timeout,
289 senf::ClockService::now()+senf::ClockService::milliseconds(400));
291 event = senf::scheduler::FdEvent::EV_NONE;
292 senf::ClockService::clock_type t (senf::ClockService::now());
293 SENF_CHECK_NO_THROW( senf::scheduler::process() );
295 BOOST_CHECK_PREDICATE( is_close, (senf::ClockService::now()-t) (senf::ClockService::milliseconds(200)) );
296 BOOST_CHECK( timeoutCalled );
297 BOOST_CHECK( ! timer1.enabled() );
298 BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_NONE );
300 BOOST_CHECK_PREDICATE( is_close, (senf::ClockService::now()) (senf::scheduler::eventTime()) );
301 timeoutCalled = false;
302 SENF_CHECK_NO_THROW( senf::scheduler::process() );
304 BOOST_CHECK_PREDICATE( is_close, (senf::ClockService::now()-t) (senf::ClockService::milliseconds(400)) );
305 BOOST_CHECK( timeoutCalled );
306 BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_NONE );
307 BOOST_CHECK( ! timer2.enabled() );
309 BOOST_MESSAGE( "A 'Scheduler task hanging' error is expected to be signaled here." );
310 SENF_CHECK_NO_THROW( timer1.action(&blockingHandler) );
311 SENF_CHECK_NO_THROW( timer1.timeout(senf::ClockService::now()) );
312 SENF_CHECK_NO_THROW( senf::scheduler::process() );
313 BOOST_CHECK_EQUAL( senf::scheduler::watchdogEvents(), 1u );
317 senf::scheduler::TimerEvent timer ("testWatchdog", &timeout,
318 senf::ClockService::now()+senf::ClockService::milliseconds(400));
319 senf::scheduler::SignalEvent sig (SIGUSR1, &sigusr);
321 senf::ClockService::clock_type t = senf::ClockService::now();
322 ::kill(::getpid(), SIGUSR1);
324 SENF_CHECK_NO_THROW( senf::scheduler::process() );
326 BOOST_CHECK_PREDICATE( is_close, (senf::ClockService::now()) (t+senf::ClockService::milliseconds(200)) );
327 BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+senf::ClockService::milliseconds(200)) );
329 SENF_CHECK_NO_THROW( senf::scheduler::process() );
332 BOOST_CHECK( eventCount >= 8u );
335 //-/////////////////////////////////////////////////////////////////////////////////////////////
339 BOOST_CHECK (stop_server(pid));
342 SENF_AUTO_UNIT_TEST(testSchedulerPollTimers)
344 BOOST_CHECK( ! senf::scheduler::usingHiresTimers() );
348 SENF_AUTO_UNIT_TEST(testSchedulerHiresTimers)
350 if (senf::scheduler::haveScalableHiresTimers())
351 BOOST_MESSAGE( "Using timerfd() hires timers" );
353 BOOST_MESSAGE( "Using POSIX hires timers");
354 SENF_CHECK_NO_THROW( senf::scheduler::hiresTimers() );
355 BOOST_CHECK( senf::scheduler::usingHiresTimers() );
357 SENF_CHECK_NO_THROW( senf::scheduler::loresTimers() );
358 BOOST_CHECK( ! senf::scheduler::usingHiresTimers() );
361 SENF_AUTO_UNIT_TEST(testSchedulerPOSIXTimers)
363 if (senf::scheduler::haveScalableHiresTimers()) {
364 SENF_CHECK_NO_THROW( senf::scheduler::detail::TimerDispatcher::instance().timerSource(
365 std::auto_ptr<senf::scheduler::detail::TimerSource>(
366 new senf::scheduler::detail::POSIXTimerSource())) );
368 senf::scheduler::loresTimers();
376 senf::scheduler::BlockSignals signalBlocker;
377 signalBlocker.block();
378 signalBlocker.unblock();
379 BOOST_CHECK( ! signalBlocker.blocked() );
380 signalBlocker.unblock();
381 signalBlocker.block();
382 BOOST_CHECK( signalBlocker.blocked() );
383 ::kill(::getpid(), SIGUSR1);
389 SENF_AUTO_UNIT_TEST(blockSignals)
391 char const * enabled (getenv("SENF_TIMING_CRITICAL_TESTS"));
392 BOOST_WARN_MESSAGE(enabled, "Set SENF_TIMING_CRITICAL_TESTS to not skip timing critical tests");
394 senf::scheduler::TimerEvent signaler ("sigme", &sigme, senf::ClockService::now());
395 senf::scheduler::TimerEvent timer (
396 "testWatchdog", &timeout, senf::ClockService::now()+senf::ClockService::milliseconds(400));
397 senf::scheduler::SignalEvent sig (SIGUSR1, &sigusr);
399 senf::ClockService::clock_type t = senf::ClockService::now();
400 SENF_CHECK_NO_THROW( senf::scheduler::process() );
403 BOOST_CHECK_PREDICATE( is_close,
404 (senf::ClockService::now())
405 (t+senf::ClockService::milliseconds(200)) );
406 BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+senf::ClockService::milliseconds(200)) );
409 SENF_CHECK_NO_THROW( senf::scheduler::process() );
412 //-/////////////////////////////////////////////////////////////////////////////////////////////////
419 // c-file-style: "senf"
420 // indent-tabs-mode: nil
421 // ispell-local-dictionary: "american"
422 // compile-command: "scons -u test"
423 // comment-column: 40