2 //=============================================================================
6 * This is a simple test to illustrate OS thread preemption. One
7 * ore more high priority threads periodically (every half
8 * second, by default) reads the clock. They use select () to
9 * block for that duration. Meanwhile, a low priority thread
10 * continually chews up the CPU. Without preemption, the high
11 * priority thread won't have a chance to read the clock in a
14 * At the end of the test, the actual clock read intervals by the
15 * high priority task(s) are printed out. With proper
16 * preemption, the intervals should correspond to the requested
17 * clock read interval.
19 * There is a -y option for the low priority thread to periodically
20 * yield. It shouldn't be necessary to use that option, if preemption
21 * is supported. It's a handy option for testing.
23 * @author David L. Levine
25 //=============================================================================
28 #include "ace/OS_main.h"
31 #include "ace/Sched_Params.h"
32 #include "ace/Get_Opt.h"
33 #include "ace/OS_NS_sys_select.h"
34 #include "ace/OS_NS_time.h"
35 #include "ace/OS_NS_errno.h"
36 #include "ace/OS_NS_unistd.h"
38 #if defined (ACE_HAS_THREADS) || ! defined (ACE_LACKS_FORK)
40 static const char usage
[] = "[-? |\n"
41 #if defined (ACE_HAS_THREADS)
42 " [-f use fork instead of spawn]\n"
43 #endif /* ACE_HAS_THREADS */
44 " [-h <high pri iterations, default 10>]\n"
45 " [-l <low pri iterations, default 25000>]\n"
46 " [-n <high priority threads, default 1>]\n"
47 " [-p <read period, default 500000 usec>]\n"
48 " [-y to yield the low priority thread]]\n";
50 // Configuration options.
51 #if defined (ACE_HAS_THREADS)
53 #else /* ! ACE_HAS_THREADS */
55 #endif /* ! ACE_HAS_THREADS */
56 u_int high_iterations
= 10;
57 u_int high_priority_tasks
= 1;
58 u_int low_iterations
= 25000; /* Big enough to keep the low priority task
59 cranking for a while */
60 u_long read_period
= 500000; /* usec */
63 // To permit calculation of relative times.
64 ACE_hrtime_t starttime
;
67 ///////////////////////////////////////////////////////////////////////////////
68 ///////////////////////////////////////////////////////////////////////////////
69 // class High_Priority_Task
70 ///////////////////////////////////////////////////////////////////////////////
71 ///////////////////////////////////////////////////////////////////////////////
73 class High_Priority_Task
: public ACE_Task
<ACE_SYNCH
>
76 High_Priority_Task ();
77 ~High_Priority_Task ();
79 //FUZZ: disable check_for_lack_ACE_OS
81 //FUZZ: enable check_for_lack_ACE_OS
84 int done () const { return done_
; }
85 void print_times () const;
93 High_Priority_Task::High_Priority_Task ()
94 : ACE_Task
<ACE_SYNCH
> (ACE_Thread_Manager::instance ()),
95 priority_ (ACE_Sched_Params::next_priority (
97 ACE_Sched_Params::priority_min (ACE_SCHED_FIFO
,
102 ACE_NEW (time_
, u_long
[high_iterations
]);
105 High_Priority_Task::~High_Priority_Task ()
112 High_Priority_Task::open (void *)
116 ACE_hthread_t thr_handle
;
117 ACE_Thread::self (thr_handle
);
119 if (ACE_Thread::setprio (thr_handle
, priority_
) == -1)
120 ACE_ERROR_RETURN ((LM_ERROR
, "%p\n", "setprio failed"), -1);
126 long flags
= THR_BOUND
| THR_NEW_LWP
| THR_SCHED_FIFO
;
128 // Become an active object.
129 if (this->activate (flags
, 1, 0, this->priority_
) == -1)
131 ACE_DEBUG ((LM_ERROR
, "(%P|%t) task activation failed, exiting!\n"));
140 High_Priority_Task::svc ()
142 ACE_hthread_t thr_handle
;
143 ACE_Thread::self (thr_handle
);
146 if (ACE_Thread::getprio (thr_handle
, prio
) == -1)
147 ACE_ERROR_RETURN ((LM_ERROR
, "%p\n", "getprio failed"), -1);
149 ACE_DEBUG ((LM_DEBUG
, "(%P|%t) High: prio = %d, priority_ = %d\n",
150 prio
, this->priority_
));
152 ACE_ASSERT (this->priority_
== prio
);
154 ACE_Time_Value
pause (0, read_period
);
156 for (u_int i
= 0; i
< high_iterations
; ++i
)
158 time_
[i
] = (u_long
) ((ACE_OS::gethrtime () - starttime
)/
159 (ACE_UINT32
) 1000000u);
160 ACE_OS::select (0, 0, 0, 0, &pause
);
169 High_Priority_Task::print_times () const
171 for (u_int i
= 0; i
< high_iterations
; ++i
)
173 ACE_DEBUG ((LM_INFO
, " iteration %u, time %u msec\n",
179 ///////////////////////////////////////////////////////////////////////////////
180 ///////////////////////////////////////////////////////////////////////////////
181 // class Low_Priority_Task
182 ///////////////////////////////////////////////////////////////////////////////
183 ///////////////////////////////////////////////////////////////////////////////
185 class Low_Priority_Task
: public ACE_Task
<ACE_SYNCH
>
188 Low_Priority_Task (const High_Priority_Task
&);
190 //FUZZ: disable check_for_lack_ACE_OS
192 //FUZZ: enable check_for_lack_ACE_OS
198 const High_Priority_Task
&high_priority_task_
;
201 Low_Priority_Task::Low_Priority_Task (
202 const High_Priority_Task
&high_priority_task
)
203 : ACE_Task
<ACE_SYNCH
> (ACE_Thread_Manager::instance ()),
204 priority_ (ACE_Sched_Params::priority_min (ACE_SCHED_FIFO
,
206 high_priority_task_ (high_priority_task
)
211 Low_Priority_Task::open (void *)
215 ACE_hthread_t thr_handle
;
216 ACE_Thread::self (thr_handle
);
218 if (ACE_Thread::setprio (thr_handle
, priority_
) == -1)
219 ACE_ERROR_RETURN ((LM_ERROR
, "%p\n", "setprio failed"), -1);
225 long flags
= THR_BOUND
| THR_NEW_LWP
| THR_SCHED_FIFO
;
227 // Become an active object.
228 if (this->activate (flags
, 1, 0, this->priority_
) == -1)
229 ACE_ERROR ((LM_ERROR
,
230 "(%P|%t) task activation failed, exiting!\n%a",
237 Low_Priority_Task::svc ()
239 ACE_hthread_t thr_handle
;
240 ACE_Thread::self (thr_handle
);
243 if (ACE_Thread::getprio (thr_handle
, prio
) == -1)
244 ACE_ERROR_RETURN ((LM_ERROR
, "%p\n", "getprio failed"), -1);
246 ACE_DEBUG ((LM_DEBUG
, "(%P|%t) Low: prio = %d, priority_ = %d\n",
247 prio
, this->priority_
));
249 ACE_ASSERT (this->priority_
== prio
);
251 u_long iterations
= 0;
253 // Chew up CPU for the entire interval.
255 ! high_priority_task_
.done () && iterations
< low_iterations
;
258 u_long n
= 1279ul; /* Takes about 40.2 usecs on a 168 MHz Ultra2. */
260 2ul /* min_factor */,
261 n
/2 /* max_factor */);
264 ACE_OS::thr_yield ();
267 ACE_DEBUG ((LM_INFO
, "Low completed %u iterations\n", iterations
));
273 ///////////////////////////////////////////////////////////////////////////////
274 ///////////////////////////////////////////////////////////////////////////////
275 // function get_options
276 ///////////////////////////////////////////////////////////////////////////////
277 ///////////////////////////////////////////////////////////////////////////////
280 get_options (int argc
, ACE_TCHAR
*argv
[])
282 ACE_Get_Opt
get_opt (argc
, argv
, ACE_TEXT("fh:l:n:p:y?"));
284 while ((opt
= get_opt ()) != EOF
) {
290 if (ACE_OS::atoi (get_opt
.opt_arg ()) >= 2)
291 high_iterations
= ACE_OS::atoi (get_opt
.opt_arg ());
293 ACE_ERROR_RETURN ((LM_ERROR
, "%n: high iterations must be >= 2\n"),
297 if (ACE_OS::atoi (get_opt
.opt_arg ()) >= 2)
298 low_iterations
= ACE_OS::atoi (get_opt
.opt_arg ());
300 ACE_ERROR_RETURN ((LM_ERROR
, "%n: low iterations must be >= 2\n"), -1);
303 if (ACE_OS::atoi (get_opt
.opt_arg ()) >= 1)
304 high_priority_tasks
= ACE_OS::atoi (get_opt
.opt_arg ());
306 ACE_ERROR_RETURN ((LM_ERROR
, "%n: number of high priority threads "
307 "must be >= 1\n"), -1);
310 if (ACE_OS::atoi (get_opt
.opt_arg ()) > 0)
311 read_period
= ACE_OS::atoi (get_opt
.opt_arg ());
313 ACE_ERROR_RETURN ((LM_ERROR
, "%n: read period > 0\n"), -1);
319 ACE_DEBUG ((LM_ERROR
, "usage: %n %s\n%a", usage
, 0));
322 ACE_ERROR_RETURN ((LM_ERROR
,
323 "%n: unknown arg, %c\nusage: %n %s\n", opt
, usage
),
328 switch (argc
- get_opt
.opt_ind ()) {
330 // OK, no non-flag arguments.
333 ACE_ERROR_RETURN ((LM_ERROR
,
334 "%n: too many arguments\nusage: %n %s\n", usage
),
341 #endif /* ACE_HAS_THREADS || ! ACE_LACKS_FORK */
344 ///////////////////////////////////////////////////////////////////////////////
345 ///////////////////////////////////////////////////////////////////////////////
347 ///////////////////////////////////////////////////////////////////////////////
348 ///////////////////////////////////////////////////////////////////////////////
351 ACE_TMAIN (int argc
, ACE_TCHAR
*argv
[])
353 ACE_LOG_MSG
->open (argv
[0] ? argv
[0] : ACE_TEXT("preempt"));
355 #if defined (ACE_HAS_THREADS) || !defined (ACE_LACKS_FORK)
359 if (get_options (argc
, argv
))
362 // Enable FIFO scheduling
363 if (ACE_OS::sched_params (
366 ACE_Sched_Params::priority_min (ACE_SCHED_FIFO
),
367 ACE_SCOPE_PROCESS
)) != 0)
369 if (ACE_OS::last_error () == EPERM
)
370 ACE_DEBUG ((LM_MAX
, "preempt: user is not superuser, "
371 "so remain in time-sharing class\n"));
373 ACE_ERROR_RETURN ((LM_ERROR
, "%n: ACE_OS::sched_params failed\n%a"),
377 High_Priority_Task
*high_priority_task
;
378 ACE_NEW_RETURN (high_priority_task
, High_Priority_Task
[high_priority_tasks
],
381 Low_Priority_Task
low_priority_task (high_priority_task
[0]);
385 ACE_DEBUG ((LM_DEBUG
,
386 "(%P|%t) main (), wait for threads to exit . . .\n"));
389 // Save the start time, so that deltas can be displayed later.
390 starttime
= ACE_OS::gethrtime ();
392 // Spawn the threads/processes . . .
396 switch ((child
= ACE_OS::fork (ACE_TEXT("preempt-low_priority_process"))))
399 ACE_ERROR ((LM_ERROR
, "%p\n%a", "fork failed"));
403 low_priority_task
.open (0);
406 default: // In parent
407 for (i
= 0; i
< high_priority_tasks
; ++i
)
409 high_priority_task
[i
].open (0);
416 for (i
= 0; i
< high_priority_tasks
; ++i
)
418 high_priority_task
[i
].open (0);
420 low_priority_task
.open (0);
422 #if defined (ACE_HAS_THREADS)
423 // Wait for all threads to exit.
424 ACE_Thread_Manager::instance ()->wait ();
425 #endif /* ACE_HAS_THREADS */
428 // Display the time deltas. They should be about a half second apart.
429 if (child
|| ! use_fork
)
431 for (i
= 0; i
< high_priority_tasks
; ++i
)
433 ACE_DEBUG ((LM_DEBUG
, "High priority task %u:\n", i
+ 1));
434 high_priority_task
[i
].print_times ();
438 delete [] high_priority_task
;
440 #else /* ! ACE_HAS_THREADS && ACE_LACKS_FORK */
441 ACE_UNUSED_ARG (argc
);
442 ACE_UNUSED_ARG (argv
);
443 ACE_ERROR ((LM_ERROR
, "threads and fork not supported on this platform\n"));
444 #endif /* ! ACE_HAS_THREADS && ACE_LACKS_FORK */