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
|
$NetBSD: patch-lib_thread.c,v 1.1 2019/09/30 08:57:49 kardel Exp $
- add fast check on prev/next pointer invariants
- add check to detect inserting of a thread already in a list
- add check to detect deletion of a thread not in a list
- ignore cancellation requests for the currently running thread (fixes crash)
- fix setting of prey/next pointers on adjecant elements when a head/tail element is
deleted
--- lib/thread.c.orig 2018-02-19 21:24:55.000000000 +0000
+++ lib/thread.c
@@ -531,6 +531,10 @@ thread_master_create ()
return NULL;
}
+ rv->ready.name = "ready";
+ rv->event.name = "event";
+ rv->unuse.name = "unuse";
+
rv->fd_limit = (int)limit.rlim_cur;
rv->read = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit);
if (rv->read == NULL)
@@ -560,6 +564,11 @@ thread_master_create ()
static void
thread_list_add (struct thread_list *list, struct thread *thread)
{
+ if (thread->list) {
+ zlog_err("%s:%d: thread_list_add INCONSISTENCY thread %p is already linked in list %s", __FILE__, __LINE__, thread, thread->list->name);
+ assert(!thread->list);
+ }
+
thread->next = NULL;
thread->prev = list->tail;
if (list->tail)
@@ -568,22 +577,57 @@ thread_list_add (struct thread_list *lis
list->head = thread;
list->tail = thread;
list->count++;
+ thread->list = list;
}
/* Delete a thread from the list. */
static struct thread *
thread_list_delete (struct thread_list *list, struct thread *thread)
{
+ if (!thread->list) {
+ zlog_err("%s:%d: thread_list_delete INCONSISTENCY thread %p is NOT linked in a list", __FILE__, __LINE__, thread);
+ assert(thread->list);
+ }
+
+ if (thread->list && thread->list != list) {
+ zlog_err("%s:%d: thread_list_delete INCONSISTENCY thread %p is linked in list %s but should be removed from list %s",
+ __FILE__, __LINE__, thread, thread->list->name, list->name);
+ assert(thread->list == list);
+ }
+
if (thread->next)
thread->next->prev = thread->prev;
- else
+ else {
+ if (list->tail != thread) {
+ zlog_debug("%s:%d: thread_list_delete INCONSISTENCY thread %p has no successor but list->tail points to %p in list %s",
+ __FILE__, __LINE__, thread, list->tail, list->name);
+ assert(list->tail == thread);
+ }
+
list->tail = thread->prev;
+ if (list->tail)
+ list->tail->next = NULL;
+ }
+
if (thread->prev)
thread->prev->next = thread->next;
- else
+ else {
+ if (list->head != thread) {
+ zlog_debug("%s:%d: thread_list_delete INCONSISTENCY thread %p has no predecessor but list->head points to %p in list %s",
+ __FILE__, __LINE__, thread, list->head, list->name);
+ assert(list->head == thread);
+ }
+
list->head = thread->next;
- thread->next = thread->prev = NULL;
+ if (list->head)
+ list->head->prev = NULL;
+ }
+
list->count--;
+
+ thread->next = thread->prev = NULL;
+ thread->list = NULL;
+
return thread;
}
@@ -603,10 +647,12 @@ thread_add_fd (struct thread **thread_ar
static void
thread_add_unuse (struct thread *thread)
{
- thread->type = THREAD_UNUSED;
assert (thread->master != NULL && thread != NULL);
+ assert (thread_current != thread);
assert (thread->next == NULL);
assert (thread->prev == NULL);
+ assert (thread->list == NULL);
+ thread->type = THREAD_UNUSED;
thread_list_add (&thread->master->unuse, thread);
}
@@ -948,7 +994,15 @@ thread_cancel (struct thread *thread)
struct thread_list *list = NULL;
struct pqueue *queue = NULL;
struct thread **thread_array = NULL;
-
+
+ /*
+ * we cannot cancel ourself when running.
+ * cancellation of ourself would lead to a double entry attempt
+ * into the unuse list.
+ */
+ if (thread_current == thread)
+ return;
+
switch (thread->type)
{
case THREAD_READ:
@@ -1175,7 +1229,7 @@ thread_fetch (struct thread_master *m)
exceptfd = fd_copy_fd_set(m->exceptfd);
/* Calculate select wait timer if nothing else to do */
- if (m->ready.count == 0)
+ if (thread_empty(&m->ready))
{
quagga_get_relative (NULL);
timer_wait = thread_timer_wait (m->timer, &timer_val);
|