2 * Utilities and interfaces for managing POSIX threads
3 * Copyright (C) 2017 Cumulus Networks
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "frr_pthread.h"
28 DEFINE_MTYPE_STATIC(LIB
, FRR_PTHREAD
, "FRR POSIX Thread");
30 static unsigned int next_id
= 0;
32 /* Hash table of all frr_pthreads along with synchronization primitive(s) and
33 * hash table callbacks.
34 * ------------------------------------------------------------------------ */
35 static struct hash
*pthread_table
;
36 static pthread_mutex_t pthread_table_mtx
= PTHREAD_MUTEX_INITIALIZER
;
38 /* pthread_table->hash_cmp */
39 static int pthread_table_hash_cmp(const void *value1
, const void *value2
)
41 const struct frr_pthread
*tq1
= value1
;
42 const struct frr_pthread
*tq2
= value2
;
44 return (tq1
->id
== tq2
->id
);
47 /* pthread_table->hash_key */
48 static unsigned int pthread_table_hash_key(void *value
)
50 return ((struct frr_pthread
*)value
)->id
;
52 /* ------------------------------------------------------------------------ */
54 void frr_pthread_init()
56 pthread_mutex_lock(&pthread_table_mtx
);
58 pthread_table
= hash_create(pthread_table_hash_key
,
59 pthread_table_hash_cmp
, NULL
);
61 pthread_mutex_unlock(&pthread_table_mtx
);
64 void frr_pthread_finish()
66 pthread_mutex_lock(&pthread_table_mtx
);
68 hash_clean(pthread_table
,
69 (void (*)(void *))frr_pthread_destroy
);
70 hash_free(pthread_table
);
72 pthread_mutex_unlock(&pthread_table_mtx
);
75 struct frr_pthread
*frr_pthread_new(const char *name
, unsigned int id
,
76 void *(*start_routine
)(void *),
77 int (*stop_routine
)(void **,
78 struct frr_pthread
*))
80 static struct frr_pthread holder
= {0};
81 struct frr_pthread
*fpt
= NULL
;
83 pthread_mutex_lock(&pthread_table_mtx
);
87 if (!hash_lookup(pthread_table
, &holder
)) {
88 struct frr_pthread
*fpt
= XCALLOC(
89 MTYPE_FRR_PTHREAD
, sizeof(struct frr_pthread
));
91 fpt
->master
= thread_master_create(name
);
92 fpt
->start_routine
= start_routine
;
93 fpt
->stop_routine
= stop_routine
;
94 fpt
->name
= XSTRDUP(MTYPE_FRR_PTHREAD
, name
);
96 hash_get(pthread_table
, fpt
, hash_alloc_intern
);
99 pthread_mutex_unlock(&pthread_table_mtx
);
104 void frr_pthread_destroy(struct frr_pthread
*fpt
)
106 thread_master_free(fpt
->master
);
107 XFREE(MTYPE_FRR_PTHREAD
, fpt
->name
);
108 XFREE(MTYPE_FRR_PTHREAD
, fpt
);
111 struct frr_pthread
*frr_pthread_get(unsigned int id
)
113 static struct frr_pthread holder
= {0};
114 struct frr_pthread
*fpt
;
116 pthread_mutex_lock(&pthread_table_mtx
);
119 fpt
= hash_lookup(pthread_table
, &holder
);
121 pthread_mutex_unlock(&pthread_table_mtx
);
126 int frr_pthread_run(unsigned int id
, const pthread_attr_t
*attr
, void *arg
)
128 struct frr_pthread
*fpt
= frr_pthread_get(id
);
134 ret
= pthread_create(&fpt
->thread
, attr
, fpt
->start_routine
, arg
);
136 /* Per pthread_create(3), the contents of fpt->thread are undefined if
137 * pthread_create() did not succeed. Reset this value to zero. */
139 memset(&fpt
->thread
, 0x00, sizeof(fpt
->thread
));
145 * Calls the stop routine for the frr_pthread and resets any relevant fields.
147 * @param fpt - the frr_pthread to stop
148 * @param result - pointer to result pointer
149 * @return the return code from the stop routine
151 static int frr_pthread_stop_actual(struct frr_pthread
*fpt
, void **result
)
153 int ret
= (*fpt
->stop_routine
)(result
, fpt
);
154 memset(&fpt
->thread
, 0x00, sizeof(fpt
->thread
));
158 int frr_pthread_stop(unsigned int id
, void **result
)
160 struct frr_pthread
*fpt
= frr_pthread_get(id
);
161 return frr_pthread_stop_actual(fpt
, result
);
165 * Callback for hash_iterate to stop all frr_pthread's.
167 static void frr_pthread_stop_all_iter(struct hash_backet
*hb
, void *arg
)
169 struct frr_pthread
*fpt
= hb
->data
;
170 frr_pthread_stop_actual(fpt
, NULL
);
173 void frr_pthread_stop_all()
175 pthread_mutex_lock(&pthread_table_mtx
);
177 hash_iterate(pthread_table
, frr_pthread_stop_all_iter
, NULL
);
179 pthread_mutex_unlock(&pthread_table_mtx
);
182 unsigned int frr_pthread_get_id()
187 void frr_pthread_yield(void)