1ggAddTask(3) GGI ggAddTask(3)
2
3
4
6 ggAddTask, ggDelTask, ggTimeBase, GG_SCHED_TICKS2USECS,
7 GG_SCHED_USECS2TICKS : LibGG simple task scheduler routines
8
10 #include <ggi/gg.h>
11
12 struct gg_task {
13 gg_task_callback_fn *cb; /* Function to call to run task */
14 void *hook; /* Task data can be hung here */
15 int pticks; /* Run once every pticks ticks. */
16 int ncalls; /* Run ncalls times (0 = infinite) */
17 int lasttick; /* last tick run (read-only) */
18
19 /* Other members present but are for internal use only. */
20 };
21
22 typedef int (gg_task_callback_fn)(struct gg_task *task);
23
24 GG_SCHED_TICKS2USECS(uint32_t ticks);
25 GG_SCHED_USECS2TICKS(uint32_t usecs);
26
27 uint32_t ggTimeBase(void);
28
29 int ggAddTask(struct gg_task *task);
30
31 int ggDelTask(struct gg_task *task);
32
33
35 LibGG implements a task scheduler in both threaded and non-threaded
36 environments. Tasks can be registered with the scheduler to run short,
37 asynchronous routines called "handlers" which may interrupt or run in
38 parallel with the normal flow-of-control. It is recommended to use
39 LibGG tasks in lieue of threads when writing for maximum portability,
40 if they can meet the demands of the application, since not all environ‐
41 ments support threads.
42
43 The LibGG task scheduler uses a unit of time called a "tick", which may
44 vary between architectures. The tick is guaranteed to be no more than
45 one second, however, most environments will support at least 60 ticks
46 per second. By default LibGG will select 60 ticks per second if it is
47 supported, see below for instructions on modifying this behavior. The
48 function ggTimeBase is used to find out the size of a tick.
49
50 GG_SCHED_TICKS2USECS and GG_SCHED_USECS2TICKS are convenient macros
51 that simplifies conversion between ticks and microseconds and vice
52 versa.
53
54 The maximum rate at which a periodic task may run is once per tick.
55 The maximum period (minimum rate) of a LibGG task is the value of the
56 macro GG_SCHED_TICK_WRAP minus one, and is also measured in ticks.
57
58 ggAddTask will examine the values in the offered task control structure
59 task. Before calling ggAddTask the task control structure must be ini‐
60 tialized by filling it with zeros, including the internal-use-only
61 area. The task control structure should be further initialized by pro‐
62 viding at least a pointer to a callback handler function in the member
63 cb, and initializing the pticks member to contain the number of ticks
64 between each call to the handler function. The ncalls member may be
65 left at zero, in which case the task remains scheduled to run once
66 every pticks until explicitly deleted, or it may be set to a positive
67 integer to indicate that the task should be automatically deleted after
68 the handler has been called ncalls times. The int return type on the
69 callback hook is only there for possible future expansion. For now
70 callbacks should always return 0. Other values are undefined.
71
72 The task control structure must only be used for one task, however a
73 task handler may be called by multiple tasks. The member hook is pro‐
74 vided for the application's use in the task control structure as a
75 means to easily transport task-local data to the handler. If a tick
76 arrives during a call to ggAddTask, the handler may be invoked before
77 ggAddTask returns; A memory barrier is included in ggAddTask which
78 ensures that all values in the task control structure are up to date on
79 multiprocessor systems even in this case. The task control structure
80 should not be altered, except by a task handler as noted below, while
81 the task is scheduled.
82
83 ggDelTask will remove a task from the scheduler. The task may be
84 called after ggDelTask is called, but is guaranteed not to be called
85 after ggDelTask has returned, until such a point as it is added again
86 with ggAddTask.
87
88 A task can be put to sleep for a certain amount of time in microseconds
89 by altering the period of the task to the correct number of ticks, and
90 then that task itself can reset it's period back based on a value in
91 it's private hook when it next runs.
92
93 A task can wait for an other task to finish either by writing code to
94 poll the other task's flags, or by writing a callback into the latter
95 task when it is done to reschedule a list of waiting tasks. How a task
96 terminates is entirely up to the author.
97
98 Each scheduled task is guaranteed never to be reentered by the sched‐
99 uler. That is, only one call to a task handler for a given task con‐
100 trol structure will be run at a time, though a single handler function
101 that handles more than one task control structure may be entered simul‐
102 taneously once per structure.
103
104 When a task executes, the handler is invoked and the parameter task
105 given to the handler contains the same pointer value as was given to
106 ggAddTask. The ncalls member will be updated to contain the number of
107 calls, including the current call, which remain before the task is
108 automatically deleted (or zero if the task will never be automatically
109 deleted.) Thus it is safe to call ggAddTask again to reuse the task
110 control structure once the handler has returned with ncalls equal to 1.
111 The lasttick member will contain the number of the LibGG scheduler tick
112 being executed, which should increase monotonically unless a problem
113 occurs as noted below, wrapping around modulus the value
114 GG_SCHED_TICK_WRAP.
115
116 ggAddTask and ggDelTask may not be called from within a task handler,
117 however, the task handler is free to alter the pticks and ncalls mem‐
118 bers in the task control structure task in order to change its period,
119 or increase or decrease the number of calls before auto-deletion. For
120 example, to cancel itself, a task need only set ncalls to 1 before
121 returning. The task handler may also change it's callback function or
122 data hook members. A write memory barrier is included in the scheduler
123 to prevent old values from being seen by other processors on SMP sys‐
124 tems.
125
126 LibGG ticks are measured in real (wall clock) time and LibGG makes
127 every effort to ensure that drift due to runtime factors is kept at a
128 minimum. When a process is suspended, however, LibGG ticks stop and
129 resume where they left off. Likewise, when system utilization is very
130 high or tasks are misused the LibGG scheduler may fail to count ticks.
131 However the ggCurTime(3) function will still be accurate in these cases
132 and can be used to detect such situations.
133
134 All scheduled LibGG tasks may in the worst case have to be run serial‐
135 ized, and may be postponed slightly while a call to ggAddTask or
136 ggDelTask is in progress, so there may be some delay between the start
137 of a LibGG tick and the actual execution of the task. This can be min‐
138 imized by limiting the duties of task handlers to very short, quick
139 operations.
140
141 When utilization is high or tasks misbehave, the scheduler may elect
142 simply not to call a task handler even though it is scheduled to be
143 called on a given tick. This may happen either to all tasks or to
144 select individual tasks. The "lasttick" member of the task control
145 structure can be safely read from within a task handler in order to
146 detect such a circumstance (it will always contain the current tick,
147 but can be compared to a previously stored value.)
148
149 Since LibGG tasks may be called in a signal handler or other non-inter‐
150 ruptible context, they should not call ggLock(3) on any locks that may
151 already be locked. In addition, there may be limits imposed on the
152 functions which are safe to use inside task handlers (that is, only
153 reentrant functions may be safe.) More detailed information on using
154 locks inside LibGG task handlers is contained in the manpage for
155 ggLock(3).
156
157 Scheduled tasks will be canceled, in a somewhat precarious fashion, by
158 a normal call to ggExit(3). As such, it is considered best practice to
159 use ggDelTask to cancel tasks when gracefully deinitializing LibGG or a
160 library that uses LibGG.
161
163 ggAddTask returns GGI_OK on success or:
164
165 · GGI_EARGREQ if called with NULL argument;
166
167 · GGI_EARGINVAL if the task is incorrectly set;
168
169 · GGI_EBUSY if the task is already added;
170
171 · GGI_ENOMEM if the task lock could not be created.
172
173 ggDelTask returns GGI_OK on success or:
174
175 · GGI_EARGREQ if called with NULL argument;
176
177 · GGI_EARGINVAL if the task is not currently scheduled.
178
179 ggTimeBase returns an integer between 1 and 1000000, inclusive, which
180 represents the number on microseconds between each tick of the LibGG
181 scheduler.
182
184 If the "-schedhz=speed" option is present in the GG_OPTS environment
185 variable when ggInit is first called, the scheduler time base will be
186 set such that the scheduler executes speed ticks per second. If this
187 is not possible, ggInit(3) will fail. The default speed is 60HZ, or
188 the maximum that the environment can support, whichever is less.
189
190 If the "-signum=n" option is present in the GG_OPTS environment vari‐
191 able when ggInit is first called, and LibGG is not compiled with
192 threads support, the UNIX signal used by the scheduler may be selected.
193 If n is not a valid signal for this purpose, the results are undefined,
194 but should not be unsafe for SUID processes. The default signal used
195 is usually SIGPROF, but may be chosen differently based on the needs of
196 the package maintainer for any particular LibGG distribution. Applica‐
197 tions using LibGG are forbidden from using this signal for other pur‐
198 poses, whether or not tasks are used.
199
200 If the "-schedthreads=numthreads" option is present in the GG_OPTS
201 environment variable when ggInit is first called, and LibGG is compiled
202 with threading support, the scheduler will create numthreads additional
203 threads to call task handlers. The default is one additional thread.
204 If numthreads is not valid or causes resource allocation problems, the
205 results are undefined, but should not be unsafe for SUID (or other ele‐
206 vated privilege) processes.
207
208
209
210libgg-1.0.x 2005-08-26 ggAddTask(3)