You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
5.6 KiB
164 lines
5.6 KiB
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "admissions_info.h"
|
|
#include "http.h"
|
|
#include "listener_thread.h"
|
|
#include "module_database.h"
|
|
#include "panic.h"
|
|
#include "scheduler_options.h"
|
|
#include "tenant.h"
|
|
#include "tenant_config.h"
|
|
#include "priority_queue.h"
|
|
#include "sandbox_functions.h"
|
|
|
|
int tenant_database_add(struct tenant *tenant);
|
|
struct tenant *tenant_database_find_by_name(char *name);
|
|
struct tenant *tenant_database_find_by_socket_descriptor(int socket_descriptor);
|
|
struct tenant *tenant_database_find_by_port(uint16_t port);
|
|
struct tenant *tenant_database_find_by_ptr(void *ptr);
|
|
|
|
typedef void (*tenant_database_foreach_cb_t)(struct tenant *, void *, void *);
|
|
void tenant_database_foreach(tenant_database_foreach_cb_t, void *, void *);
|
|
|
|
static inline int
|
|
tenant_policy_specific_init(struct tenant *tenant, struct tenant_config *config)
|
|
{
|
|
switch (scheduler) {
|
|
case SCHEDULER_FIFO:
|
|
break;
|
|
case SCHEDULER_EDF:
|
|
break;
|
|
case SCHEDULER_MTDS:
|
|
/* Deferable Server Initialization */
|
|
tenant->replenishment_period = (uint64_t)config->replenishment_period_us * runtime_processor_speed_MHz;
|
|
tenant->max_budget = (uint64_t)config->max_budget_us * runtime_processor_speed_MHz;
|
|
tenant->remaining_budget = tenant->max_budget;
|
|
|
|
tenant->pwt_sandboxes = (struct perworker_tenant_sandbox_queue *)malloc(
|
|
runtime_worker_threads_count * sizeof(struct perworker_tenant_sandbox_queue));
|
|
if (!tenant->pwt_sandboxes) {
|
|
fprintf(stderr, "Failed to allocate tenant_sandboxes array: %s\n", strerror(errno));
|
|
return -1;
|
|
};
|
|
|
|
memset(tenant->pwt_sandboxes, 0,
|
|
runtime_worker_threads_count * sizeof(struct perworker_tenant_sandbox_queue));
|
|
|
|
for (int i = 0; i < runtime_worker_threads_count; i++) {
|
|
tenant->pwt_sandboxes[i].sandboxes = priority_queue_initialize(RUNTIME_TENANT_QUEUE_SIZE, false,
|
|
sandbox_get_priority);
|
|
tenant->pwt_sandboxes[i].tenant = tenant;
|
|
tenant->pwt_sandboxes[i].mt_class = (tenant->replenishment_period == 0) ? MT_DEFAULT
|
|
: MT_GUARANTEED;
|
|
tenant->pwt_sandboxes[i].tenant_timeout.tenant = tenant;
|
|
tenant->pwt_sandboxes[i].tenant_timeout.pwt = &tenant->pwt_sandboxes[i];
|
|
}
|
|
|
|
/* Initialize the tenant's global request queue */
|
|
tenant->tgrq_requests = malloc(sizeof(struct tenant_global_request_queue));
|
|
tenant->tgrq_requests->sandbox_requests = priority_queue_initialize(RUNTIME_TENANT_QUEUE_SIZE, false,
|
|
sandbox_get_priority);
|
|
tenant->tgrq_requests->tenant = tenant;
|
|
tenant->tgrq_requests->mt_class = (tenant->replenishment_period == 0) ? MT_DEFAULT : MT_GUARANTEED;
|
|
tenant->tgrq_requests->tenant_timeout.tenant = tenant;
|
|
tenant->tgrq_requests->tenant_timeout.pwt = NULL;
|
|
break;
|
|
|
|
case SCHEDULER_MTDBF:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline struct tenant *
|
|
tenant_alloc(struct tenant_config *config)
|
|
{
|
|
struct tenant *existing_tenant = tenant_database_find_by_name(config->name);
|
|
if (existing_tenant != NULL) panic("Tenant %s is already initialized\n", existing_tenant->name);
|
|
|
|
existing_tenant = tenant_database_find_by_port(config->port);
|
|
if (existing_tenant != NULL)
|
|
panic("Tenant %s is already configured with port %u\n", existing_tenant->name, config->port);
|
|
|
|
struct tenant *tenant = (struct tenant *)calloc(1, sizeof(struct tenant));
|
|
|
|
/* Move name */
|
|
tenant->name = config->name;
|
|
config->name = NULL;
|
|
|
|
tcp_server_init(&tenant->tcp_server, config->port);
|
|
http_router_init(&tenant->router, config->routes_len);
|
|
module_database_init(&tenant->module_db);
|
|
map_init(&tenant->scratch_storage);
|
|
|
|
/* Deferrable Server init */
|
|
tenant_policy_specific_init(tenant, config);
|
|
|
|
for (int i = 0; i < config->routes_len; i++) {
|
|
struct module *module = module_database_find_by_path(&tenant->module_db, config->routes[i].path);
|
|
if (module == NULL) {
|
|
/* Ownership of path moves here */
|
|
module = module_alloc(config->routes[i].path);
|
|
if (module != NULL) {
|
|
module_database_add(&tenant->module_db, module);
|
|
config->routes[i].path = NULL;
|
|
}
|
|
} else {
|
|
free(config->routes[i].path);
|
|
config->routes[i].path = NULL;
|
|
}
|
|
|
|
assert(module != NULL);
|
|
|
|
/* Ownership of config's route and http_resp_content_type move here */
|
|
int rc = http_router_add_route(&tenant->router, &config->routes[i], module);
|
|
if (unlikely(rc != 0)) {
|
|
panic("Tenant %s defined %lu routes, but router failed to grow beyond %lu\n", tenant->name,
|
|
config->routes_len, tenant->router.capacity);
|
|
}
|
|
|
|
config->routes[i].route = NULL;
|
|
config->routes[i].http_resp_content_type = NULL;
|
|
}
|
|
|
|
return tenant;
|
|
}
|
|
|
|
/**
|
|
* Get Timeout priority for Priority Queue ordering
|
|
* @param element tenant_timeout
|
|
* @returns the priority of the tenant _timeout element
|
|
*/
|
|
static inline uint64_t
|
|
tenant_timeout_get_priority(void *element)
|
|
{
|
|
return ((struct tenant_timeout *)element)->timeout;
|
|
}
|
|
|
|
/**
|
|
* Compute the next timeout given a tenant's replenishment period
|
|
* @param m_replenishment_period
|
|
* @return given tenant's next timeout
|
|
*/
|
|
static inline uint64_t
|
|
get_next_timeout_of_tenant(uint64_t replenishment_period)
|
|
{
|
|
assert(replenishment_period != 0);
|
|
uint64_t now = __getcycles();
|
|
return runtime_boot_timestamp
|
|
+ ((now - runtime_boot_timestamp) / replenishment_period + 1) * replenishment_period;
|
|
}
|
|
|
|
|
|
/**
|
|
* Start the tenant as a server listening at tenant->port
|
|
* @param tenant
|
|
* @returns 0 on success, -1 on error
|
|
*/
|
|
int tenant_listen(struct tenant *tenant);
|
|
int listener_thread_register_tenant(struct tenant *tenant);
|