blob: a3ae792417af77dbf30aa46fc1525d310c2dd539 [file] [log] [blame]
Harald Weltecbd18962019-03-03 19:02:38 +01001
2#include <stdint.h>
3#include <stdlib.h>
4#include <stdio.h>
5#include <errno.h>
6
7#include <pthread.h>
8
9#include <talloc.h>
10
11#include <osmocom/core/linuxlist.h>
12
13#include "slotmap.h"
14
Harald Weltefaef8f02019-03-03 20:55:22 +010015const char *slotmap_name(char *buf, size_t buf_len, const struct slot_mapping *map)
16{
17 snprintf(buf, buf_len, "B(%u:%u) <-> C(%u:%u)",
18 map->bank.bank_id, map->bank.slot_nr, map->client.client_id, map->client.slot_nr);
19 return buf;
20}
21
22
Harald Weltecbd18962019-03-03 19:02:38 +010023/* thread-safe lookup of map by client:slot */
24struct slot_mapping *slotmap_by_client(struct slotmaps *maps, const struct client_slot *client)
25{
26 struct slot_mapping *map;
27
28 pthread_rwlock_rdlock(&maps->rwlock);
29 llist_for_each_entry(map, &maps->mappings, list) {
30 if (client_slot_equals(&map->client, client)) {
31 pthread_rwlock_unlock(&maps->rwlock);
32 return map;
33 }
34 }
35 pthread_rwlock_unlock(&maps->rwlock);
36 return NULL;
37}
38
39/* thread-safe lookup of map by bank:slot */
40struct slot_mapping *slotmap_by_bank(struct slotmaps *maps, const struct bank_slot *bank)
41{
42 struct slot_mapping *map;
43
44 pthread_rwlock_rdlock(&maps->rwlock);
45 llist_for_each_entry(map, &maps->mappings, list) {
46 if (bank_slot_equals(&map->bank, bank)) {
47 pthread_rwlock_unlock(&maps->rwlock);
48 return map;
49 }
50 }
51 pthread_rwlock_unlock(&maps->rwlock);
52 return NULL;
53
54}
55
56/* thread-safe creating of a new bank<->client map */
57int slotmap_add(struct slotmaps *maps, const struct bank_slot *bank, const struct client_slot *client)
58{
59 struct slot_mapping *map;
Harald Weltefaef8f02019-03-03 20:55:22 +010060 char mapname[64];
Harald Weltecbd18962019-03-03 19:02:38 +010061
62 /* We assume a single thread (main thread) will ever update the mappings,
63 * and hence we don't have any races by first grabbing + releasing the read
64 * lock twice before grabbing the writelock below */
65
66 map = slotmap_by_bank(maps, bank);
67 if (map) {
68 fprintf(stderr, "BANKD %u:%u already in use, cannot add new map\n",
69 bank->bank_id, bank->slot_nr);
70 return -EBUSY;
71 }
72
73 map = slotmap_by_client(maps, client);
74 if (map) {
75 fprintf(stderr, "CLIENT %u:%u already in use, cannot add new map\n",
76 client->client_id, client->slot_nr);
77 return -EBUSY;
78 }
79
80 /* allocate new mapping and add to list of mappings */
81 map = talloc_zero(maps, struct slot_mapping);
82 if (!map)
83 return -ENOMEM;
84
85 map->bank = *bank;
86 map->client = *client;
87
88 pthread_rwlock_wrlock(&maps->rwlock);
89 llist_add_tail(&map->list, &maps->mappings);
90 pthread_rwlock_unlock(&maps->rwlock);
91
Harald Weltefaef8f02019-03-03 20:55:22 +010092 printf("Slot Map %s added\n", slotmap_name(mapname, sizeof(mapname), map));
Harald Weltecbd18962019-03-03 19:02:38 +010093
94 return 0;
95}
96
97/* thread-safe removal of a bank<->client map */
98void slotmap_del(struct slotmaps *maps, struct slot_mapping *map)
99{
Harald Weltefaef8f02019-03-03 20:55:22 +0100100 char mapname[64];
101
102 printf("Slot Map %s deleted\n", slotmap_name(mapname, sizeof(mapname), map));
Harald Weltecbd18962019-03-03 19:02:38 +0100103
104 pthread_rwlock_wrlock(&maps->rwlock);
105 llist_del(&map->list);
106 pthread_rwlock_unlock(&maps->rwlock);
107
108 talloc_free(map);
109}
110
111struct slotmaps *slotmap_init(void *ctx)
112{
113 struct slotmaps *sm = talloc_zero(ctx, struct slotmaps);
114
115 INIT_LLIST_HEAD(&sm->mappings);
116 pthread_rwlock_init(&sm->rwlock, NULL);
117
118 return sm;
119}