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");
29 DEFINE_MTYPE(LIB
, PTHREAD_PRIM
, "POSIX synchronization primitives");
31 static unsigned int next_id
= 0;
33 /* Hash table of all frr_pthreads along with synchronization primitive(s) and
34 * hash table callbacks.
35 * ------------------------------------------------------------------------ */
36 static struct hash
*pthread_table
;
37 static pthread_mutex_t pthread_table_mtx
= PTHREAD_MUTEX_INITIALIZER
;
39 /* pthread_table->hash_cmp */
40 static int pthread_table_hash_cmp(const void *value1
, const void *value2
)
42 const struct frr_pthread
*tq1
= value1
;
43 const struct frr_pthread
*tq2
= value2
;
45 return (tq1
->id
== tq2
->id
);
48 /* pthread_table->hash_key */
49 static unsigned int pthread_table_hash_key(void *value
)
51 return ((struct frr_pthread
*)value
)->id
;
53 /* ------------------------------------------------------------------------ */
55 void frr_pthread_init()
57 pthread_mutex_lock(&pthread_table_mtx
);
59 pthread_table
= hash_create(pthread_table_hash_key
,
60 pthread_table_hash_cmp
, NULL
);
62 pthread_mutex_unlock(&pthread_table_mtx
);
65 void frr_pthread_finish()
67 pthread_mutex_lock(&pthread_table_mtx
);
69 hash_clean(pthread_table
,
70 (void (*)(void *))frr_pthread_destroy
);
71 hash_free(pthread_table
);
73 pthread_mutex_unlock(&pthread_table_mtx
);
76 struct frr_pthread
*frr_pthread_new(const char *name
, unsigned int id
,
77 void *(*start_routine
)(void *),
78 int (*stop_routine
)(void **,
79 struct frr_pthread
*))
81 static struct frr_pthread holder
= {0};
82 struct frr_pthread
*fpt
= NULL
;
84 pthread_mutex_lock(&pthread_table_mtx
);
88 if (!hash_lookup(pthread_table
, &holder
)) {
89 struct frr_pthread
*fpt
= XCALLOC(
90 MTYPE_FRR_PTHREAD
, sizeof(struct frr_pthread
));
92 fpt
->master
= thread_master_create(name
);
93 fpt
->start_routine
= start_routine
;
94 fpt
->stop_routine
= stop_routine
;
95 fpt
->name
= XSTRDUP(MTYPE_FRR_PTHREAD
, name
);
97 hash_get(pthread_table
, fpt
, hash_alloc_intern
);
100 pthread_mutex_unlock(&pthread_table_mtx
);
105 void frr_pthread_destroy(struct frr_pthread
*fpt
)
107 thread_master_free(fpt
->master
);
108 XFREE(MTYPE_FRR_PTHREAD
, fpt
->name
);
109 XFREE(MTYPE_FRR_PTHREAD
, fpt
);
112 struct frr_pthread
*frr_pthread_get(unsigned int id
)
114 static struct frr_pthread holder
= {0};
115 struct frr_pthread
*fpt
;
117 pthread_mutex_lock(&pthread_table_mtx
);
120 fpt
= hash_lookup(pthread_table
, &holder
);
122 pthread_mutex_unlock(&pthread_table_mtx
);
127 int frr_pthread_run(unsigned int id
, const pthread_attr_t
*attr
, void *arg
)
129 struct frr_pthread
*fpt
= frr_pthread_get(id
);
135 ret
= pthread_create(&fpt
->thread
, attr
, fpt
->start_routine
, arg
);
137 /* Per pthread_create(3), the contents of fpt->thread are undefined if
138 * pthread_create() did not succeed. Reset this value to zero. */
140 memset(&fpt
->thread
, 0x00, sizeof(fpt
->thread
));
146 * Calls the stop routine for the frr_pthread and resets any relevant fields.
148 * @param fpt - the frr_pthread to stop
149 * @param result - pointer to result pointer
150 * @return the return code from the stop routine
152 static int frr_pthread_stop_actual(struct frr_pthread
*fpt
, void **result
)
154 int ret
= (*fpt
->stop_routine
)(result
, fpt
);
155 memset(&fpt
->thread
, 0x00, sizeof(fpt
->thread
));
159 int frr_pthread_stop(unsigned int id
, void **result
)
161 struct frr_pthread
*fpt
= frr_pthread_get(id
);
162 return frr_pthread_stop_actual(fpt
, result
);
166 * Callback for hash_iterate to stop all frr_pthread's.
168 static void frr_pthread_stop_all_iter(struct hash_backet
*hb
, void *arg
)
170 struct frr_pthread
*fpt
= hb
->data
;
171 frr_pthread_stop_actual(fpt
, NULL
);
174 void frr_pthread_stop_all()
176 pthread_mutex_lock(&pthread_table_mtx
);
178 hash_iterate(pthread_table
, frr_pthread_stop_all_iter
, NULL
);
180 pthread_mutex_unlock(&pthread_table_mtx
);
183 unsigned int frr_pthread_get_id()
188 void frr_pthread_yield(void)