-
Notifications
You must be signed in to change notification settings - Fork 0
/
timer_create.html
642 lines (482 loc) · 18.5 KB
/
timer_create.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
<!-- Creator : groff version 1.22.4 -->
<!-- CreationDate: Wed Jan 29 11:26:12 2020 -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta name="generator" content="groff -Thtml, see www.gnu.org">
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<meta name="Content-Style" content="text/css">
<style type="text/css">
p { margin-top: 0; margin-bottom: 0; vertical-align: top }
pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
table { margin-top: 0; margin-bottom: 0; vertical-align: top }
h1 { text-align: center }
</style>
<title>TIMER_CREATE</title>
</head>
<body>
<h1 align="center">TIMER_CREATE</h1>
<a href="#NAME">NAME</a><br>
<a href="#SYNOPSIS">SYNOPSIS</a><br>
<a href="#DESCRIPTION">DESCRIPTION</a><br>
<a href="#RETURN VALUE">RETURN VALUE</a><br>
<a href="#ERRORS">ERRORS</a><br>
<a href="#VERSIONS">VERSIONS</a><br>
<a href="#CONFORMING TO">CONFORMING TO</a><br>
<a href="#NOTES">NOTES</a><br>
<a href="#EXAMPLE">EXAMPLE</a><br>
<a href="#SEE ALSO">SEE ALSO</a><br>
<a href="#COLOPHON">COLOPHON</a><br>
<hr>
<h2>NAME
<a name="NAME"></a>
</h2>
<p style="margin-left:11%; margin-top: 1em">timer_create -
create a POSIX per-process timer</p>
<h2>SYNOPSIS
<a name="SYNOPSIS"></a>
</h2>
<p style="margin-left:11%; margin-top: 1em"><b>#include
<signal.h> <br>
#include <time.h></b></p>
<p style="margin-left:11%; margin-top: 1em"><b>int
timer_create(clockid_t</b> <i>clockid</i><b>, struct
sigevent *</b><i>sevp</i><b>, <br>
timer_t *</b><i>timerid</i><b>);</b></p>
<p style="margin-left:11%; margin-top: 1em">Link with
<i>-lrt</i>.</p>
<p style="margin-left:5%; margin-top: 1em">Feature Test
Macro Requirements for glibc (see
<b>feature_test_macros</b>(7)):</p>
<p style="margin-left:11%; margin-top: 1em"><b>timer_create</b>():
_POSIX_C_SOURCE >= 199309L</p>
<h2>DESCRIPTION
<a name="DESCRIPTION"></a>
</h2>
<p style="margin-left:11%; margin-top: 1em"><b>timer_create</b>()
creates a new per-process interval timer. The ID of the new
timer is returned in the buffer pointed to by
<i>timerid</i>, which must be a non-null pointer. This ID is
unique within the process, until the timer is deleted. The
new timer is initially disarmed.</p>
<p style="margin-left:11%; margin-top: 1em">The
<i>clockid</i> argument specifies the clock that the new
timer uses to measure time. It can be specified as one of
the following values: <b><br>
CLOCK_REALTIME</b></p>
<p style="margin-left:22%;">A settable system-wide
real-time clock.</p>
<p style="margin-left:11%;"><b>CLOCK_MONOTONIC</b></p>
<p style="margin-left:22%;">A nonsettable monotonically
increasing clock that measures time from some unspecified
point in the past that does not change after system
startup.</p>
<p style="margin-left:11%;"><b>CLOCK_PROCESS_CPUTIME_ID</b>
(since Linux 2.6.12)</p>
<p style="margin-left:22%;">A clock that measures (user and
system) CPU time consumed by (all of the threads in) the
calling process.</p>
<p style="margin-left:11%;"><b>CLOCK_THREAD_CPUTIME_ID</b>
(since Linux 2.6.12)</p>
<p style="margin-left:22%;">A clock that measures (user and
system) CPU time consumed by the calling thread.</p>
<p style="margin-left:11%;"><b>CLOCK_BOOTTIME</b> (Since
Linux 2.6.39)</p>
<p style="margin-left:22%;">Like <b>CLOCK_MONOTONIC</b>,
this is a monotonically increasing clock. However, whereas
the <b>CLOCK_MONOTONIC</b> clock does not measure the time
while a system is suspended, the <b>CLOCK_BOOTTIME</b> clock
does include the time during which the system is suspended.
This is useful for applications that need to be
suspend-aware. <b>CLOCK_REALTIME</b> is not suitable for
such applications, since that clock is affected by
discontinuous changes to the system clock.</p>
<p style="margin-left:11%;"><b>CLOCK_REALTIME_ALARM</b>
(since Linux 3.0)</p>
<p style="margin-left:22%;">This clock is like
<b>CLOCK_REALTIME</b>, but will wake the system if it is
suspended. The caller must have the <b>CAP_WAKE_ALARM</b>
capability in order to set a timer against this clock.</p>
<p style="margin-left:11%;"><b>CLOCK_BOOTTIME_ALARM</b>
(since Linux 3.0)</p>
<p style="margin-left:22%;">This clock is like
<b>CLOCK_BOOTTIME</b>, but will wake the system if it is
suspended. The caller must have the <b>CAP_WAKE_ALARM</b>
capability in order to set a timer against this clock.</p>
<p style="margin-left:11%; margin-top: 1em">As well as the
above values, <i>clockid</i> can be specified as the
<i>clockid</i> returned by a call to
<b>clock_getcpuclockid</b>(3) or
<b>pthread_getcpuclockid</b>(3).</p>
<p style="margin-left:11%; margin-top: 1em">The <i>sevp</i>
argument points to a <i>sigevent</i> structure that
specifies how the caller should be notified when the timer
expires. For the definition and general details of this
structure, see <b>sigevent</b>(7).</p>
<p style="margin-left:11%; margin-top: 1em">The
<i>sevp.sigev_notify</i> field can have the following
values: <b><br>
SIGEV_NONE</b></p>
<p style="margin-left:22%;">Don’t asynchronously
notify when the timer expires. Progress of the timer can be
monitored using <b>timer_gettime</b>(2).</p>
<p style="margin-left:11%;"><b>SIGEV_SIGNAL</b></p>
<p style="margin-left:22%;">Upon timer expiration, generate
the signal <i>sigev_signo</i> for the process. See
<b>sigevent</b>(7) for general details. The <i>si_code</i>
field of the <i>siginfo_t</i> structure will be set to
<b>SI_TIMER</b>. At any point in time, at most one signal is
queued to the process for a given timer; see
<b>timer_getoverrun</b>(2) for more details.</p>
<p style="margin-left:11%;"><b>SIGEV_THREAD</b></p>
<p style="margin-left:22%;">Upon timer expiration, invoke
<i>sigev_notify_function</i> as if it were the start
function of a new thread. See <b>sigevent</b>(7) for
details.</p>
<p style="margin-left:11%;"><b>SIGEV_THREAD_ID</b>
(Linux-specific)</p>
<p style="margin-left:22%;">As for <b>SIGEV_SIGNAL</b>, but
the signal is targeted at the thread whose ID is given in
<i>sigev_notify_thread_id</i>, which must be a thread in the
same process as the caller. The
<i>sigev_notify_thread_id</i> field specifies a kernel
thread ID, that is, the value returned by <b>clone</b>(2) or
<b>gettid</b>(2). This flag is intended only for use by
threading libraries.</p>
<p style="margin-left:11%; margin-top: 1em">Specifying
<i>sevp</i> as NULL is equivalent to specifying a pointer to
a <i>sigevent</i> structure in which <i>sigev_notify</i> is
<b>SIGEV_SIGNAL</b>, <i>sigev_signo</i> is <b>SIGALRM</b>,
and <i>sigev_value.sival_int</i> is the timer ID.</p>
<h2>RETURN VALUE
<a name="RETURN VALUE"></a>
</h2>
<p style="margin-left:11%; margin-top: 1em">On success,
<b>timer_create</b>() returns 0, and the ID of the new timer
is placed in <i>*timerid</i>. On failure, -1 is returned,
and <i>errno</i> is set to indicate the error.</p>
<h2>ERRORS
<a name="ERRORS"></a>
</h2>
<table width="100%" border="0" rules="none" frame="void"
cellspacing="0" cellpadding="0">
<tr valign="top" align="left">
<td width="11%"></td>
<td width="9%">
<p style="margin-top: 1em"><b>EAGAIN</b></p></td>
<td width="2%"></td>
<td width="78%">
<p style="margin-top: 1em">Temporary error during kernel
allocation of timer structures.</p></td></tr>
<tr valign="top" align="left">
<td width="11%"></td>
<td width="9%">
<p><b>EINVAL</b></p></td>
<td width="2%"></td>
<td width="78%">
<p>Clock ID, <i>sigev_notify</i>, <i>sigev_signo</i>, or
<i>sigev_notify_thread_id</i> is invalid.</p></td></tr>
<tr valign="top" align="left">
<td width="11%"></td>
<td width="9%">
<p><b>ENOMEM</b></p></td>
<td width="2%"></td>
<td width="78%">
<p>Could not allocate memory.</p></td></tr>
</table>
<h2>VERSIONS
<a name="VERSIONS"></a>
</h2>
<p style="margin-left:11%; margin-top: 1em">This system
call is available since Linux 2.6.</p>
<h2>CONFORMING TO
<a name="CONFORMING TO"></a>
</h2>
<p style="margin-left:11%; margin-top: 1em">POSIX.1-2001,
POSIX.1-2008.</p>
<h2>NOTES
<a name="NOTES"></a>
</h2>
<p style="margin-left:11%; margin-top: 1em">A program may
create multiple interval timers using
<b>timer_create</b>().</p>
<p style="margin-left:11%; margin-top: 1em">Timers are not
inherited by the child of a <b>fork</b>(2), and are disarmed
and deleted during an <b>execve</b>(2).</p>
<p style="margin-left:11%; margin-top: 1em">The kernel
preallocates a "queued real-time signal" for each
timer created using <b>timer_create</b>(). Consequently, the
number of timers is limited by the <b>RLIMIT_SIGPENDING</b>
resource limit (see <b>setrlimit</b>(2)).</p>
<p style="margin-left:11%; margin-top: 1em">The timers
created by <b>timer_create</b>() are commonly known as
"POSIX (interval) timers". The POSIX timers API
consists of the following interfaces:</p>
<table width="100%" border="0" rules="none" frame="void"
cellspacing="0" cellpadding="0">
<tr valign="top" align="left">
<td width="11%"></td>
<td width="1%">
<p style="margin-top: 1em">*</p></td>
<td width="3%"></td>
<td width="85%">
<p style="margin-top: 1em"><b>timer_create</b>(): Create a
timer.</p> </td></tr>
<tr valign="top" align="left">
<td width="11%"></td>
<td width="1%">
<p>*</p></td>
<td width="3%"></td>
<td width="85%">
<p><b>timer_settime</b>(2): Arm (start) or disarm (stop) a
timer.</p> </td></tr>
<tr valign="top" align="left">
<td width="11%"></td>
<td width="1%">
<p>*</p></td>
<td width="3%"></td>
<td width="85%">
<p><b>timer_gettime</b>(2): Fetch the time remaining until
the next expiration of a timer, along with the interval
setting of the timer.</p></td></tr>
<tr valign="top" align="left">
<td width="11%"></td>
<td width="1%">
<p>*</p></td>
<td width="3%"></td>
<td width="85%">
<p><b>timer_getoverrun</b>(2): Return the overrun count for
the last timer expiration.</p></td></tr>
<tr valign="top" align="left">
<td width="11%"></td>
<td width="1%">
<p>*</p></td>
<td width="3%"></td>
<td width="85%">
<p><b>timer_delete</b>(2): Disarm and delete a timer.</p></td></tr>
</table>
<p style="margin-left:11%; margin-top: 1em">Since Linux
3.10, the <i>/proc/[pid]/timers</i> file can be used to list
the POSIX timers for the process with PID <i>pid</i>. See
<b>proc</b>(5) for further information.</p>
<p style="margin-left:11%; margin-top: 1em">Since Linux
4.10, support for POSIX timers is a configurable option that
is enabled by default. Kernel support can be disabled via
the <b>CONFIG_POSIX_TIMERS</b> option.</p>
<p style="margin-left:11%; margin-top: 1em"><b>C
library/kernel differences</b> <br>
Part of the implementation of the POSIX timers API is
provided by glibc. In particular:</p>
<table width="100%" border="0" rules="none" frame="void"
cellspacing="0" cellpadding="0">
<tr valign="top" align="left">
<td width="11%"></td>
<td width="1%">
<p style="margin-top: 1em">*</p></td>
<td width="3%"></td>
<td width="85%">
<p style="margin-top: 1em">Much of the functionality for
<b>SIGEV_THREAD</b> is implemented within glibc, rather than
the kernel. (This is necessarily so, since the thread
involved in handling the notification is one that must be
managed by the C library POSIX threads implementation.)
Although the notification delivered to the process is via a
thread, internally the NPTL implementation uses a
<i>sigev_notify</i> value of <b>SIGEV_THREAD_ID</b> along
with a real-time signal that is reserved by the
implementation (see <b>nptl</b>(7)).</p></td></tr>
<tr valign="top" align="left">
<td width="11%"></td>
<td width="1%">
<p>*</p></td>
<td width="3%"></td>
<td width="85%">
<p>The implementation of the default case where <i>evp</i>
is NULL is handled inside glibc, which invokes the
underlying system call with a suitably populated
<i>sigevent</i> structure.</p></td></tr>
<tr valign="top" align="left">
<td width="11%"></td>
<td width="1%">
<p>*</p></td>
<td width="3%"></td>
<td width="85%">
<p>The timer IDs presented at user level are maintained by
glibc, which maps these IDs to the timer IDs employed by the
kernel.</p> </td></tr>
</table>
<p style="margin-left:11%; margin-top: 1em">The POSIX
timers system calls first appeared in Linux 2.6. Prior to
this, glibc provided an incomplete user-space implementation
(<b>CLOCK_REALTIME</b> timers only) using POSIX threads, and
in glibc versions before 2.17, the implementation falls back
to this technique on systems running pre-2.6 Linux
kernels.</p>
<h2>EXAMPLE
<a name="EXAMPLE"></a>
</h2>
<p style="margin-left:11%; margin-top: 1em">The program
below takes two arguments: a sleep period in seconds, and a
timer frequency in nanoseconds. The program establishes a
handler for the signal it uses for the timer, blocks that
signal, creates and arms a timer that expires with the given
frequency, sleeps for the specified number of seconds, and
then unblocks the timer signal. Assuming that the timer
expired at least once while the program slept, the signal
handler will be invoked, and the handler displays some
information about the timer notification. The program
terminates after one invocation of the signal handler.</p>
<p style="margin-left:11%; margin-top: 1em">In the
following example run, the program sleeps for 1 second,
after creating a timer that has a frequency of 100
nanoseconds. By the time the signal is unblocked and
delivered, there have been around ten million overruns.</p>
<p style="margin-left:17%; margin-top: 1em">$ <b>./a.out 1
100</b> <br>
Establishing handler for signal 34 <br>
Blocking signal 34 <br>
timer ID is 0x804c008 <br>
Sleeping for 1 seconds <br>
Unblocking signal 34 <br>
Caught signal 34 <br>
sival_ptr = 0xbfb174f4; *sival_ptr = 0x804c008 <br>
overrun count = 10004886</p>
<p style="margin-left:11%; margin-top: 1em"><b>Program
source</b> <br>
#include <stdlib.h> <br>
#include <unistd.h> <br>
#include <stdio.h> <br>
#include <signal.h> <br>
#include <time.h></p>
<p style="margin-left:11%; margin-top: 1em">#define CLOCKID
CLOCK_REALTIME <br>
#define SIG SIGRTMIN</p>
<p style="margin-left:11%; margin-top: 1em">#define
errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ <br>
} while (0)</p>
<p style="margin-left:11%; margin-top: 1em">static void
<br>
print_siginfo(siginfo_t *si) <br>
{ <br>
timer_t *tidp; <br>
int or;</p>
<p style="margin-left:11%; margin-top: 1em">tidp =
si->si_value.sival_ptr;</p>
<p style="margin-left:11%; margin-top: 1em">printf("
sival_ptr = %p; ", si->si_value.sival_ptr); <br>
printf(" *sival_ptr = 0x%lx\n", (long) *tidp);</p>
<p style="margin-left:11%; margin-top: 1em">or =
timer_getoverrun(*tidp); <br>
if (or == -1) <br>
errExit("timer_getoverrun"); <br>
else <br>
printf(" overrun count = %d\n", or); <br>
}</p>
<p style="margin-left:11%; margin-top: 1em">static void
<br>
handler(int sig, siginfo_t *si, void *uc) <br>
{ <br>
/* Note: calling printf() from a signal handler is not safe
<br>
(and should not be done in production programs), since <br>
printf() is not async-signal-safe; see signal-safety(7).
<br>
Nevertheless, we use printf() here as a simple way of <br>
showing that the handler was called. */</p>
<p style="margin-left:11%; margin-top: 1em">printf("Caught
signal %d\n", sig); <br>
print_siginfo(si); <br>
signal(sig, SIG_IGN); <br>
}</p>
<p style="margin-left:11%; margin-top: 1em">int <br>
main(int argc, char *argv[]) <br>
{ <br>
timer_t timerid; <br>
struct sigevent sev; <br>
struct itimerspec its; <br>
long long freq_nanosecs; <br>
sigset_t mask; <br>
struct sigaction sa;</p>
<p style="margin-left:11%; margin-top: 1em">if (argc != 3)
{ <br>
fprintf(stderr, "Usage: %s <sleep-secs>
<freq-nanosecs>\n", <br>
argv[0]); <br>
exit(EXIT_FAILURE); <br>
}</p>
<p style="margin-left:11%; margin-top: 1em">/* Establish
handler for timer signal */</p>
<p style="margin-left:11%; margin-top: 1em">printf("Establishing
handler for signal %d\n", SIG); <br>
sa.sa_flags = SA_SIGINFO; <br>
sa.sa_sigaction = handler; <br>
sigemptyset(&sa.sa_mask); <br>
if (sigaction(SIG, &sa, NULL) == -1) <br>
errExit("sigaction");</p>
<p style="margin-left:11%; margin-top: 1em">/* Block timer
signal temporarily */</p>
<p style="margin-left:11%; margin-top: 1em">printf("Blocking
signal %d\n", SIG); <br>
sigemptyset(&mask); <br>
sigaddset(&mask, SIG); <br>
if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) <br>
errExit("sigprocmask");</p>
<p style="margin-left:11%; margin-top: 1em">/* Create the
timer */</p>
<p style="margin-left:11%; margin-top: 1em">sev.sigev_notify
= SIGEV_SIGNAL; <br>
sev.sigev_signo = SIG; <br>
sev.sigev_value.sival_ptr = &timerid; <br>
if (timer_create(CLOCKID, &sev, &timerid) == -1)
<br>
errExit("timer_create");</p>
<p style="margin-left:11%; margin-top: 1em">printf("timer
ID is 0x%lx\n", (long) timerid);</p>
<p style="margin-left:11%; margin-top: 1em">/* Start the
timer */</p>
<p style="margin-left:11%; margin-top: 1em">freq_nanosecs =
atoll(argv[2]); <br>
its.it_value.tv_sec = freq_nanosecs / 1000000000; <br>
its.it_value.tv_nsec = freq_nanosecs % 1000000000; <br>
its.it_interval.tv_sec = its.it_value.tv_sec; <br>
its.it_interval.tv_nsec = its.it_value.tv_nsec;</p>
<p style="margin-left:11%; margin-top: 1em">if
(timer_settime(timerid, 0, &its, NULL) == -1) <br>
errExit("timer_settime");</p>
<p style="margin-left:11%; margin-top: 1em">/* Sleep for a
while; meanwhile, the timer may expire <br>
multiple times */</p>
<p style="margin-left:11%; margin-top: 1em">printf("Sleeping
for %d seconds\n", atoi(argv[1])); <br>
sleep(atoi(argv[1]));</p>
<p style="margin-left:11%; margin-top: 1em">/* Unlock the
timer signal, so that timer notification <br>
can be delivered */</p>
<p style="margin-left:11%; margin-top: 1em">printf("Unblocking
signal %d\n", SIG); <br>
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) <br>
errExit("sigprocmask");</p>
<p style="margin-left:11%; margin-top: 1em">exit(EXIT_SUCCESS);
<br>
}</p>
<h2>SEE ALSO
<a name="SEE ALSO"></a>
</h2>
<p style="margin-left:11%; margin-top: 1em"><b>clock_gettime</b>(2),
<b>setitimer</b>(2), <b>timer_delete</b>(2),
<b>timer_getoverrun</b>(2), <b>timer_settime</b>(2),
<b>timerfd_create</b>(2), <b>clock_getcpuclockid</b>(3),
<b>pthread_getcpuclockid</b>(3), <b>pthreads</b>(7),
<b>sigevent</b>(7), <b>signal</b>(7), <b>time</b>(7)</p>
<h2>COLOPHON
<a name="COLOPHON"></a>
</h2>
<p style="margin-left:11%; margin-top: 1em">This page is
part of release 5.02 of the Linux <i>man-pages</i> project.
A description of the project, information about reporting
bugs, and the latest version of this page, can be found at
https://www.kernel.org/doc/man-pages/.</p>
<hr>
</body>
</html>