Arax -8d09c51940345c86062e8ef2427c705ae66e5926
A Runtime Framework for Decoupling Applications from Heterogeneous Accelerators
Loading...
Searching...
No Matches
ivshmem/async.c
Go to the documentation of this file.
1#include "conf.h"
2#include "async.h"
3#include "utils/config.h"
4#include <stdlib.h>
5#include <stdio.h>
6#include <unistd.h>
7#include <fcntl.h>
8#include <sys/mman.h>
9
10// Taken from ivshmem manual/thesis:
11// See Shared-Memory Optimizations for Virtual Machines by A. Cameron Macdonell
12// Sections 4.6 (4.6.5 and 4.6.6 in particular)
14{
15 ISR_REG = 0, // < Not used(yet)
16 IMR_REG = 1, // < Not used(yet)
17 VM_ID_REG = 2, // < My VMs ID
18 BELL_REG = 3 // < [DEST_VM_ID,FD_NUMBER]
19};
20
21struct ivshmem
22{
23 volatile unsigned int regs[64];
24};
25
26void wakeupVm(async_meta_s *meta, unsigned int vm_id)
27{
28 meta->regs->regs[BELL_REG] = (vm_id << 16) | 0; // Wakeup
29}
30
31unsigned int getVmID(async_meta_s *meta)
32{
33 return meta->regs->regs[VM_ID_REG];
34}
35
36static int reg_fd = 0;
37void* async_thread(void *data)
38{
39 async_meta_s *meta = data;
42 async_completion_s *compl;
43 int buff;
44
45 printf("async_thread started (VM:%d)!\n", getVmID(meta));
46 while (reg_fd) {
47 // Waiting for 'interrupt'
48 read(reg_fd, &buff, sizeof(buff));
49 // something happened
51 {
52 compl = itr->owner;
53 // Should check completion is mine?
54 if (async_completion_check(compl) ) {
55 utils_list_del(&(meta->outstanding), itr);
56 pthread_mutex_unlock(&(compl->mutex));
57 }
58 }
59 }
60 printf("async_thread stoped (VM:%d)!\n", getVmID(meta));
61 return 0;
62}
63
65{
66 utils_spinlock_lock(&(meta->lock));
67 utils_list_add(&(meta->outstanding), &(completion->outstanding));
69}
70
72{
73 int shm_ivshmem = 0;
74 char *config = utils_config_alloc_path(ARAX_CONFIG_FILE);
75
76 utils_config_get_bool(config, "shm_ivshmem", &shm_ivshmem, 0);
78 if (!shm_ivshmem) {
79 fprintf(stderr, "Attempted to use ivshmem synchronization on non-"
80 "ivshmem setup!\n");
81 abort();
82 }
83
84 utils_spinlock_init(&(meta->lock));
86 meta->alloc = alloc;
87}
88
90{
91 char shm_file[1024];
92 char *config = utils_config_alloc_path(ARAX_CONFIG_FILE);
93
94 if (!utils_config_get_str(config, "shm_file", shm_file, 1024, 0) ) {
96 abort();
97 }
99
100 reg_fd = open(shm_file, O_CREAT | O_RDWR, 0644);
101
102 if (reg_fd <= 0) {
103 fprintf(stderr, "Failed to open shm_file: %s\n", shm_file);
104 abort();
105 }
106
107 meta->regs = mmap(meta->regs, 256, PROT_READ | PROT_WRITE,
108 MAP_SHARED, reg_fd, 0);
109
110 fprintf(stderr, "Ivshmem regs mapped at %p\n", meta->regs);
111
112 if (pthread_create(&(meta->thread), 0, async_thread, meta)) {
113 fprintf(stderr, "Failed to spawn async_thread\n");
114 abort();
115 }
116}
117
119{
120 completion->meta = meta;
121 utils_list_node_init(&(completion->outstanding), completion);
122 pthread_mutexattr_init(&(completion->attr));
123 pthread_mutexattr_setpshared(&(completion->attr), PTHREAD_PROCESS_SHARED);
124 pthread_mutex_init(&(completion->mutex), &(completion->attr));
125 completion->completed = 0; // Completion not completed
126 pthread_mutex_lock(&(completion->mutex)); // wait should block
127}
128
130{
131 completion->completed = 1; // Mark as completed
132 wakeupVm(completion->meta, completion->vm_id);
133}
134
136{
137 if (pthread_mutex_trylock(&(completion->mutex))) { // Failed, so add me to the outstanding list
138 _add_completion(completion->meta, completion);
139 }
140 completion->vm_id = getVmID(completion->meta);
141 pthread_mutex_lock(&(completion->mutex)); // Will sleep until mutex unlocked.
142}
143
145{
146 return completion->completed;
147}
148
150{
153 sem->value = 0;
154}
155
157{
158 return sem->value;
159}
160
162{
163 int val = __sync_fetch_and_add(&(sem->value), 1);
164 utils_list_node_s *node, *next;
165
166 // val contains the min number of penders that must wake up.
167 if (sem->pending_list.length) { // Seem to have penders
169 do{ // Lets wake em
170 node = sem->pending_list.head.next;
171 next = node->next;
172 utils_list_del(&(sem->pending_list), node);
173 _add_completion(sem->meta, node->owner);
174 async_completion_complete(node->owner); // Notify vm
175 node = next;
176 }while ( (val = __sync_fetch_and_add(&(sem->value), -1)) );
178 }
179}
180
182{
183 int val = sem->value;
184
185 while (val) { // Seems Positive
186 if (__sync_bool_compare_and_swap(&(sem->value), val - 1, val)) { // Was positive and i got it
187 return;
188 } else {
189 val = sem->value;
190 }
191 }
192 // Have to wait
193 async_completion_s *compl;
194
195 compl = arch_alloc_allocate(sem->meta->alloc, sizeof(*compl));
196 async_completion_init(sem->meta, compl);
198 // Add is LIFO, this might be bad for tail latency(starvation).
199 utils_list_add(&(sem->pending_list), &(compl->outstanding));
201 wakeupVm(sem->meta, getVmID(sem->meta)); // Might missed an inc
203 arch_alloc_free(sem->meta->alloc, compl);
204}
205
207{
208 async_completion_init(meta, &(cond->mutex));
210 async_semaphore_init(meta, &(cond->semaphore));
211}
212
217
224
229
234
236{
237 int fd = meta->fd;
238
239 meta->fd = 0;
240 wakeupVm(meta, getVmID(meta)); // Wakeup Myself to terminate async_thread
241 printf("Waiting for async_thread to exit!\n");
242 pthread_join(meta->thread, 0);
243 munmap(meta->regs, 256);
244 close(fd);
245}
#define arch_alloc_free(ALLOC, MEM)
Definition alloc.h:70
void * arch_alloc_allocate(arch_alloc_s *alloc, size_t size)
struct utils_list_node utils_list_node_s
#define utils_list_for_each_safe(list, itr, tmp)
Definition list.h:106
char shm_file[1024]
Definition impl.c:18
int fd
Definition impl.c:25
int utils_config_get_str(char *path, const char *key, char *value, size_t value_size, const char *def_val)
Definition config.c:164
void utils_config_free_path(char *path)
Definition config.c:128
int utils_config_get_bool(char *path, const char *key, int *value, int def_val)
Definition config.c:178
char * utils_config_alloc_path(const char *path)
Definition config.c:94
utils_list_node_s * utils_list_del(utils_list_s *list, utils_list_node_s *node)
Definition list.c:26
void utils_list_node_init(utils_list_node_s *node, void *owner)
Definition list.c:74
utils_list_s * utils_list_init(void *mem)
Definition list.c:3
void utils_list_add(utils_list_s *list, utils_list_node_s *node)
Definition list.c:20
#define utils_spinlock_lock(V)
Definition queue.c:35
#define utils_spinlock_init(V)
Definition queue.c:34
#define utils_spinlock_unlock(V)
Definition queue.c:36
volatile unsigned int regs[64]
pthread_t thread
utils_spinlock lock
utils_list_s outstanding
volatile int fd
arch_alloc_s * alloc
ivshmem_s * regs
async_meta_s * meta
pthread_mutex_t mutex
volatile size_t completed
pthread_mutexattr_t attr
utils_list_node_s outstanding
async_meta_s * meta
utils_spinlock pending_lock
utils_list_s pending_list
volatile size_t value
async_semaphore_s semaphore
async_completion_s mutex
struct utils_list_node * next
Definition list.h:12
void * owner
Definition list.h:14
utils_list_node_s head
Definition list.h:18
size_t length
Definition list.h:19
void async_semaphore_inc(async_semaphore_s *sem)
void async_condition_wait(async_condition_s *cond)
void async_semaphore_init(async_meta_s *meta, async_semaphore_s *sem)
int async_semaphore_value(async_semaphore_s *sem)
void async_condition_unlock(async_condition_s *cond)
void async_condition_notify(async_condition_s *cond)
unsigned int getVmID(async_meta_s *meta)
RegisterOffsets
@ ISR_REG
@ IMR_REG
@ BELL_REG
@ VM_ID_REG
void async_semaphore_dec(async_semaphore_s *sem)
void _add_completion(async_meta_s *meta, async_completion_s *completion)
void * async_thread(void *data)
void async_meta_init_once(async_meta_s *meta, arch_alloc_s *alloc)
void wakeupVm(async_meta_s *meta, unsigned int vm_id)
void async_completion_init(async_meta_s *meta, async_completion_s *completion)
void async_condition_init(async_meta_s *meta, async_condition_s *cond)
void async_completion_complete(async_completion_s *completion)
void async_meta_init_always(async_meta_s *meta)
int async_completion_check(async_completion_s *completion)
void async_completion_wait(async_completion_s *completion)
static int reg_fd
void async_condition_lock(async_condition_s *cond)
void async_meta_exit(async_meta_s *meta)