1md_docs_job-safety(3)               dirsrv               md_docs_job-safety(3)
2
3
4

NAME

6       md_docs_job-safety - Nunc Stans Job Safety Nunc Stans 0.2.0 comes with
7       many improvements for job safety. Most consumers of this framework will
8       not notice the difference if they are using it 'correctly', but in
9       other cases, you may find you have error conditions.
10
11       Jobs now flow through a set of states in their lifetime.
12
13   States
14       · WAITING: This represents a job that is idle, and not owned by a
15         worker or event thread. Any thread can alter this job.
16
17       · NEEDS_DELETE: This represents a job that is marked for deletion. It
18         cannot be accessed again!
19
20       · DELETED: This represents a job that is deleted. In theory, you can
21         never access a job in this state.
22
23       · NEEDS_ARM: This is a job that is about to be placed into the event or
24         work queue for arming, but has not yet been queued.
25
26       · ARMED: This is a job that is currently in the event queue or work
27         queue waiting to be executed.
28
29       · RUNNING: This is a job that is in the process of executing it's
30         callback right now.
31
32   Diagram
33   WAITING
34       All jobs start in the WAITING state. At this point, the job can have
35       two transitions. It is sent to ns_job_done, and marked as NEEDS_DELETE,
36       or it can be sent to ns_job_rearm, and marked as NEEDS_ARM. A job that
37       is WAITING can be safely modify with ns_job_set_* and accessed with
38       ns_job_get_* from any thread.
39
40   NEEDS_ARM
41       Once a job is in the NEEDS_ARM state, it can not be altered by
42       ns_job_set_*. It can be read from with ns_job_get_*. It can be sent to
43       ns_job_done (which moves to NEEDS_DELETE), but generally this is only
44       from within the job callback, with code like the following.
45
46       callback(ns_job_t *job) {
47           ns_job_rearm(job);
48           ns_job_done(job);
49       }
50
51
52       NEEDS_ARM in most cases will quickly move to the next state, ARMED
53
54   ARMED
55       In the ARMED state, this means that the job has been sucessfully queued
56       into the event or work queue. In the ARMED state, the job can be read
57       from with ns_job_get_*, but it cannot be altered with ns_job_set_*. If
58       a job could be altered while queued, this could cause issues with the
59       intent of what the job should do (set_data, set_cb, set_done_cb) etc.
60
61       A job that is ARMED and queued can NOT be removed from the queue, or
62       stopped from running. This is a point of no return!
63
64   RUNNING
65       In the RUNNING state, the job is in the process of executing the
66       callback that the job contains. While RUNNING, the thread that is
67       executing the callback may call ns_job_done, ns_job_rearm, ns_job_get_*
68       and ns_job_set_* upon the job. Note, that calling both ns_job_done and
69       ns_job_rearm from the callback, as the 'done' is a 'stronger' action we
70       will delete the job even though rearm was also called.
71
72       While RUNNING other threads (ie, not the worker thread executing the
73       callback) may only call ns_job_get_* upon the job. Due to the design of
74       the synchronisation underneath, this will block until the execution of
75       the callback, so for all intents and purposes by the time the external
76       thread is able to call ns_job_get_*, the job will have moved to
77       NEEDS_DELETE, NEEDS_ARM or WAITING.
78
79   NEEDS_DELETE
80       When you call ns_job_done, this marks the job as NEEDS_DELETE. The
81       deletion actually occurs at 'some later point'. When a job is set to
82       NEEDS_DELETE, you may not call any of the ns_job_get_* and ns_job_set_*
83       functions on the job.
84
85   DELETED
86       This state only exists on the job briefly. This means we are in the
87       process of deleting the job internally. We execute the ns_job_done_cb
88       at this point, so that the user may clean up and free any data as
89       required. Only the ns_job_done_cb thread may access the job at this
90       point.
91
92   Putting it all together
93       This state machine encourages certain types of work flows with jobs.
94       This is because the current states are opaque to the caller, and are
95       enforced inside of nunc-stans. The most obviously side effect of a
96       state machine violation is a ASSERT failure with -DDEBUG, or PR_FAILURE
97       from get()/set(). This encourages certain practices:
98
99       · Only single threads should be accessing jobs. This prevents races and
100         sync issues.
101
102       · Data and variables should exist in a single job. Avoid shared (heap)
103         memory locations!
104
105       · Changing jobs should only happen from within the callback, as you can
106         guarantee a consistent state without needing to spin/block on
107         ns_job_set_*.
108
109       · You may not need mutexes on your data or thread locals, as the job
110         provides the correct cpu synchronisation guarantees. Consider that
111         each job takes a 'root' data node, then all other allocated variables
112         are referenced there only by the single thread. You can now dispose
113         of mutexes, as the job will guarantee the synchronisation of this
114         data.
115
116       · Jobs work well if stack variables are used inside the callback
117         functions, rather than heap.
118
119       Some work flows that don't work well here:
120
121       · Having threads alter in-flight jobs. This causes race conditions and
122         inconsistencies.
123
124       · Sharing heap data via pointers in jobs. This means you need a mutex
125         on the data, which causes a serialisation point: Why bother with
126         thread pools if you are just going to serialise on some data points
127         anyway!
128
129       · Modifying jobs and what they handle. Don't do it! Just ns_job_done on
130         the job, and create a new one that matches what you want to do.
131
132       · Map reduce: Nunc-Stans doesn't provide a good way to aggregate data
133         on the return, IE reduce. You may need to provide a queue or some
134         other method to reduce if you were interested in this.
135
136   Examples
137       Inside of the nunc-stans project, the tests/cmocka/stress_test.c code
138       is a good example of a socket server and socket client using nunc-stans
139       that adheres to these principles.
140
141
142
143Version 1.4.2.5                 Mon Dec 9 2019           md_docs_job-safety(3)
Impressum