brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · ff2b169 Raw
191 lines · c
1// SPDX-License-Identifier: GPL-2.02#include "threads.h"3#include "machine.h"4#include "thread.h"5 6static struct threads_table_entry *threads__table(struct threads *threads, pid_t tid)7{8	/* Cast it to handle tid == -1 */9	return &threads->table[(unsigned int)tid % THREADS__TABLE_SIZE];10}11 12static size_t key_hash(long key, void *ctx __maybe_unused)13{14	/* The table lookup removes low bit entropy, but this is just ignored here. */15	return key;16}17 18static bool key_equal(long key1, long key2, void *ctx __maybe_unused)19{20	return key1 == key2;21}22 23void threads__init(struct threads *threads)24{25	for (int i = 0; i < THREADS__TABLE_SIZE; i++) {26		struct threads_table_entry *table = &threads->table[i];27 28		hashmap__init(&table->shard, key_hash, key_equal, NULL);29		init_rwsem(&table->lock);30		table->last_match = NULL;31	}32}33 34void threads__exit(struct threads *threads)35{36	threads__remove_all_threads(threads);37	for (int i = 0; i < THREADS__TABLE_SIZE; i++) {38		struct threads_table_entry *table = &threads->table[i];39 40		hashmap__clear(&table->shard);41		exit_rwsem(&table->lock);42	}43}44 45size_t threads__nr(struct threads *threads)46{47	size_t nr = 0;48 49	for (int i = 0; i < THREADS__TABLE_SIZE; i++) {50		struct threads_table_entry *table = &threads->table[i];51 52		down_read(&table->lock);53		nr += hashmap__size(&table->shard);54		up_read(&table->lock);55	}56	return nr;57}58 59/*60 * Front-end cache - TID lookups come in blocks,61 * so most of the time we dont have to look up62 * the full rbtree:63 */64static struct thread *__threads_table_entry__get_last_match(struct threads_table_entry *table,65							    pid_t tid)66{67	struct thread *th, *res = NULL;68 69	th = table->last_match;70	if (th != NULL) {71		if (thread__tid(th) == tid)72			res = thread__get(th);73	}74	return res;75}76 77static void __threads_table_entry__set_last_match(struct threads_table_entry *table,78						  struct thread *th)79{80	thread__put(table->last_match);81	table->last_match = thread__get(th);82}83 84static void threads_table_entry__set_last_match(struct threads_table_entry *table,85						struct thread *th)86{87	down_write(&table->lock);88	__threads_table_entry__set_last_match(table, th);89	up_write(&table->lock);90}91 92struct thread *threads__find(struct threads *threads, pid_t tid)93{94	struct threads_table_entry *table  = threads__table(threads, tid);95	struct thread *res;96 97	down_read(&table->lock);98	res = __threads_table_entry__get_last_match(table, tid);99	if (!res) {100		if (hashmap__find(&table->shard, tid, &res))101			res = thread__get(res);102	}103	up_read(&table->lock);104	if (res)105		threads_table_entry__set_last_match(table, res);106	return res;107}108 109struct thread *threads__findnew(struct threads *threads, pid_t pid, pid_t tid, bool *created)110{111	struct threads_table_entry *table  = threads__table(threads, tid);112	struct thread *res = NULL;113 114	*created = false;115	down_write(&table->lock);116	res = thread__new(pid, tid);117	if (res) {118		if (hashmap__add(&table->shard, tid, res)) {119			/* Add failed. Assume a race so find other entry. */120			thread__put(res);121			res = NULL;122			if (hashmap__find(&table->shard, tid, &res))123				res = thread__get(res);124		} else {125			res = thread__get(res);126			*created = true;127		}128		if (res)129			__threads_table_entry__set_last_match(table, res);130	}131	up_write(&table->lock);132	return res;133}134 135void threads__remove_all_threads(struct threads *threads)136{137	for (int i = 0; i < THREADS__TABLE_SIZE; i++) {138		struct threads_table_entry *table = &threads->table[i];139		struct hashmap_entry *cur, *tmp;140		size_t bkt;141 142		down_write(&table->lock);143		__threads_table_entry__set_last_match(table, NULL);144		hashmap__for_each_entry_safe((&table->shard), cur, tmp, bkt) {145			struct thread *old_value;146 147			hashmap__delete(&table->shard, cur->key, /*old_key=*/NULL, &old_value);148			thread__put(old_value);149		}150		up_write(&table->lock);151	}152}153 154void threads__remove(struct threads *threads, struct thread *thread)155{156	struct threads_table_entry *table  = threads__table(threads, thread__tid(thread));157	struct thread *old_value;158 159	down_write(&table->lock);160	if (table->last_match && RC_CHK_EQUAL(table->last_match, thread))161		__threads_table_entry__set_last_match(table, NULL);162 163	hashmap__delete(&table->shard, thread__tid(thread), /*old_key=*/NULL, &old_value);164	thread__put(old_value);165	up_write(&table->lock);166}167 168int threads__for_each_thread(struct threads *threads,169			     int (*fn)(struct thread *thread, void *data),170			     void *data)171{172	for (int i = 0; i < THREADS__TABLE_SIZE; i++) {173		struct threads_table_entry *table = &threads->table[i];174		struct hashmap_entry *cur;175		size_t bkt;176 177		down_read(&table->lock);178		hashmap__for_each_entry((&table->shard), cur, bkt) {179			int rc = fn((struct thread *)cur->pvalue, data);180 181			if (rc != 0) {182				up_read(&table->lock);183				return rc;184			}185		}186		up_read(&table->lock);187	}188	return 0;189 190}191