-
Notifications
You must be signed in to change notification settings - Fork 1
/
TODO
106 lines (72 loc) · 3.95 KB
/
TODO
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
* TODO
- Return void for functions that always succeed.
This would simplify error handling.
- Write a test case that checks if pthread_spin_unlock from a
different thread works fine.
- Rename libtask_task_execute to libtask_task_resume
* DONE
- We need the ability to assign threads to task-pool and remove them.
This would allow us to make threads wait for-ever even when there
are no tasks in the task-pool.
Proposed interface is:
error_t task_pool_start(task_pool_t *pool, uint32_t *idp);
error_t task_pool_stop(task_pool_t *pool, uint32_t id);
These methods can be invoked from any context by any thread except
the thread that is supposed to quit the task-pool. When stop method
returns, thread may still be executing its last task from the
task-pool. Other mechanisms should be used to signal existing from
the task-pool.
- Define libtask_spinlock_t interface
Because pthread_spinlock_t behavior is undefined when unlocking
thread is different from the calling thread.
Also, make sure spin_lock and spin_unlock methods don't return an
error value. Otherwise, error handling becomes tedious and handling
spin_unlock failure when spin_lock succeeds is never obvious.
- Introduce wait queues where threads can sleep and woken up.
Wait queues will be the underlying mechanism for blocking tasks for
synchronization and events.
- Remove busy loop in libtask_task_pool_execute.
The "schedule" invocation should wake up threads waiting in the
"execute" function.
- Task pool should have "schedule" function.
The task-pool interface must be simple. It shouldn't expose too
verbose public API. It will make changes to the library difficult
because user code may break.
Lets define a "schedule" function that takes care of adding a task
into a task-pool and adding runnable task into the waiting
list. This change makes the "insert/erase/push_back/pop_front"
functions private.
Also, having higher level interface gives us more room to optmize
the underlying implementation.
- Make tasks belong to a task-pool for entire life-time.
We expect tasks to be created for performing long running
actions/requests involving multiple cpu and io operations and their
priorities, etc. to be defined at the task-pool level. So, it is
important to have the ability to inspect all tasks of a subsystem
through its task-pool for debugging, reporting and analysis.
Note that depending on the steps involved in completing, a task may
migrate between different task-pools waiting for execution. Such
tasks are still part of its originating task-pool even though they
currently may be executed in a different task-pool context.
The "task_list" in the task-pool and the "originating_pool_link" in
task are used to maintain this relation between the tasks and the
task-pools.
- Add a private interface to get the current task pool.
Since tasks are always tied to a task-pool, if a _current_ task
wants to switch to another task-pool, it has to store the current
task-pool in its stack so that it can come back to it later. This is
crucial for implementing asynchronous operations.
The "waiting_link" member of the task structure cannot be used for
this purpose because "waiting_link" is not guaranteed to link only
to the task-pools (mutexes, semaphres, sleep etc. may use it)
When current task_pool is returned, no reference is taken on the
task-pool. Since this is a private interface, we are expected to
handle this as necessary.
- Task pool should have "execute" function.
It is unnecessary to implement the task-pool execution loop in every
test case. Having this method as part of the library simplifies the
testcases. Also, this makes using libtask library less error prone.
- Every task should have a owner task-pool.
Supporting tasks without an associated task-pool is not a frequent
case. Besides, creating a task-pool and adding a task to it doesn't
cost anything, so lets drop support for independent tasks.