TIMER_CREATE(3P)
π TIMER_CREATE(3P) β a.k.a. "how to make a timer, bestie" π
okay so real quick before we even start: this page lives in the POSIX Programmer's Manual, and it's the β¨ official β¨ spec version of things. Heads up though β the Linux implementation of this interface may differ (so like, go check the corresponding Linux manual page for the actual Linux tea), or the interface might not even be implemented on Linux at all. π Not me delivering bad news in the first paragraph.
π«Ά PROLOG π«Ά
This manual page is part of the POSIX Programmer's Manual. The Linux implementation of this interface may differ (consult the corresponding Linux manual page for details of Linux behavior), or the interface may not be implemented on Linux.
πΈ NAME πΈ
timer_create β create a per-process timer
β¨ SYNOPSIS β¨
#include <signal.h>
#include <time.h>
int timer_create(clockid_t clockid, struct sigevent *restrict evp,
timer_t *restrict timerid);
π DESCRIPTION π
okay so timer_create() creates a per-process timer, and the timing base is whatever clock you hand it in clock_id. Periodt. Then it hands you back a timer ID of type timer_t in the place timerid points at, and that ID is literally how you'll refer to this timer in every future timer request. It stays unique within the calling process until the timer gets deleted β no duplicates, we don't do that here. The clock itself, clock_id, is defined in <time.h>. And the timer you just got? It comes out disarmed. Like, it exists but it's not doing anything yet. Asleep. Beauty rest. π΄
Now, the evp argument β if it's not NULL, it points at a sigevent structure. You (the app) allocate that structure, and it defines the async notification that fires when the timer expires, exactly as laid out in Section 2.4.1, Signal Generation and Delivery. If evp is NULL though? It's as if evp pointed to a sigevent structure where the sigev_notify member has the value SIGEV_SIGNAL, the sigev_signo has a default signal number, and the sigev_value member has the value of the timer ID. So like, defaults, but make them β¨vibesβ¨.
Every implementation defines its own little set of clocks usable as timing bases for per-process timers. But all implementations shall support a clock_id of CLOCK_REALTIME β that one's non-negotiable. And if the Monotonic Clock option is supported, implementations shall support a clock_id of CLOCK_MONOTONIC. slay.
Per-process timers do not get inherited by a child process across a fork(), and they get disarmed and deleted by an exec. So no, your timer is not coming with you, it's not packing a bag. π
If _POSIX_CPUTIME is defined, implementations shall support clock_id values representing the CPU-time clock of the calling process.
If _POSIX_THREAD_CPUTIME is defined, implementations shall support clock_id values representing the CPU-time clock of the calling thread.
Now here's a lil implementation-defined moment for you: whether a timer_create() call will succeed if the clock_id corresponds to the CPU-time clock of a process or thread that's different from the process or thread invoking the function. It's just, like, up to the implementation. shrug.
And one more thing that is genuinely important: if evp->sigev_sigev_notify is SIGEV_THREAD and sev->sigev_notify_attributes is not NULL, and if the attribute pointed to by sev->sigev_notify_attributes has a thread stack address specified by a call to pthread_attr_setstack(), then the results are unspecified if the signal is generated more than once. Read that twice, bestie. Not me being dramatic β that's just what it says.
π RETURN VALUE π
If it works? timer_create() returns zero and updates the location timerid points to with a timer_t, which you can then pass to the per-process timer calls. If something goes wrong, it returns -1 and sets errno to tell you what happened. And important: the value of timerid is undefined if an error occurs. So don't go reading it like it means something. It doesn't. π
π₯ ERRORS π₯
The timer_create() function shall fail if:
EAGAINβ the system lacks sufficient signal queuing resources to honor the request. (rip, no room at the inn)EAGAINβ the calling process has already created all of the timers it is allowed by this implementation. (you hit your limit, babe, that's a you problem and also a system limit)EINVALβ the specified clock ID is not defined. (that clock doesn't exist, we made it up)ENOTSUPβ the implementation does not support the creation of a timer attached to the CPU-time clock that is specified byclock_idand associated with a process or thread different from the process or thread invokingtimer_create().
The following sections are informative. (translation: the β¨loreβ¨ is over, this is bonus content)
π EXAMPLES π
None. (literally none. the well is dry. moving on π)
π¦ APPLICATION USAGE π¦
So if you create a timer where evp->sigev_sigev_notify is set to SIGEV_THREAD, and the attribute pointed to by evp->sigev_notify_attributes has a thread stack address specified by a call to pthread_attr_setstack(), then the memory dedicated as a thread stack cannot be recovered. Like, it's gone. It's not coming back. πͺ¦
Why tho? Because the threads created in response to a timer expiration are created detached β or in an unspecified way if the thread attribute's detachstate is PTHREAD_CREATE_JOINABLE. And in neither case is it valid to call pthread_join(). Which means it's impossible to determine the lifetime of the created thread, which means the stack memory cannot be reused. That's the whole chain of consequences. That's the tea. π΅
π RATIONALE π
π§ Periodic Timer Overrun and Resource Allocation π§
The specified timer facilities may deliver realtime signals (that is, queued signals) on implementations that support this option. And since realtime applications cannot afford to lose notifications of asynchronous events β like timer expirations or asynchronous I/O completions β it has to be possible to make sure sufficient resources exist to actually deliver the signal when the event happens. In general this isn't a big deal, because there's a one-to-one correspondence between a request and a subsequent signal generation. If the request can't allocate the signal delivery resources, it can just fail the call with an [EAGAIN] error. Easy.
Periodic timers, though? Special case, bestie. A single request can generate an unspecified number of signals. That's fine if the requesting process can service the signals as fast as they're generated β then the signal delivery resources free up for the next periodic timer expiration signal. But in general, that cannot be assured. Processing of periodic timer signals may ``overrun'' β meaning subsequent periodic timer expirations can occur before the currently pending signal has even been delivered. π
Also, for signals, according to the POSIX.1β1990 standard, if subsequent occurrences of a pending signal are generated, it is implementation-defined whether a signal is delivered for each occurrence. And that's just not adequate for some realtime applications. So a mechanism is required that lets applications detect how many timer expirations were delayed β without requiring an indefinite amount of system resources to store the delayed expirations.
And that's where the overrun count comes in. The overrun count is defined as the number of extra timer expirations that occurred between the time a timer expiration signal is generated and the time the signal is delivered. The signal-catching function, if it cares about overruns, can retrieve this count on entry. With this method, a periodic timer only needs one ``signal queuing resource'' β and it can be allocated at the time of the timer_create() function call. One. Iconic. π
A function is defined to retrieve the overrun count so that an application doesn't have to allocate static storage for it, and an implementation doesn't have to update that storage asynchronously on timer expirations. But for some high-frequency periodic applications, the overhead of an additional system call on each timer expiration may be prohibitive. So the functions, as defined, permit an implementation to maintain the overrun count in user space, associated with the timerid. Then timer_getoverrun() can be implemented as a macro that uses the timerid argument (which may just be a pointer to a user space structure containing the counter) to locate the overrun count with no system call overhead. Other implementations, less concerned with this class of applications, can avoid the asynchronous update of user space by maintaining the count in a system structure β at the cost of the extra system call to obtain it. Trade-offs, babes. βοΈ
πΈ Timer Expiration Signal Parameters πΈ
The Realtime Signals Extension option supports an application-specific datum that gets delivered to the extended signal handler. This value is explicitly specified by the application, along with the signal number to be delivered, in a sigevent structure. The type of the application-defined value can be either an integer constant or a pointer. And the reason we explicitly specify the value β as opposed to always just sending the timer ID β is that it was selected based on existing practice.
It's common practice for realtime applications (on non-POSIX systems or realtime extended POSIX systems) to use the parameters of event handlers as the case label of a switch statement, or as a pointer to an application-defined data structure. But since timer_ids are dynamically allocated by the timer_create() function, they can't be used for either of those things without additional application overhead in the signal handler β like, for example, searching an array of saved timer IDs to associate the ID with a constant or application data structure. And who has the time. β° (the timer does. the timer has the time.)
β FUTURE DIRECTIONS β
None.
π SEE ALSO π
clock_getres()timer_delete()timer_getoverrun()
The Base Definitions volume of POSIX.1β2017: <signal.h>, <time.h>
π COPYRIGHT π
Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1-2017, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 7, 2018 Edition, Copyright (C) 2018 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .
Any typographical or formatting errors that appear in this page are most likely to have been introduced during the conversion of the source files to man page format. To report such errors, see https://www.kernel.org/doc/man-pages/reporting_bugs.html .
okay that's the whole page, bestie, you made it to the end π«Ά this edition came to you courtesy of IEEE/The Open Group, 2017 β the TIMER_CREATE(3P) moment, no cap. now go forth and arm some timers responsibly. β¨ππ
π¦ where this page comes from
- alpine 3.22: man-pages-posix 2017a-r0 Β· custom
- alpine 3.23: man-pages-posix 2017a-r0 Β· custom
- alpine 3.24: man-pages-posix 2017a-r0 Β· custom
- arch rolling: man-pages 6.19-1
- arch rolling: man-pages 6.20-1 Β· BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages-posix 2017a
- opensuse-leap 16.0: man-pages-posix 2017a-160000.4.1 Β· SUSE-IEEE
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms