futex adaptation from Linux 2.6.34 (Intel MPSS Linux)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
IHKDIR=$(IHKBASE)/$(TARGETDIR)
|
IHKDIR=$(IHKBASE)/$(TARGETDIR)
|
||||||
OBJS = init.o mem.o debug.o mikc.o listeners.o ap.o syscall.o cls.o host.o
|
OBJS = init.o mem.o debug.o mikc.o listeners.o ap.o syscall.o cls.o host.o
|
||||||
OBJS += process.o copy.o waitq.o futex.o timer.o
|
OBJS += process.o copy.o waitq.o futex.o timer.o plist.o
|
||||||
DEPSRCS=$(wildcard $(SRC)/*.c)
|
DEPSRCS=$(wildcard $(SRC)/*.c)
|
||||||
|
|
||||||
CFLAGS += -I$(SRC)/include -mcmodel=kernel -D__KERNEL__
|
CFLAGS += -I$(SRC)/include -mcmodel=kernel -D__KERNEL__
|
||||||
|
|||||||
1048
kernel/futex.c
1048
kernel/futex.c
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,50 @@
|
|||||||
/* Kitten LWK futex adaptation */
|
/*
|
||||||
|
* Linux futex adaptation.
|
||||||
|
* (C) Copyright 2013 RIKEN AICS
|
||||||
|
* Balazs Gerofi <bgerofi@riken.jp>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FUTEX_H
|
||||||
#ifndef _LWK_FUTEX_H
|
#define _FUTEX_H
|
||||||
#define _LWK_FUTEX_H
|
|
||||||
|
|
||||||
/** \name Futex Commands
|
/** \name Futex Commands
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
#define FUTEX_WAIT 0
|
#define FUTEX_WAIT 0
|
||||||
#define FUTEX_WAKE 1
|
#define FUTEX_WAKE 1
|
||||||
|
#define FUTEX_FD 2
|
||||||
|
#define FUTEX_REQUEUE 3
|
||||||
#define FUTEX_CMP_REQUEUE 4
|
#define FUTEX_CMP_REQUEUE 4
|
||||||
#define FUTEX_WAKE_OP 5
|
#define FUTEX_WAKE_OP 5
|
||||||
|
#define FUTEX_LOCK_PI 6
|
||||||
|
#define FUTEX_UNLOCK_PI 7
|
||||||
|
#define FUTEX_TRYLOCK_PI 8
|
||||||
#define FUTEX_WAIT_BITSET 9
|
#define FUTEX_WAIT_BITSET 9
|
||||||
#define FUTEX_WAKE_BITSET 10
|
#define FUTEX_WAKE_BITSET 10
|
||||||
|
#define FUTEX_WAIT_REQUEUE_PI 11
|
||||||
|
#define FUTEX_CMP_REQUEUE_PI 12
|
||||||
// @}
|
// @}
|
||||||
|
|
||||||
#define FUTEX_PRIVATE_FLAG 128
|
#define FUTEX_PRIVATE_FLAG 128
|
||||||
#define FUTEX_CLOCK_REALTIME 256
|
#define FUTEX_CLOCK_REALTIME 256
|
||||||
#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
|
#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
|
||||||
|
|
||||||
|
#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
|
||||||
|
#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
|
||||||
|
#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG)
|
||||||
|
#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG)
|
||||||
|
#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG)
|
||||||
|
#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
|
||||||
|
#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
|
||||||
|
#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
|
||||||
|
#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG)
|
||||||
|
#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG)
|
||||||
|
#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \
|
||||||
|
FUTEX_PRIVATE_FLAG)
|
||||||
|
#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \
|
||||||
|
FUTEX_PRIVATE_FLAG)
|
||||||
|
|
||||||
|
|
||||||
/** \name Futex Operations, used for FUTEX_WAKE_OP
|
/** \name Futex Operations, used for FUTEX_WAKE_OP
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
@@ -201,30 +227,34 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
|
|||||||
|
|
||||||
#define FUTEX_HASHBITS 8 /* 256 entries in each futex hash tbl */
|
#define FUTEX_HASHBITS 8 /* 256 entries in each futex hash tbl */
|
||||||
|
|
||||||
/** Futex tracking structure.
|
#define FUT_OFF_INODE 1 /* We set bit 0 if key has a reference on inode */
|
||||||
*
|
#define FUT_OFF_MMSHARED 2 /* We set bit 1 if key has a reference on mm */
|
||||||
* A futex has a woken state, just like tasks have TASK_RUNNING.
|
|
||||||
* It is considered woken when list_empty(&futex->link) || futex->lock_ptr == 0.
|
struct process_vm;
|
||||||
* The order of wakup is always to make the first condition true, then
|
|
||||||
* wake up futex->waitq, then make the second condition true.
|
union futex_key {
|
||||||
*/
|
#if 0
|
||||||
struct futex {
|
struct {
|
||||||
struct list_head link;
|
unsigned long pgoff;
|
||||||
struct waitq waitq;
|
struct inode *inode;
|
||||||
ihk_spinlock_t * lock_ptr;
|
int offset;
|
||||||
uint32_t __user * uaddr;
|
} shared;
|
||||||
uint32_t bitset;
|
#endif
|
||||||
|
struct {
|
||||||
|
unsigned long address;
|
||||||
|
struct process_vm *mm;
|
||||||
|
int offset;
|
||||||
|
} private;
|
||||||
|
struct {
|
||||||
|
unsigned long word;
|
||||||
|
void *ptr;
|
||||||
|
int offset;
|
||||||
|
} both;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct futex_queue {
|
#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = NULL } }
|
||||||
ihk_spinlock_t lock;
|
|
||||||
struct list_head futex_list;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void
|
extern int futex_init(void);
|
||||||
futex_queue_init(
|
|
||||||
struct futex_queue * queue
|
|
||||||
);
|
|
||||||
|
|
||||||
extern int
|
extern int
|
||||||
futex(
|
futex(
|
||||||
|
|||||||
145
kernel/include/jhash.h
Normal file
145
kernel/include/jhash.h
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
#ifndef _LINUX_JHASH_H
|
||||||
|
#define _LINUX_JHASH_H
|
||||||
|
|
||||||
|
/* RIKEN: u32 replaced to uint32_t
|
||||||
|
*
|
||||||
|
* jhash.h: Jenkins hash support.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
|
||||||
|
*
|
||||||
|
* http://burtleburtle.net/bob/hash/
|
||||||
|
*
|
||||||
|
* These are the credits from Bob's sources:
|
||||||
|
*
|
||||||
|
* lookup2.c, by Bob Jenkins, December 1996, Public Domain.
|
||||||
|
* hash(), hash2(), hash3, and mix() are externally useful functions.
|
||||||
|
* Routines to test the hash are included if SELF_TEST is defined.
|
||||||
|
* You can use this free for any purpose. It has no warranty.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2003 David S. Miller (davem@redhat.com)
|
||||||
|
*
|
||||||
|
* I've modified Bob's hash to be useful in the Linux kernel, and
|
||||||
|
* any bugs present are surely my fault. -DaveM
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* NOTE: Arguments are modified. */
|
||||||
|
#define __jhash_mix(a, b, c) \
|
||||||
|
{ \
|
||||||
|
a -= b; a -= c; a ^= (c>>13); \
|
||||||
|
b -= c; b -= a; b ^= (a<<8); \
|
||||||
|
c -= a; c -= b; c ^= (b>>13); \
|
||||||
|
a -= b; a -= c; a ^= (c>>12); \
|
||||||
|
b -= c; b -= a; b ^= (a<<16); \
|
||||||
|
c -= a; c -= b; c ^= (b>>5); \
|
||||||
|
a -= b; a -= c; a ^= (c>>3); \
|
||||||
|
b -= c; b -= a; b ^= (a<<10); \
|
||||||
|
c -= a; c -= b; c ^= (b>>15); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The golden ration: an arbitrary value */
|
||||||
|
#define JHASH_GOLDEN_RATIO 0x9e3779b9
|
||||||
|
|
||||||
|
/* The most generic version, hashes an arbitrary sequence
|
||||||
|
* of bytes. No alignment or length assumptions are made about
|
||||||
|
* the input key.
|
||||||
|
*/
|
||||||
|
static inline uint32_t jhash(const void *key, uint32_t length, uint32_t initval)
|
||||||
|
{
|
||||||
|
uint32_t a, b, c, len;
|
||||||
|
const uint8_t *k = key;
|
||||||
|
|
||||||
|
len = length;
|
||||||
|
a = b = JHASH_GOLDEN_RATIO;
|
||||||
|
c = initval;
|
||||||
|
|
||||||
|
while (len >= 12) {
|
||||||
|
a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24));
|
||||||
|
b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24));
|
||||||
|
c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24));
|
||||||
|
|
||||||
|
__jhash_mix(a,b,c);
|
||||||
|
|
||||||
|
k += 12;
|
||||||
|
len -= 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
c += length;
|
||||||
|
switch (len) {
|
||||||
|
case 11: c += ((uint32_t)k[10]<<24);
|
||||||
|
case 10: c += ((uint32_t)k[9]<<16);
|
||||||
|
case 9 : c += ((uint32_t)k[8]<<8);
|
||||||
|
case 8 : b += ((uint32_t)k[7]<<24);
|
||||||
|
case 7 : b += ((uint32_t)k[6]<<16);
|
||||||
|
case 6 : b += ((uint32_t)k[5]<<8);
|
||||||
|
case 5 : b += k[4];
|
||||||
|
case 4 : a += ((uint32_t)k[3]<<24);
|
||||||
|
case 3 : a += ((uint32_t)k[2]<<16);
|
||||||
|
case 2 : a += ((uint32_t)k[1]<<8);
|
||||||
|
case 1 : a += k[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
__jhash_mix(a,b,c);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A special optimized version that handles 1 or more of uint32_ts.
|
||||||
|
* The length parameter here is the number of uint32_ts in the key.
|
||||||
|
*/
|
||||||
|
static inline uint32_t jhash2(const uint32_t *k, uint32_t length, uint32_t initval)
|
||||||
|
{
|
||||||
|
uint32_t a, b, c, len;
|
||||||
|
|
||||||
|
a = b = JHASH_GOLDEN_RATIO;
|
||||||
|
c = initval;
|
||||||
|
len = length;
|
||||||
|
|
||||||
|
while (len >= 3) {
|
||||||
|
a += k[0];
|
||||||
|
b += k[1];
|
||||||
|
c += k[2];
|
||||||
|
__jhash_mix(a, b, c);
|
||||||
|
k += 3; len -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
c += length * 4;
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 2 : b += k[1];
|
||||||
|
case 1 : a += k[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
__jhash_mix(a,b,c);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* A special ultra-optimized versions that knows they are hashing exactly
|
||||||
|
* 3, 2 or 1 word(s).
|
||||||
|
*
|
||||||
|
* NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
|
||||||
|
* done at the end is not done here.
|
||||||
|
*/
|
||||||
|
static inline uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, uint32_t initval)
|
||||||
|
{
|
||||||
|
a += JHASH_GOLDEN_RATIO;
|
||||||
|
b += JHASH_GOLDEN_RATIO;
|
||||||
|
c += initval;
|
||||||
|
|
||||||
|
__jhash_mix(a, b, c);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval)
|
||||||
|
{
|
||||||
|
return jhash_3words(a, b, 0, initval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t jhash_1word(uint32_t a, uint32_t initval)
|
||||||
|
{
|
||||||
|
return jhash_3words(a, 0, 0, initval);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _LINUX_JHASH_H */
|
||||||
273
kernel/include/plist.h
Normal file
273
kernel/include/plist.h
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
/*
|
||||||
|
* Descending-priority-sorted double-linked list
|
||||||
|
*
|
||||||
|
* (C) 2002-2003 Intel Corp
|
||||||
|
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
|
||||||
|
*
|
||||||
|
* 2001-2005 (c) MontaVista Software, Inc.
|
||||||
|
* Daniel Walker <dwalker@mvista.com>
|
||||||
|
*
|
||||||
|
* (C) 2005 Thomas Gleixner <tglx@linutronix.de>
|
||||||
|
*
|
||||||
|
* Simplifications of the original code by
|
||||||
|
* Oleg Nesterov <oleg@tv-sign.ru>
|
||||||
|
*
|
||||||
|
* Licensed under the FSF's GNU Public License v2 or later.
|
||||||
|
*
|
||||||
|
* Based on simple lists (include/linux/list.h).
|
||||||
|
*
|
||||||
|
* This is a priority-sorted list of nodes; each node has a
|
||||||
|
* priority from INT_MIN (highest) to INT_MAX (lowest).
|
||||||
|
*
|
||||||
|
* Addition is O(K), removal is O(1), change of priority of a node is
|
||||||
|
* O(K) and K is the number of RT priority levels used in the system.
|
||||||
|
* (1 <= K <= 99)
|
||||||
|
*
|
||||||
|
* This list is really a list of lists:
|
||||||
|
*
|
||||||
|
* - The tier 1 list is the prio_list, different priority nodes.
|
||||||
|
*
|
||||||
|
* - The tier 2 list is the node_list, serialized nodes.
|
||||||
|
*
|
||||||
|
* Simple ASCII art explanation:
|
||||||
|
*
|
||||||
|
* |HEAD |
|
||||||
|
* | |
|
||||||
|
* |prio_list.prev|<------------------------------------|
|
||||||
|
* |prio_list.next|<->|pl|<->|pl|<--------------->|pl|<-|
|
||||||
|
* |10 | |10| |21| |21| |21| |40| (prio)
|
||||||
|
* | | | | | | | | | | | |
|
||||||
|
* | | | | | | | | | | | |
|
||||||
|
* |node_list.next|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-|
|
||||||
|
* |node_list.prev|<------------------------------------|
|
||||||
|
*
|
||||||
|
* The nodes on the prio_list list are sorted by priority to simplify
|
||||||
|
* the insertion of new nodes. There are no nodes with duplicate
|
||||||
|
* priorites on the list.
|
||||||
|
*
|
||||||
|
* The nodes on the node_list are ordered by priority and can contain
|
||||||
|
* entries which have the same priority. Those entries are ordered
|
||||||
|
* FIFO
|
||||||
|
*
|
||||||
|
* Addition means: look for the prio_list node in the prio_list
|
||||||
|
* for the priority of the node and insert it before the node_list
|
||||||
|
* entry of the next prio_list node. If it is the first node of
|
||||||
|
* that priority, add it to the prio_list in the right position and
|
||||||
|
* insert it into the serialized node_list list
|
||||||
|
*
|
||||||
|
* Removal means remove it from the node_list and remove it from
|
||||||
|
* the prio_list if the node_list list_head is non empty. In case
|
||||||
|
* of removal from the prio_list it must be checked whether other
|
||||||
|
* entries of the same priority are on the list or not. If there
|
||||||
|
* is another entry of the same priority then this entry has to
|
||||||
|
* replace the removed entry on the prio_list. If the entry which
|
||||||
|
* is removed is the only entry of this priority then a simple
|
||||||
|
* remove from both list is sufficient.
|
||||||
|
*
|
||||||
|
* INT_MIN is the highest priority, 0 is the medium highest, INT_MAX
|
||||||
|
* is lowest priority.
|
||||||
|
*
|
||||||
|
* No locking is done, up to the caller.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef _LINUX_PLIST_H_
|
||||||
|
#define _LINUX_PLIST_H_
|
||||||
|
|
||||||
|
#include <ihk/lock.h>
|
||||||
|
#include <list.h>
|
||||||
|
|
||||||
|
struct plist_head {
|
||||||
|
struct list_head prio_list;
|
||||||
|
struct list_head node_list;
|
||||||
|
#ifdef CONFIG_DEBUG_PI_LIST
|
||||||
|
raw_spinlock_t *rawlock;
|
||||||
|
spinlock_t *spinlock;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct plist_node {
|
||||||
|
int prio;
|
||||||
|
struct plist_head plist;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_PI_LIST
|
||||||
|
# define PLIST_HEAD_LOCK_INIT(_lock) .spinlock = _lock
|
||||||
|
# define PLIST_HEAD_LOCK_INIT_RAW(_lock) .rawlock = _lock
|
||||||
|
#else
|
||||||
|
# define PLIST_HEAD_LOCK_INIT(_lock)
|
||||||
|
# define PLIST_HEAD_LOCK_INIT_RAW(_lock)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _PLIST_HEAD_INIT(head) \
|
||||||
|
.prio_list = LIST_HEAD_INIT((head).prio_list), \
|
||||||
|
.node_list = LIST_HEAD_INIT((head).node_list)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PLIST_HEAD_INIT - static struct plist_head initializer
|
||||||
|
* @head: struct plist_head variable name
|
||||||
|
* @_lock: lock to initialize for this list
|
||||||
|
*/
|
||||||
|
#define PLIST_HEAD_INIT(head, _lock) \
|
||||||
|
{ \
|
||||||
|
_PLIST_HEAD_INIT(head), \
|
||||||
|
PLIST_HEAD_LOCK_INIT(&(_lock)) \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PLIST_HEAD_INIT_RAW - static struct plist_head initializer
|
||||||
|
* @head: struct plist_head variable name
|
||||||
|
* @_lock: lock to initialize for this list
|
||||||
|
*/
|
||||||
|
#define PLIST_HEAD_INIT_RAW(head, _lock) \
|
||||||
|
{ \
|
||||||
|
_PLIST_HEAD_INIT(head), \
|
||||||
|
PLIST_HEAD_LOCK_INIT_RAW(&(_lock)) \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PLIST_NODE_INIT - static struct plist_node initializer
|
||||||
|
* @node: struct plist_node variable name
|
||||||
|
* @__prio: initial node priority
|
||||||
|
*/
|
||||||
|
#define PLIST_NODE_INIT(node, __prio) \
|
||||||
|
{ \
|
||||||
|
.prio = (__prio), \
|
||||||
|
.plist = { _PLIST_HEAD_INIT((node).plist) }, \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_head_init - dynamic struct plist_head initializer
|
||||||
|
* @head: &struct plist_head pointer
|
||||||
|
* @lock: spinlock protecting the list (debugging)
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
plist_head_init(struct plist_head *head, ihk_spinlock_t *lock)
|
||||||
|
{
|
||||||
|
INIT_LIST_HEAD(&head->prio_list);
|
||||||
|
INIT_LIST_HEAD(&head->node_list);
|
||||||
|
#ifdef CONFIG_DEBUG_PI_LIST
|
||||||
|
head->spinlock = lock;
|
||||||
|
head->rawlock = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_head_init_raw - dynamic struct plist_head initializer
|
||||||
|
* @head: &struct plist_head pointer
|
||||||
|
* @lock: raw_spinlock protecting the list (debugging)
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
plist_head_init_raw(struct plist_head *head, ihk_spinlock_t *lock)
|
||||||
|
{
|
||||||
|
INIT_LIST_HEAD(&head->prio_list);
|
||||||
|
INIT_LIST_HEAD(&head->node_list);
|
||||||
|
#ifdef CONFIG_DEBUG_PI_LIST
|
||||||
|
head->rawlock = lock;
|
||||||
|
head->spinlock = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_node_init - Dynamic struct plist_node initializer
|
||||||
|
* @node: &struct plist_node pointer
|
||||||
|
* @prio: initial node priority
|
||||||
|
*/
|
||||||
|
static inline void plist_node_init(struct plist_node *node, int prio)
|
||||||
|
{
|
||||||
|
node->prio = prio;
|
||||||
|
plist_head_init(&node->plist, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void plist_add(struct plist_node *node, struct plist_head *head);
|
||||||
|
extern void plist_del(struct plist_node *node, struct plist_head *head);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_for_each - iterate over the plist
|
||||||
|
* @pos: the type * to use as a loop counter
|
||||||
|
* @head: the head for your list
|
||||||
|
*/
|
||||||
|
#define plist_for_each(pos, head) \
|
||||||
|
list_for_each_entry(pos, &(head)->node_list, plist.node_list)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_for_each_safe - iterate safely over a plist of given type
|
||||||
|
* @pos: the type * to use as a loop counter
|
||||||
|
* @n: another type * to use as temporary storage
|
||||||
|
* @head: the head for your list
|
||||||
|
*
|
||||||
|
* Iterate over a plist of given type, safe against removal of list entry.
|
||||||
|
*/
|
||||||
|
#define plist_for_each_safe(pos, n, head) \
|
||||||
|
list_for_each_entry_safe(pos, n, &(head)->node_list, plist.node_list)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_for_each_entry - iterate over list of given type
|
||||||
|
* @pos: the type * to use as a loop counter
|
||||||
|
* @head: the head for your list
|
||||||
|
* @mem: the name of the list_struct within the struct
|
||||||
|
*/
|
||||||
|
#define plist_for_each_entry(pos, head, mem) \
|
||||||
|
list_for_each_entry(pos, &(head)->node_list, mem.plist.node_list)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_for_each_entry_safe - iterate safely over list of given type
|
||||||
|
* @pos: the type * to use as a loop counter
|
||||||
|
* @n: another type * to use as temporary storage
|
||||||
|
* @head: the head for your list
|
||||||
|
* @m: the name of the list_struct within the struct
|
||||||
|
*
|
||||||
|
* Iterate over list of given type, safe against removal of list entry.
|
||||||
|
*/
|
||||||
|
#define plist_for_each_entry_safe(pos, n, head, m) \
|
||||||
|
list_for_each_entry_safe(pos, n, &(head)->node_list, m.plist.node_list)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_head_empty - return !0 if a plist_head is empty
|
||||||
|
* @head: &struct plist_head pointer
|
||||||
|
*/
|
||||||
|
static inline int plist_head_empty(const struct plist_head *head)
|
||||||
|
{
|
||||||
|
return list_empty(&head->node_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_node_empty - return !0 if plist_node is not on a list
|
||||||
|
* @node: &struct plist_node pointer
|
||||||
|
*/
|
||||||
|
static inline int plist_node_empty(const struct plist_node *node)
|
||||||
|
{
|
||||||
|
return plist_head_empty(&node->plist);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All functions below assume the plist_head is not empty. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_first_entry - get the struct for the first entry
|
||||||
|
* @head: the &struct plist_head pointer
|
||||||
|
* @type: the type of the struct this is embedded in
|
||||||
|
* @member: the name of the list_struct within the struct
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_DEBUG_PI_LIST
|
||||||
|
# define plist_first_entry(head, type, member) \
|
||||||
|
({ \
|
||||||
|
WARN_ON(plist_head_empty(head)); \
|
||||||
|
container_of(plist_first(head), type, member); \
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
# define plist_first_entry(head, type, member) \
|
||||||
|
container_of(plist_first(head), type, member)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_first - return the first node (and thus, highest priority)
|
||||||
|
* @head: the &struct plist_head pointer
|
||||||
|
*
|
||||||
|
* Assumes the plist is _not_ empty.
|
||||||
|
*/
|
||||||
|
static inline struct plist_node *plist_first(const struct plist_head *head)
|
||||||
|
{
|
||||||
|
return list_entry(head->node_list.next,
|
||||||
|
struct plist_node, plist.node_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -73,9 +73,6 @@ struct process_vm {
|
|||||||
struct list_head vm_range_list;
|
struct list_head vm_range_list;
|
||||||
struct vm_regions region;
|
struct vm_regions region;
|
||||||
|
|
||||||
// Address space private futexes
|
|
||||||
struct futex_queue futex_queues[1 << FUTEX_HASHBITS];
|
|
||||||
|
|
||||||
ihk_spinlock_t page_table_lock;
|
ihk_spinlock_t page_table_lock;
|
||||||
ihk_spinlock_t memory_range_lock;
|
ihk_spinlock_t memory_range_lock;
|
||||||
// to protect the followings:
|
// to protect the followings:
|
||||||
|
|||||||
@@ -216,6 +216,8 @@ int main(void)
|
|||||||
|
|
||||||
post_init();
|
post_init();
|
||||||
|
|
||||||
|
futex_init();
|
||||||
|
|
||||||
kputs("MCK/IHK booted.\n");
|
kputs("MCK/IHK booted.\n");
|
||||||
|
|
||||||
#ifdef DCFA_KMOD
|
#ifdef DCFA_KMOD
|
||||||
|
|||||||
123
kernel/plist.c
Normal file
123
kernel/plist.c
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* lib/plist.c
|
||||||
|
*
|
||||||
|
* Descending-priority-sorted double-linked list
|
||||||
|
*
|
||||||
|
* (C) 2002-2003 Intel Corp
|
||||||
|
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
|
||||||
|
*
|
||||||
|
* 2001-2005 (c) MontaVista Software, Inc.
|
||||||
|
* Daniel Walker <dwalker@mvista.com>
|
||||||
|
*
|
||||||
|
* (C) 2005 Thomas Gleixner <tglx@linutronix.de>
|
||||||
|
*
|
||||||
|
* Simplifications of the original code by
|
||||||
|
* Oleg Nesterov <oleg@tv-sign.ru>
|
||||||
|
*
|
||||||
|
* Licensed under the FSF's GNU Public License v2 or later.
|
||||||
|
*
|
||||||
|
* Based on simple lists (include/linux/list.h).
|
||||||
|
*
|
||||||
|
* This file contains the add / del functions which are considered to
|
||||||
|
* be too large to inline. See include/linux/plist.h for further
|
||||||
|
* information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <plist.h>
|
||||||
|
#include <ihk/lock.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_PI_LIST
|
||||||
|
|
||||||
|
static void plist_check_prev_next(struct list_head *t, struct list_head *p,
|
||||||
|
struct list_head *n)
|
||||||
|
{
|
||||||
|
WARN(n->prev != p || p->next != n,
|
||||||
|
"top: %p, n: %p, p: %p\n"
|
||||||
|
"prev: %p, n: %p, p: %p\n"
|
||||||
|
"next: %p, n: %p, p: %p\n",
|
||||||
|
t, t->next, t->prev,
|
||||||
|
p, p->next, p->prev,
|
||||||
|
n, n->next, n->prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void plist_check_list(struct list_head *top)
|
||||||
|
{
|
||||||
|
struct list_head *prev = top, *next = top->next;
|
||||||
|
|
||||||
|
plist_check_prev_next(top, prev, next);
|
||||||
|
while (next != top) {
|
||||||
|
prev = next;
|
||||||
|
next = prev->next;
|
||||||
|
plist_check_prev_next(top, prev, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void plist_check_head(struct plist_head *head)
|
||||||
|
{
|
||||||
|
WARN_ON(!head->rawlock && !head->spinlock);
|
||||||
|
if (head->rawlock)
|
||||||
|
WARN_ON_SMP(!raw_spin_is_locked(head->rawlock));
|
||||||
|
if (head->spinlock)
|
||||||
|
WARN_ON_SMP(!spin_is_locked(head->spinlock));
|
||||||
|
plist_check_list(&head->prio_list);
|
||||||
|
plist_check_list(&head->node_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
# define plist_check_head(h) do { } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_add - add @node to @head
|
||||||
|
*
|
||||||
|
* @node: &struct plist_node pointer
|
||||||
|
* @head: &struct plist_head pointer
|
||||||
|
*/
|
||||||
|
void plist_add(struct plist_node *node, struct plist_head *head)
|
||||||
|
{
|
||||||
|
struct plist_node *iter;
|
||||||
|
|
||||||
|
plist_check_head(head);
|
||||||
|
#if 0
|
||||||
|
WARN_ON(!plist_node_empty(node));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
list_for_each_entry(iter, &head->prio_list, plist.prio_list) {
|
||||||
|
if (node->prio < iter->prio)
|
||||||
|
goto lt_prio;
|
||||||
|
else if (node->prio == iter->prio) {
|
||||||
|
iter = list_entry(iter->plist.prio_list.next,
|
||||||
|
struct plist_node, plist.prio_list);
|
||||||
|
goto eq_prio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lt_prio:
|
||||||
|
list_add_tail(&node->plist.prio_list, &iter->plist.prio_list);
|
||||||
|
eq_prio:
|
||||||
|
list_add_tail(&node->plist.node_list, &iter->plist.node_list);
|
||||||
|
|
||||||
|
plist_check_head(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plist_del - Remove a @node from plist.
|
||||||
|
*
|
||||||
|
* @node: &struct plist_node pointer - entry to be removed
|
||||||
|
* @head: &struct plist_head pointer - list head
|
||||||
|
*/
|
||||||
|
void plist_del(struct plist_node *node, struct plist_head *head)
|
||||||
|
{
|
||||||
|
plist_check_head(head);
|
||||||
|
|
||||||
|
if (!list_empty(&node->plist.prio_list)) {
|
||||||
|
struct plist_node *next = plist_first(&node->plist);
|
||||||
|
|
||||||
|
list_move_tail(&next->plist.prio_list, &node->plist.prio_list);
|
||||||
|
list_del_init(&node->plist.prio_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del_init(&node->plist.node_list);
|
||||||
|
|
||||||
|
plist_check_head(head);
|
||||||
|
}
|
||||||
@@ -19,25 +19,18 @@
|
|||||||
|
|
||||||
|
|
||||||
#define USER_STACK_NR_PAGES 8192
|
#define USER_STACK_NR_PAGES 8192
|
||||||
#define KERNEL_STACK_NR_PAGES 16
|
#define KERNEL_STACK_NR_PAGES 24
|
||||||
|
|
||||||
extern long do_arch_prctl(unsigned long code, unsigned long address);
|
extern long do_arch_prctl(unsigned long code, unsigned long address);
|
||||||
|
|
||||||
void init_process_vm(struct process_vm *vm)
|
void init_process_vm(struct process_vm *vm)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
ihk_mc_spinlock_init(&vm->memory_range_lock);
|
ihk_mc_spinlock_init(&vm->memory_range_lock);
|
||||||
ihk_mc_spinlock_init(&vm->page_table_lock);
|
ihk_mc_spinlock_init(&vm->page_table_lock);
|
||||||
|
|
||||||
ihk_atomic_set(&vm->refcount, 1);
|
ihk_atomic_set(&vm->refcount, 1);
|
||||||
INIT_LIST_HEAD(&vm->vm_range_list);
|
INIT_LIST_HEAD(&vm->vm_range_list);
|
||||||
vm->page_table = ihk_mc_pt_create();
|
vm->page_table = ihk_mc_pt_create();
|
||||||
|
|
||||||
/* Initialize futex queues */
|
|
||||||
for (i = 0; i < (1 << FUTEX_HASHBITS); ++i)
|
|
||||||
futex_queue_init(&vm->futex_queues[i]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct process *create_process(unsigned long user_pc)
|
struct process *create_process(unsigned long user_pc)
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ SYSCALL_DECLARE(exit_group)
|
|||||||
SYSCALL_DECLARE(mmap)
|
SYSCALL_DECLARE(mmap)
|
||||||
{
|
{
|
||||||
struct vm_regions *region = &cpu_local_var(current)->vm->region;
|
struct vm_regions *region = &cpu_local_var(current)->vm->region;
|
||||||
unsigned long lockr;
|
unsigned long lockr;
|
||||||
|
|
||||||
dkprintf("syscall.c,mmap,addr=%lx,len=%lx,prot=%lx,flags=%x,fd=%x,offset=%lx\n",
|
dkprintf("syscall.c,mmap,addr=%lx,len=%lx,prot=%lx,flags=%x,fd=%x,offset=%lx\n",
|
||||||
ihk_mc_syscall_arg0(ctx), ihk_mc_syscall_arg1(ctx),
|
ihk_mc_syscall_arg0(ctx), ihk_mc_syscall_arg1(ctx),
|
||||||
@@ -865,14 +865,22 @@ SYSCALL_DECLARE(futex)
|
|||||||
uint32_t *uaddr2 = (uint32_t *)ihk_mc_syscall_arg4(ctx);
|
uint32_t *uaddr2 = (uint32_t *)ihk_mc_syscall_arg4(ctx);
|
||||||
uint32_t val3 = (uint32_t)ihk_mc_syscall_arg5(ctx);
|
uint32_t val3 = (uint32_t)ihk_mc_syscall_arg5(ctx);
|
||||||
|
|
||||||
dkprintf("futex,uaddr=%lx,op=%x, val=%x, utime=%lx, uaddr2=%lx, val3=%x, []=%x\n", (unsigned long)uaddr, op, val, utime, uaddr2, val3, *uaddr);
|
|
||||||
|
|
||||||
/* Mask off the FUTEX_PRIVATE_FLAG,
|
/* Mask off the FUTEX_PRIVATE_FLAG,
|
||||||
* assume all futexes are address space private */
|
* assume all futexes are address space private */
|
||||||
op = (op & FUTEX_CMD_MASK);
|
op = (op & FUTEX_CMD_MASK);
|
||||||
|
|
||||||
|
dkprintf("futex op=[%x, %s],uaddr=%lx, val=%x, utime=%lx, uaddr2=%lx, val3=%x, []=%x\n",
|
||||||
|
op,
|
||||||
|
(op == FUTEX_WAIT) ? "FUTEX_WAIT" :
|
||||||
|
(op == FUTEX_WAIT_BITSET) ? "FUTEX_WAIT_BITSET" :
|
||||||
|
(op == FUTEX_WAKE) ? "FUTEX_WAKE" :
|
||||||
|
(op == FUTEX_WAKE_OP) ? "FUTEX_WAKE_OP" :
|
||||||
|
(op == FUTEX_WAKE_BITSET) ? "FUTEX_WAKE_BITSET" :
|
||||||
|
(op == FUTEX_CMP_REQUEUE) ? "FUTEX_CMP_REQUEUE" :
|
||||||
|
(op == FUTEX_REQUEUE) ? "FUTEX_REQUEUE (NOT IMPL!)" : "unknown",
|
||||||
|
(unsigned long)uaddr, op, val, utime, uaddr2, val3, *uaddr);
|
||||||
|
|
||||||
if (utime && (op == FUTEX_WAIT_BITSET || op == FUTEX_WAIT)) {
|
if (utime && (op == FUTEX_WAIT_BITSET || op == FUTEX_WAIT)) {
|
||||||
/* gettimeofday(&tv_now, NULL) from host */
|
|
||||||
struct syscall_request request IHK_DMA_ALIGN;
|
struct syscall_request request IHK_DMA_ALIGN;
|
||||||
struct timeval tv_now;
|
struct timeval tv_now;
|
||||||
request.number = 96;
|
request.number = 96;
|
||||||
@@ -904,6 +912,7 @@ SYSCALL_DECLARE(futex)
|
|||||||
long diff_nsec = nsec_timeout - nsec_now;
|
long diff_nsec = nsec_timeout - nsec_now;
|
||||||
|
|
||||||
timeout = (diff_nsec / 1000) * 1100; // (usec * 1.1GHz)
|
timeout = (diff_nsec / 1000) * 1100; // (usec * 1.1GHz)
|
||||||
|
dkprintf("futex timeout: %lu\n", timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Requeue parameter in 'utime' if op == FUTEX_CMP_REQUEUE.
|
/* Requeue parameter in 'utime' if op == FUTEX_CMP_REQUEUE.
|
||||||
@@ -911,51 +920,6 @@ SYSCALL_DECLARE(futex)
|
|||||||
if (op == FUTEX_CMP_REQUEUE || op == FUTEX_WAKE_OP)
|
if (op == FUTEX_CMP_REQUEUE || op == FUTEX_WAKE_OP)
|
||||||
val2 = (uint32_t) (unsigned long) ihk_mc_syscall_arg3(ctx);
|
val2 = (uint32_t) (unsigned long) ihk_mc_syscall_arg3(ctx);
|
||||||
|
|
||||||
// we don't have timer interrupt and wakeup, so fake it by just pausing
|
|
||||||
if (utime && (op == FUTEX_WAIT_BITSET || op == FUTEX_WAIT)) {
|
|
||||||
// gettimeofday(&tv_now, NULL);
|
|
||||||
struct syscall_request request IHK_DMA_ALIGN;
|
|
||||||
struct timeval tv_now;
|
|
||||||
request.number = 96;
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
unsigned long __phys;
|
|
||||||
if (ihk_mc_pt_virt_to_phys(cpu_local_var(current)->vm->page_table,
|
|
||||||
(void *)&tv_now,
|
|
||||||
&__phys)) {
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
request.args[0] = __phys;
|
|
||||||
|
|
||||||
int r = do_syscall(&request, ctx);
|
|
||||||
if(r < 0) {
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
dkprintf("futex,FUTEX_WAIT_BITSET,arg3!=NULL,pc=%lx\n", (unsigned long)ihk_mc_syscall_pc(ctx));
|
|
||||||
|
|
||||||
dkprintf(" now->tv_sec=%016ld,tv_nsec=%016ld\n", tv_now.tv_sec, tv_now.tv_usec * 1000);
|
|
||||||
dkprintf("utime->tv_sec=%016ld,tv_nsec=%016ld\n", utime->tv_sec, utime->tv_nsec);
|
|
||||||
|
|
||||||
long nsec_now = ((long)tv_now.tv_sec * 1000000000ULL) +
|
|
||||||
tv_now.tv_usec * 1000;
|
|
||||||
long nsec_timeout = ((long)utime->tv_sec * 1000000000ULL) +
|
|
||||||
utime->tv_nsec * 1;
|
|
||||||
long diff_nsec = nsec_timeout - nsec_now;
|
|
||||||
|
|
||||||
/*
|
|
||||||
if(diff_nsec > 0) {
|
|
||||||
dkprintf("pausing %016ldnsec\n", diff_nsec);
|
|
||||||
arch_delay(diff_nsec/1000); // unit is usec
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
timeout = (diff_nsec / 1000) * 1100; // (usec * 1.1GHz)
|
|
||||||
#else
|
|
||||||
arch_delay(200000); // unit is usec
|
|
||||||
return -ETIMEDOUT;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return futex(uaddr, op, val, timeout, uaddr2, val2, val3);
|
return futex(uaddr, op, val, timeout, uaddr2, val2, val3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user