Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
30a27016ba | ||
![]() |
f1d5ed18a9 | ||
290adb044b | |||
8f9c2ce3b1 | |||
![]() |
25f85c939a | ||
![]() |
330b4c8908 | ||
![]() |
a1c272e8b0 | ||
![]() |
45c6c2012d | ||
![]() |
a558bbe732 | ||
![]() |
6ac7dac4ad | ||
![]() |
f51ce7f10b | ||
![]() |
303909439d |
4680
a1.1.config
Normal file
4680
a1.1.config
Normal file
File diff suppressed because it is too large
Load Diff
4684
a1.2.config
Normal file
4684
a1.2.config
Normal file
File diff suppressed because it is too large
Load Diff
4684
a1.3.config
Normal file
4684
a1.3.config
Normal file
File diff suppressed because it is too large
Load Diff
4689
a1.4.config
Normal file
4689
a1.4.config
Normal file
File diff suppressed because it is too large
Load Diff
2
a1.4.txt
Normal file
2
a1.4.txt
Normal file
@ -0,0 +1,2 @@
|
||||
1) hardirq_safe bedeutet dass eine prozess läuft in einem Kontext, der sicher für Hardware-Unterbrechungen ist. es halt keine kmalloc, spin_locks...
|
||||
2) lockdep_assert_held()
|
@ -239,4 +239,6 @@ source "drivers/peci/Kconfig"
|
||||
|
||||
source "drivers/hte/Kconfig"
|
||||
|
||||
source "drivers/sst/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
@ -189,3 +189,4 @@ obj-$(CONFIG_COUNTER) += counter/
|
||||
obj-$(CONFIG_MOST) += most/
|
||||
obj-$(CONFIG_PECI) += peci/
|
||||
obj-$(CONFIG_HTE) += hte/
|
||||
obj-$(CONFIG_SST) += sst/
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <net/route.h>
|
||||
#include <net/xdp.h>
|
||||
#include <net/net_failover.h>
|
||||
#include <linux/sst.h>
|
||||
|
||||
static int napi_weight = NAPI_POLL_WEIGHT;
|
||||
module_param(napi_weight, int, 0444);
|
||||
@ -1674,8 +1675,25 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
|
||||
struct send_queue *sq;
|
||||
unsigned int received;
|
||||
unsigned int xdp_xmit = 0;
|
||||
#ifdef CONFIG_SST_LOCKING
|
||||
static unsigned long next_time = 0;
|
||||
char *question = NULL;
|
||||
#endif
|
||||
|
||||
virtnet_poll_cleantx(rq, budget);
|
||||
#ifdef CONFIG_SST_LOCKING
|
||||
if (next_time == 0) {
|
||||
next_time = msecs_to_jiffies(65000) + jiffies;
|
||||
} else if (time_after_eq(jiffies, next_time)) {
|
||||
pr_debug("sst: Sending a random question (0x%lx,0x%lx)\n", in_hardirq(), in_softirq());
|
||||
next_time = msecs_to_jiffies((get_random_u8() % 100) * 1000 + 15000) + jiffies;
|
||||
question = kmalloc(sizeof(char) * 100, GFP_NOWAIT);
|
||||
if (question) {
|
||||
snprintf(question, 100, sst_questions[(get_random_u8() % SST_MAX_QUESTIONS)]);
|
||||
sst_produce_question(get_sst_info(), question);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
received = virtnet_receive(rq, budget, &xdp_xmit);
|
||||
|
||||
|
24
drivers/sst/Kconfig
Normal file
24
drivers/sst/Kconfig
Normal file
@ -0,0 +1,24 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Character device configuration
|
||||
#
|
||||
|
||||
menuconfig SST
|
||||
tristate "Modules for system software techniques"
|
||||
default y
|
||||
help
|
||||
TODO
|
||||
|
||||
if SST
|
||||
config SST_BOUNDS
|
||||
tristate "Out-of-bounds accesses for exercise a1.3"
|
||||
default n
|
||||
help
|
||||
Activate out-of-bounds accesses for exercise a1.3
|
||||
|
||||
config SST_ASYNC_SOURCE
|
||||
tristate "Enable async source of messages from the universe"
|
||||
default n
|
||||
help
|
||||
This is needed for task a1.4
|
||||
endif
|
9
drivers/sst/Makefile
Normal file
9
drivers/sst/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the SST's faulty drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SST) += sst_chrdev.o boundedbuffer.o sst_common.o
|
||||
CFLAGS_sst_chrdev.o := -DDEBUG
|
||||
CFLAGS_sst_common.o := -DDEBUG
|
||||
CFLAGS_boundedbuffer.o := -DDEBUG
|
42
drivers/sst/boundedbuffer.c
Normal file
42
drivers/sst/boundedbuffer.c
Normal file
@ -0,0 +1,42 @@
|
||||
#include "sst_internal.h"
|
||||
|
||||
#ifdef CONFIG_SST_BOUNDS
|
||||
#define OFFSET (4 * BOUNDEDBUFFER_SIZE)
|
||||
#else
|
||||
#define OFFSET 0
|
||||
#endif
|
||||
|
||||
void init_bbuffer(struct boundedbuffer *buffer) {
|
||||
buffer->next_in = 0;
|
||||
buffer->next_out = 0;
|
||||
buffer->size = BOUNDEDBUFFER_SIZE;
|
||||
}
|
||||
|
||||
int is_full(struct boundedbuffer *buffer) {
|
||||
return (buffer->next_in + 1) % buffer->size == buffer->next_out;
|
||||
}
|
||||
|
||||
int is_empty(struct boundedbuffer *buffer) {
|
||||
return buffer->next_out == buffer->next_in;
|
||||
}
|
||||
|
||||
int produce(struct boundedbuffer *buffer, BOUNDEDBUFFER_STORAGE_TYPE data) {
|
||||
if (is_full(buffer)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer->data[buffer->next_in + OFFSET] = data;
|
||||
buffer->next_in = (buffer->next_in + 1) % buffer->size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int consume(struct boundedbuffer *buffer, BOUNDEDBUFFER_STORAGE_TYPE *ret) {
|
||||
if (is_empty(buffer)) {
|
||||
return -1;
|
||||
}
|
||||
*ret = buffer->data[buffer->next_out + OFFSET];
|
||||
buffer->next_out = (buffer->next_out + 1) % buffer->size;
|
||||
|
||||
return 0;
|
||||
}
|
29
drivers/sst/boundedbuffer.h
Normal file
29
drivers/sst/boundedbuffer.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef __BOUNDEDBUFFER_H__
|
||||
#define __BOUNDEDBUFFER_H__
|
||||
/*
|
||||
* For some reasons, our ring buffer (aka BSB ring buffer)
|
||||
* can only hold size - 1 elements.
|
||||
* If we want to store BOUNDEDBUFFER_SIZE elements, as desired,
|
||||
* the buffer must be one element larger.
|
||||
* Hence, BOUNDEDBUFFER_SIZE_REAL is used for allocating the actual buffer
|
||||
* and used for the size member.
|
||||
*/
|
||||
#ifndef BOUNDEDBUFFER_SIZE
|
||||
#error Buffer size not defined!
|
||||
#endif
|
||||
#define BOUNDEDBUFFER_SIZE_REAL (BOUNDEDBUFFER_SIZE + 1)
|
||||
#define BOUNDEDBUFFER_SIZE_VIRT (BOUNDEDBUFFER_SIZE_REAL - 1)
|
||||
|
||||
struct boundedbuffer {
|
||||
int next_in;
|
||||
int next_out;
|
||||
int size;
|
||||
BOUNDEDBUFFER_STORAGE_TYPE data[BOUNDEDBUFFER_SIZE_REAL];
|
||||
};
|
||||
|
||||
void init_bbuffer(struct boundedbuffer *buffer);
|
||||
int is_full(struct boundedbuffer *buffer);
|
||||
int is_empty(struct boundedbuffer *buffer);
|
||||
int produce(struct boundedbuffer *buffer, BOUNDEDBUFFER_STORAGE_TYPE data);
|
||||
int consume(struct boundedbuffer *buffer, BOUNDEDBUFFER_STORAGE_TYPE *ret);
|
||||
#endif // __BOUNDEDBUFFER_H__
|
130
drivers/sst/sst_chrdev.c
Normal file
130
drivers/sst/sst_chrdev.c
Normal file
@ -0,0 +1,130 @@
|
||||
#include "sst_internal.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#define SST_CHRDEV "the-universe"
|
||||
|
||||
static int sst_chrdev_major = 0;
|
||||
static struct device *my_universe = NULL;
|
||||
|
||||
static int universe_open(struct inode *inode, struct file *file) {
|
||||
file->private_data = get_sst_info();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int universe_release(struct inode *inode, struct file *file) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t universe_read(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *ppos) {
|
||||
struct sst_info *sst_info = (struct sst_info*)file->private_data;
|
||||
char *answer = NULL;
|
||||
int min = 0;
|
||||
size_t len = 0;
|
||||
|
||||
if (sst_consume_answer(sst_info, &answer)) {
|
||||
pr_debug("Cannot read from answers!\n");
|
||||
return 0;
|
||||
}
|
||||
len = strlen(answer);
|
||||
sst_debug("About to copy %lu bytes of your answer at 0x%lx to the userspace\n", len, (uintptr_t)answer);
|
||||
min = min(len, count);
|
||||
if (min != len) {
|
||||
pr_err("Sorry, your buffer is %lu bytes too small.\n", len - min);
|
||||
}
|
||||
if (copy_to_user(buf, answer, min)) {
|
||||
pr_err("User copy failed!\n");
|
||||
kfree(answer);
|
||||
return -EFAULT;
|
||||
}
|
||||
sst_debug("Copied %u bytes of your answer to the userspace: %s\n", min, answer);
|
||||
*ppos += len;
|
||||
kfree(answer);
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t universe_write(struct file *file, const char __user *buf, size_t count,
|
||||
loff_t *ppos) {
|
||||
struct sst_info *sst_info = (struct sst_info*)file->private_data;
|
||||
char *buf_copy;
|
||||
int err;
|
||||
|
||||
buf_copy = memdup_user_nul(buf, count);
|
||||
if (IS_ERR(buf_copy)) {
|
||||
return PTR_ERR(buf_copy);
|
||||
}
|
||||
err = sst_produce_question(sst_info, buf_copy);
|
||||
if (err) {
|
||||
pr_err("Weird! The universe is full.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
sst_debug("Asked the universe a question...\n");
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations universe_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = universe_read,
|
||||
.write = universe_write,
|
||||
.open = universe_open,
|
||||
.release = universe_release,
|
||||
};
|
||||
|
||||
static struct class universe_class = {
|
||||
.name = SST_CHRDEV,
|
||||
};
|
||||
|
||||
static int __init sst_chrdev_init(void) {
|
||||
int err;
|
||||
|
||||
sst_chrdev_major = err = register_chrdev(0, SST_CHRDEV, &universe_fops);
|
||||
if (err < 0) {
|
||||
pr_err("Cannot register chrdev: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
err = class_register(&universe_class);
|
||||
if (err) {
|
||||
pr_err("Cannot register universe class: %d\n", err);
|
||||
goto out_chrdev;
|
||||
}
|
||||
my_universe = device_create(&universe_class, NULL, MKDEV(sst_chrdev_major, 0), NULL, SST_CHRDEV);
|
||||
if (IS_ERR(my_universe)) {
|
||||
err = PTR_ERR(my_universe);
|
||||
pr_err("Cannot create device: %d\n", err);
|
||||
goto out_class;
|
||||
}
|
||||
err = sst_init();
|
||||
if (err) {
|
||||
pr_err("Cannot init sst_common: %d\n", err);
|
||||
goto out_device;
|
||||
}
|
||||
pr_notice("Loaded module %s\n", KBUILD_MODNAME);
|
||||
return 0;
|
||||
|
||||
out_device:
|
||||
device_destroy(&universe_class, MKDEV(sst_chrdev_major, 0));
|
||||
out_class:
|
||||
class_unregister(&universe_class);
|
||||
out_chrdev:
|
||||
unregister_chrdev(sst_chrdev_major, SST_CHRDEV);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit sst_chrdev_exit(void) {
|
||||
sst_destroy();
|
||||
device_destroy(&universe_class, MKDEV(sst_chrdev_major, 0));
|
||||
class_unregister(&universe_class);
|
||||
unregister_chrdev(sst_chrdev_major, SST_CHRDEV);
|
||||
pr_notice("Unloaded module %s\n", KBUILD_MODNAME);
|
||||
}
|
||||
|
||||
module_init(sst_chrdev_init);
|
||||
module_exit(sst_chrdev_exit);
|
||||
MODULE_LICENSE("LGPL");
|
186
drivers/sst/sst_common.c
Normal file
186
drivers/sst/sst_common.c
Normal file
@ -0,0 +1,186 @@
|
||||
#include "sst_internal.h"
|
||||
#include "../../include/linux/spinlock.h"
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static sst_info_t *cur_sst_info = NULL;
|
||||
static char an_answer[] = "You shall ask a question!\n";
|
||||
|
||||
char *sst_questions[SST_MAX_QUESTIONS] = {
|
||||
"What is the answer to the Ultimate Question of Life, The Universe, and Everything?",
|
||||
"What do you get if you multiply six by nine?"
|
||||
};
|
||||
EXPORT_SYMBOL(sst_questions);
|
||||
|
||||
char *sst_answers[SST_MAX_ANSWERS] = {
|
||||
"42!\n",
|
||||
"Six by nine. Forty two.\n",
|
||||
"Flash!, a-ah. Savior of the Universe. Flash!, a-ah.\n"
|
||||
};
|
||||
EXPORT_SYMBOL(sst_answers);
|
||||
|
||||
sst_info_t* get_sst_info(void) {
|
||||
return cur_sst_info;
|
||||
}
|
||||
EXPORT_SYMBOL(get_sst_info);
|
||||
|
||||
static int control_thread_work(void *data) {
|
||||
sst_info_t *info = (sst_info_t*)data;
|
||||
int err, i;
|
||||
#if 0
|
||||
int sleep = 0;
|
||||
#endif
|
||||
size_t len_answer = 0, len_question = 0;
|
||||
char *question = NULL, *answer = NULL, *my_answer = NULL;
|
||||
|
||||
sst_debug("Using data at 0x%lx\n", (uintptr_t)info);
|
||||
while(1) {
|
||||
wait_event_interruptible(info->wait, !is_empty(&info->questions));
|
||||
if (kthread_should_stop()) {
|
||||
break;
|
||||
}
|
||||
err = sst_consume_question(info, &question);
|
||||
if (err) {
|
||||
pr_err("Questions was empty!\n");
|
||||
continue;
|
||||
} else if (question == NULL) {
|
||||
pr_err("Question is NULL although ret value is 0.\n");
|
||||
continue;
|
||||
} else {
|
||||
sst_debug("Received msg '%s' at 0x%lx\n", question, (uintptr_t)question);
|
||||
}
|
||||
len_question = strlen(question);
|
||||
if (len_question > 2 && (question[len_question - 1] == '?' ||
|
||||
(question[len_question - 1] == '\n' && question[len_question - 2] == '?'))) {
|
||||
my_answer = sst_answers[0];
|
||||
for (i = 0; i < SST_MAX_QUESTIONS; i++) {
|
||||
if (strcmp(question, sst_questions[i]) == 0) {
|
||||
my_answer = sst_answers[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
my_answer = an_answer;
|
||||
}
|
||||
len_answer = strlen(my_answer) + 1;
|
||||
answer = kmalloc(len_answer, GFP_KERNEL);
|
||||
if (!answer) {
|
||||
pr_err("Cannot allocate memory for answer!\n");
|
||||
kfree(question);
|
||||
continue;
|
||||
}
|
||||
snprintf(answer, len_answer, "%s", my_answer);
|
||||
if (sst_produce_answer(info, answer)) {
|
||||
pr_err("Answers is full!\n");
|
||||
kfree(answer);
|
||||
} else {
|
||||
sst_debug("The universe has an answer at 0x%lx for you!\n", (uintptr_t)answer);
|
||||
}
|
||||
#if 0
|
||||
sleep = get_random_u8() % 90;
|
||||
sst_debug("Randomly sleeping for %d secs. ZzzzZZzz\n", sleep);
|
||||
ssleep(sleep);
|
||||
#endif
|
||||
kfree(question);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sst_init(void) {
|
||||
cur_sst_info = kmalloc(sizeof(*cur_sst_info), GFP_KERNEL);
|
||||
if (!cur_sst_info) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
spin_lock_init(&cur_sst_info->lock_questions);
|
||||
spin_lock_init(&cur_sst_info->lock_answers);
|
||||
sema_init(&cur_sst_info->answers_rdy, 0);
|
||||
init_waitqueue_head(&cur_sst_info->wait);
|
||||
init_bbuffer(&cur_sst_info->answers);
|
||||
init_bbuffer(&cur_sst_info->questions);
|
||||
sst_debug("Allocated private data for the universe at [0x%lx,0x%lx]\n", (uintptr_t)cur_sst_info, (uintptr_t)((uintptr_t)cur_sst_info + sizeof(*cur_sst_info)));
|
||||
cur_sst_info->thread = kthread_create(control_thread_work, get_sst_info(), "sst-worker-%d", 1);
|
||||
if (IS_ERR(cur_sst_info->thread)) {
|
||||
kfree(cur_sst_info);
|
||||
return -EFAULT;
|
||||
}
|
||||
wake_up_process(cur_sst_info->thread);
|
||||
sst_debug("Created and started control thread (%d)\n", cur_sst_info->thread->pid);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sst_init);
|
||||
|
||||
void sst_destroy(void) {
|
||||
sst_debug("Waiting for control thread (%d) to terminate...\n", cur_sst_info->thread->pid);
|
||||
kthread_stop(cur_sst_info->thread);
|
||||
sst_debug("Control thread (%d) terminated.\n", cur_sst_info->thread->pid);
|
||||
kfree(cur_sst_info);
|
||||
sst_debug("Freed private data for the universe at 0x%lx\n", (uintptr_t)cur_sst_info);
|
||||
};
|
||||
EXPORT_SYMBOL(sst_destroy);
|
||||
|
||||
int sst_produce_question(sst_info_t *info, char *value) {
|
||||
int err = 0;
|
||||
|
||||
if (!info) {
|
||||
return -1;
|
||||
}
|
||||
sst_debug("%s:info=%lx, questions=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->questions);
|
||||
spin_lock_bh(&info->lock_questions);
|
||||
err = produce(&info->questions, value);
|
||||
spin_unlock_bh(&info->lock_questions);
|
||||
if (!err) {
|
||||
wake_up_interruptible(&info->wait);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(sst_produce_question);
|
||||
|
||||
int sst_produce_answer(sst_info_t *info, char *value) {
|
||||
int err = 0;
|
||||
unsigned long flags;
|
||||
if (!info) {
|
||||
return -1;
|
||||
}
|
||||
sst_debug("%s:info=%lx, answers=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->answers);
|
||||
spin_lock_irqsave(&info->lock_answers, flags);
|
||||
err = produce(&info->answers, value);
|
||||
spin_unlock_irqrestore(&info->lock_answers, flags);
|
||||
up(&info->answers_rdy);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(sst_produce_answer);
|
||||
|
||||
int sst_consume_question(sst_info_t *info, char **value) {
|
||||
int err = 0;
|
||||
if (!info) {
|
||||
return -1;
|
||||
}
|
||||
sst_debug("%s:info=%lx, questions=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->questions);
|
||||
spin_lock_bh(&info->lock_questions);
|
||||
err = consume(&info->questions, value);
|
||||
spin_unlock_bh(&info->lock_questions);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(sst_consume_question);
|
||||
|
||||
int sst_consume_answer(sst_info_t *info, char **value) {
|
||||
int err = 0;
|
||||
unsigned long flags;
|
||||
if (!info) {
|
||||
return -1;
|
||||
}
|
||||
sst_debug("%s:info=%lx, answers=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->answers);
|
||||
if (down_trylock(&info->answers_rdy)) {
|
||||
sst_debug("Sry. No answer for you!\n");
|
||||
return -2;
|
||||
}
|
||||
spin_lock_irqsave(&info->lock_answers, flags);
|
||||
err = consume(&info->answers, value);
|
||||
spin_unlock_irqrestore(&info->lock_answers, flags);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(sst_consume_answer);
|
30
drivers/sst/sst_internal.h
Normal file
30
drivers/sst/sst_internal.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef __SST_INTERNAL_H__
|
||||
#define __SST_INTERNAL_H__
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/printk.h>
|
||||
#define sst_debug(format, ...) \
|
||||
pr_debug("(file:%s,line:%d,pid:%d): " format, \
|
||||
__FILE__, __LINE__, \
|
||||
current->pid, ##__VA_ARGS__)
|
||||
|
||||
#include <linux/sst.h>
|
||||
#define BOUNDEDBUFFER_SIZE 20
|
||||
#define BOUNDEDBUFFER_STORAGE_TYPE char*
|
||||
#include "boundedbuffer.h"
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
struct sst_info {
|
||||
struct boundedbuffer questions;
|
||||
struct semaphore answers_rdy;
|
||||
struct boundedbuffer answers;
|
||||
struct task_struct *thread;
|
||||
wait_queue_head_t wait;
|
||||
spinlock_t lock_questions;
|
||||
spinlock_t lock_answers;
|
||||
};
|
||||
typedef struct sst_info sst_info_t;
|
||||
|
||||
#endif // __SST_INTERNAL_H__
|
17
include/linux/sst.h
Normal file
17
include/linux/sst.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef __SST_H__
|
||||
#define __SST_H__
|
||||
|
||||
#define SST_MAX_QUESTIONS 2
|
||||
extern char *sst_questions[SST_MAX_QUESTIONS];
|
||||
#define SST_MAX_ANSWERS 3
|
||||
extern char *sst_answers[SST_MAX_ANSWERS];
|
||||
struct sst_info;
|
||||
|
||||
int sst_init(void);
|
||||
void sst_destroy(void);
|
||||
struct sst_info* get_sst_info(void);
|
||||
int sst_produce_question(struct sst_info *info, char *value);
|
||||
int sst_produce_answer(struct sst_info *info, char *value);
|
||||
int sst_consume_question(struct sst_info *info, char **value);
|
||||
int sst_consume_answer(struct sst_info *info, char **value);
|
||||
#endif // __SST_H__
|
@ -45,6 +45,8 @@
|
||||
#include <linux/compat.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/sst.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/unistd.h>
|
||||
@ -1840,6 +1842,10 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h)
|
||||
*/
|
||||
static void run_local_timers(void)
|
||||
{
|
||||
#ifdef CONFIG_SST_LOCKING
|
||||
static unsigned long next_time = 0;
|
||||
char *answer = NULL;
|
||||
#endif
|
||||
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
|
||||
|
||||
hrtimer_run_queues();
|
||||
@ -1852,6 +1858,19 @@ static void run_local_timers(void)
|
||||
if (time_before(jiffies, base->next_expiry))
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_SST_LOCKING
|
||||
if (next_time == 0) {
|
||||
next_time = msecs_to_jiffies(65000) + jiffies;
|
||||
} else if (time_after_eq(jiffies, next_time)) {
|
||||
pr_debug("sst: Sending a random answer\n");
|
||||
next_time = msecs_to_jiffies((get_random_u8() % 100) * 1000 + 15000) + jiffies;
|
||||
answer = kmalloc(sizeof(char) * 100, GFP_NOWAIT);
|
||||
if (answer) {
|
||||
snprintf(answer, 100, sst_answers[(get_random_u8() % SST_MAX_ANSWERS)]);
|
||||
sst_produce_answer(get_sst_info(), answer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
raise_softirq(TIMER_SOFTIRQ);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user