blob: 08791a298f1a0e5e4a3180f15c5b41d407642009 [file] [log] [blame]
/*
* Copyright 2010
* Princeton University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY PRINCETON UNIVERSITY ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PRINCETON UNIVERSITY OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of Princeton University.
*
*/
/*
* @(#)host_serv.h (Princeton) 11/11/2010
*
*/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <malloc.h>
#include <pthread.h>
#include <stdint.h>
#include<sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/types.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
//#include <linux/filter.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <sys/ioctl.h>
#include <sys/bsd_lock.h>
#include "host_serv.h"
#define LC_SLEEPLOCK 0x00000001 /* Sleep lock. */
#define LC_SPINLOCK 0x00000002 /* Spin lock. */
#define LC_SLEEPABLE 0x00000004 /* Sleeping allowed with this lock. */
#define LC_RECURSABLE 0x00000008 /* Locks of this type may recurse. */
#define LC_UPGRADABLE 0x00000010 /* Upgrades and downgrades permitted. */
#define LO_CLASSFLAGS 0x0000ffff /* Class specific flags. */
#define LO_INITIALIZED 0x00010000 /* Lock has been initialized. */
#define LO_WITNESS 0x00020000 /* Should witness monitor this lock. */
#define LO_QUIET 0x00040000 /* Don't log locking operations. */
#define LO_RECURSABLE 0x00080000 /* Lock may recurse. */
#define LO_SLEEPABLE 0x00100000 /* Lock may be held while sleeping. */
#define LO_UPGRADABLE 0x00200000 /* Lock may be upgraded/downgraded. */
#define LO_DUPOK 0x00400000 /* Don't check for duplicate acquires */
#define LO_CLASSMASK 0x0f000000 /* Class index bitmask. */
#define LO_NOPROFILE 0x10000000 /* Don't profile this lock */
/*
* CPU_Set
*/
long max_host_cores;
cpu_set_t cpuset_exclusive_s;
cpu_set_t cpuset_exclusive_c;
cpu_set_t cpuset_shared;
/*
* Declare some variables
*/
static pthread_mutexattr_t mutexattr;
#ifdef UPTCP_CLIENT
static struct sockaddr_in server_addr;
#else
static struct sockaddr_in client_addr;
#endif
/*
* Thread related
*/
thread_wrapper thread_list[THREAD_LIST_SIZE];
unsigned char thread_index[THREAD_INDEX_SIZE];
int uptcpip_thread_count = 0;
pthread_mutex_t uptcpip_thread_count_mutex = PTHREAD_MUTEX_INITIALIZER;
extern struct timeval global_roi_start_tv;
int in_tcpip_roi = 0;
/*
* Function Implementation
*/
int host_setup_cpuset()
{
#ifndef FOR_SIMULATION
int i, s, c;
max_host_cores = sysconf(_SC_NPROCESSORS_ONLN);
#if 0
if(max_host_cores >= 2){
s = max_host_cores/2 - 1;
c = max_host_cores/2;
CPU_ZERO(&cpuset_exclusive_s);
CPU_SET(s, &cpuset_exclusive_s);
CPU_ZERO(&cpuset_exclusive_c);
CPU_SET(c, &cpuset_exclusive_c);
CPU_ZERO(&cpuset_shared);
for(i = 0; i < max_host_cores; i ++)
if(i != s && i != c)
CPU_SET(i, &cpuset_shared);
} else {
CPU_ZERO(&cpuset_exclusive_s);
CPU_SET(0, &cpuset_exclusive_s);
CPU_ZERO(&cpuset_exclusive_c);
CPU_SET(0, &cpuset_exclusive_c);
CPU_ZERO(&cpuset_shared);
CPU_SET(0, &cpuset_shared);
}
if (sched_setaffinity(0, sizeof(cpu_set_t),&cpuset_shared) <0) {
perror("pthread_setaffinity_np");
}
#endif //0
#endif
return 0;
}
void enter_tcpip_roi()
{
int i;
for(i = 0; i < uptcpip_thread_count; i++)
thread_list[i].last_active_time = global_roi_start_tv;
in_tcpip_roi = 1;
}
void exit_tcpip_roi()
{
//NOP
in_tcpip_roi = 0;
}
int pthread_create_wrapper(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg, int type)
{
host_setup_cpuset();
thread_wrapper * tw_ptr;
int res = pthread_create(thread, attr, start_routine, arg);
/* initialize thread_wrapper for the created thread */
if(res == 0){
pthread_mutex_lock(&uptcpip_thread_count_mutex);
tw_ptr = &thread_list[uptcpip_thread_count];
tw_ptr->ptr = *thread;
tw_ptr->id = uptcpip_thread_count; //start from "1"
tw_ptr->type = type;
gettimeofday(&(tw_ptr->last_active_time), NULL);
int hash = (unsigned long)(*thread) % THREAD_INDEX_SIZE;
while(thread_index[hash] != 0xff)
hash = (hash + 1) % THREAD_INDEX_SIZE;
thread_index[hash] = tw_ptr->id;
uptcpip_thread_count ++;
pthread_mutex_unlock(&uptcpip_thread_count_mutex);
#ifndef FOR_SIMULATION
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
#ifdef UPTCP_CLIENT //client
switch(type){
case THREAD_TYPE_TX_LINK: CPU_SET(1 % max_host_cores, &cpuset); break;
case THREAD_TYPE_RX_TCPIP: CPU_SET(2 % max_host_cores, &cpuset); break;
case THREAD_TYPE_APP: CPU_SET(3 % max_host_cores, &cpuset); break;
default: CPU_SET(0 % max_host_cores, &cpuset); break;
}
#else //server
switch(type){
case THREAD_TYPE_RX_LINK: CPU_SET((max_host_cores-2) % max_host_cores, &cpuset); break;
case THREAD_TYPE_RX_TCPIP: CPU_SET((max_host_cores-1) % max_host_cores, &cpuset); break;
case THREAD_TYPE_APP: CPU_SET(max_host_cores, &cpuset); break;
default: CPU_SET((max_host_cores-3) % max_host_cores, &cpuset); break;
}
#endif
if (pthread_setaffinity_np(*thread, sizeof(cpu_set_t),&cpuset) <0) {
fprintf(stderr, "pthread_setaffinity_np failed\n");
}
#endif
}
return res;
}
int host_thread_get_uptcp_tid()
{
pthread_t self = pthread_self();
int hash = (unsigned long)self % THREAD_INDEX_SIZE;
while(thread_index[hash] == 0xff || self != thread_list[thread_index[hash]].ptr)
hash = (hash + 1) % THREAD_INDEX_SIZE;
return thread_index[hash];
}
void host_thread_enter_wait_region()
{
if(!in_tcpip_roi)
return;
struct timeval cur_time;
pthread_t self = pthread_self();
int hash = (unsigned long)self % THREAD_INDEX_SIZE;
while(thread_index[hash] == 0xff || self != thread_list[thread_index[hash]].ptr)
hash = (hash + 1) % THREAD_INDEX_SIZE;
thread_wrapper *ptr = &(thread_list[thread_index[hash]]);
/* enter wait region*/
gettimeofday(&(cur_time), NULL);
unsigned long long interval = (cur_time.tv_sec * 1000000 + cur_time.tv_usec) - (ptr->last_active_time.tv_sec * 1000000 + ptr->last_active_time.tv_usec);
ptr->active_time += interval;
}
void host_thread_exit_wait_region()
{
if(!in_tcpip_roi)
return;
pthread_t self = pthread_self();
int hash = (unsigned long)self % THREAD_INDEX_SIZE;
while(thread_index[hash] == 0xff || self != thread_list[thread_index[hash]].ptr)
hash = (hash + 1) % THREAD_INDEX_SIZE;
thread_wrapper *ptr = &(thread_list[thread_index[hash]]);
/* exit wait region*/
gettimeofday(&(ptr->last_active_time), NULL);
}
int host_thread_enter_tcpip_region(int type)
{
if(!in_tcpip_roi)
return 0;
pthread_t self = pthread_self();
int hash = (unsigned long)self % THREAD_INDEX_SIZE;
while(thread_index[hash] == 0xff || self != thread_list[thread_index[hash]].ptr)
hash = (hash + 1) % THREAD_INDEX_SIZE;
thread_wrapper *ptr = &(thread_list[thread_index[hash]]);
if(ptr->type == THREAD_TYPE_APP)
ptr->type = type;
/* enter tcpip region*/
gettimeofday(&(ptr->last_tcpip_time), NULL);
return ptr->id;
}
int host_thread_exit_tcpip_region(int thread_id)
{
if(!in_tcpip_roi)
return 0;
struct timeval tv;
thread_wrapper *ptr = &(thread_list[thread_id]);
gettimeofday(&tv, NULL);
unsigned long long interval = (tv.tv_sec * 1000000 + tv.tv_usec)- (ptr->last_tcpip_time.tv_sec * 1000000 + ptr->last_tcpip_time.tv_usec);
ptr->intcpip_time += interval;
return 0;
}
int host_thread_create(void* (*routine)(void*), void* t_args, int type)
{
pthread_t *pthread;
pthread = (pthread_t*) malloc(sizeof(pthread_t));
if(!pthread){
printf("hif_alloc_ring_and_thread(): malloc() for pthread failed\n");
return -1;
}
memset(pthread, 0, sizeof(pthread_t));
if(pthread_create_wrapper(pthread, NULL, routine, t_args, type) < 0){
printf("hif_alloc_ring_and_thread(): pthread_create() failed\n");
free(pthread);
return -1;
}
return 0;
}
int host_usleep(int num)
{
usleep(num);
return 0;
}
int host_setup_link(int port)
{
int link_fd;
/* Step.2 bind & listen */
struct sockaddr_in sin;
if((link_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
printf("host_setup_link(): socket() fail, errno = %d\n", errno);
return -1;
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = PF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
if (bind(link_fd, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
printf("host_setup_link(): bind() fail\n");
return -1;
}
return link_fd;
}
int host_connect_link(int port)
{
int link_fd;
/* Step.0 create a socket */
if((link_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
printf("host_connect_link(): socket() fail, errno = %d\n", errno);
return -1;
}
/* Step.1 connect to server */
#ifdef UPTCP_CLIENT
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(0x7f000001);
server_addr.sin_port = htons(port);
#else
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = htonl(0x0a0a0a01);
client_addr.sin_port = htons(port);
#endif
return link_fd;
}
int host_link_send(int link_fd, const void * buf, size_t len)
{
int res = 0;
#ifdef UPTCP_CLIENT
res = sendto(link_fd, buf, len, 0, (struct sockaddr*)&server_addr, sizeof(server_addr));
#else
res = sendto(link_fd, buf, len, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
#endif
if(res < 0)
printf("host_link_send: errno = %d\n", errno);
return res;
}
int host_link_recv(int link_fd,void *buf, size_t len)
{
int res;
res = recvfrom(link_fd, buf, len, 0, NULL, NULL);
if(res < 0)
printf("host_link_recv(): res = %d, errno = %d\n", res, errno);
return res;
}
/* host memory management */
void* host_malloc(size_t size, int align)
{
if(align == -1)
return malloc(size);
else return memalign(align, size);
}
void host_free(void * ptr)
{
free(ptr);
}
/*
* mutex
*/
void host_pthread_mutexattr_init()
{
pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
}
void* host_pthread_mutex_init(int flag)
{
pthread_mutex_t *p_mutex;
p_mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
if((flag & LO_RECURSABLE) != 0)
pthread_mutex_init(p_mutex, &mutexattr);
else pthread_mutex_init(p_mutex, NULL);
return p_mutex;
}
void host_pthread_mutex_destory(void* lock)
{
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_mutex_t *p_mutex = (pthread_mutex_t*)p_lo->ext_lock;
pthread_mutex_destroy(p_mutex);
free(p_mutex);
}
void host_pthread_mutex_lock(void* lock)
{
int error;
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_mutex_t *p_mutex = (pthread_mutex_t*)p_lo->ext_lock;
if(p_lo->lo_flags & LO_RECURSABLE){
error = pthread_mutex_lock(p_mutex);
p_lo->lo_data ++;
p_lo->lo_owner = (unsigned long int)pthread_self();
if(error){
printf("panic\n");
exit(-1);
}
}else{
pthread_mutex_lock(p_mutex);
if(p_lo->lo_data != 0){
printf("panic\n");
exit(-1);
}
p_lo->lo_data ++;
p_lo->lo_owner = (unsigned long int)pthread_self();
}
}
int host_pthread_mutex_trylock(void* lock)
{
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_mutex_t *p_mutex = (pthread_mutex_t*)p_lo->ext_lock;
int error, retval;
if(p_lo->lo_flags & LO_RECURSABLE){
error = pthread_mutex_trylock(p_mutex);
if(error == 0){
p_lo->lo_data ++;
p_lo->lo_owner = (unsigned long int)pthread_self();
retval = 1;
}else{
retval = 0;
}
} else {
error = pthread_mutex_trylock(p_mutex);
if(error == 0){
if(p_lo->lo_data != 0){
printf("panic\n");
exit(-1);
}
p_lo->lo_data ++;
p_lo->lo_owner = (unsigned long int)pthread_self();
retval = 1;
}else{
retval = 0;
}
}
return retval;
}
void host_pthread_mutex_unlock(void* lock)
{
int error;
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_mutex_t *p_mutex = (pthread_mutex_t*)p_lo->ext_lock;
if(p_lo->lo_flags & LO_RECURSABLE){
p_lo->lo_data --;
p_lo->lo_owner = (unsigned long int)pthread_self();
error = pthread_mutex_unlock(p_mutex);
if(error){
printf("panic\n");
exit(-1);
}
}else{
if(p_lo->lo_data != 1){
printf("panic\n");
exit(-1);
}
p_lo->lo_data --;
p_lo->lo_owner = (unsigned long int)pthread_self();
pthread_mutex_unlock(p_mutex);
}
}
void* host_pthread_rwlock_init()
{
pthread_rwlock_t *p_rwlock;
p_rwlock = (pthread_rwlock_t*)malloc(sizeof(pthread_rwlock_t));
pthread_rwlock_init(p_rwlock, NULL);
return p_rwlock;
}
int host_pthread_rwlock_destory(void* lock)
{
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_rwlock_t *p_rwlock = (pthread_rwlock_t*)p_lo->ext_lock;
int error = pthread_rwlock_destroy(p_rwlock);
free(p_rwlock);
return (error == 0) ? 1 : 0;
}
void host_pthread_rwlock_wlock(void* lock)
{
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_rwlock_t *p_rwlock = (pthread_rwlock_t*)p_lo->ext_lock;
pthread_t tid;
if(p_lo->lo_flags & LO_RECURSABLE){
tid = pthread_self();
if(p_lo->lo_owner == tid && p_lo->lo_data != 0){
p_lo->lo_data ++;
} else { /*!= tid*/
pthread_rwlock_wrlock(p_rwlock);
p_lo->lo_owner = tid;
p_lo->lo_data = 1;
}
} else {
pthread_rwlock_wrlock(p_rwlock);
if(p_lo->lo_data != 0){
printf("panic\n");
exit(-1);
}
p_lo->lo_data ++;
p_lo->lo_owner = (unsigned long int)pthread_self();
}
}
void host_pthread_rwlock_wunlock(void* lock)
{
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_rwlock_t *p_rwlock = (pthread_rwlock_t*)p_lo->ext_lock;
pthread_t tid;
if(p_lo->lo_flags & LO_RECURSABLE){
tid = pthread_self();
if(p_lo->lo_owner == tid){
if(p_lo->lo_data == 1){
p_lo->lo_owner = 0;
p_lo->lo_data = 0;
pthread_rwlock_unlock(p_rwlock);
} else {
p_lo->lo_data --;
}
} else { /*error, lock can be unlock by owner*/
printf("host_pthread_rwlock_wunlck(): ERROR, try to unlock an unacquired lock\n");
}
} else {
if(p_lo->lo_data != 1){
printf("panic\n");
exit(-1);
}
p_lo->lo_data --;
p_lo->lo_owner = 0;
pthread_rwlock_unlock(p_rwlock);
}
}
void host_pthread_rwlock_rlock(void* lock)
{
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_rwlock_t *p_rwlock = (pthread_rwlock_t*)p_lo->ext_lock;
int error;
if(p_lo->lo_flags & LO_RECURSABLE){
error = pthread_rwlock_rdlock(p_rwlock);
if(error){
printf("panic\n");
exit(-1);
}
} else {
pthread_rwlock_rdlock(p_rwlock);
p_lo->lo_data ++;
}
}
void host_pthread_rwlock_runlock(void* lock)
{
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_rwlock_t *p_rwlock = (pthread_rwlock_t*)p_lo->ext_lock;
int error;
if(p_lo->lo_flags & LO_RECURSABLE){
error = pthread_rwlock_unlock(p_rwlock);
if(error){
printf("panic\n");
exit(-1);
}
}else{
p_lo->lo_data --;
pthread_rwlock_unlock(p_rwlock);
}
}
int host_pthread_rwlock_tryrlock(void* lock)
{
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_rwlock_t *p_rwlock = (pthread_rwlock_t*)p_lo->ext_lock;
int error, retval;
if(p_lo->lo_flags & LO_RECURSABLE){
error = pthread_rwlock_tryrdlock(p_rwlock);
if(error == 0){
retval = 1;
}else{
retval = 0;
}
} else {
error = pthread_rwlock_tryrdlock(p_rwlock);
if(error == 0){
p_lo->lo_data ++;
retval = 1;
}else{
retval = 0;
}
}
return retval;
}
int host_pthread_rwlock_trywlock(void* lock)
{
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_rwlock_t *p_rwlock = (pthread_rwlock_t*)p_lo->ext_lock;
int error;
pthread_t tid;
if(p_lo->lo_flags & LO_RECURSABLE){
tid = pthread_self();
if(p_lo->lo_owner == tid && p_lo->lo_data != 0){
p_lo->lo_data ++;
error = 0;
} else { /*!= tid*/
error = pthread_rwlock_trywrlock(p_rwlock);
if(error == 0){
p_lo->lo_owner = tid;
if(p_lo->lo_data != 0){
printf("panic\n");
exit(-1);
}
p_lo->lo_data = 1;
}
}
} else {
error = pthread_rwlock_trywrlock(p_rwlock);
if(error == 0){
if(p_lo->lo_data != 0){
printf("panic\n");
exit(-1);
}
p_lo->lo_data ++;
p_lo->lo_owner = (unsigned long int)pthread_self();
}
}
return (error == 0) ? 1 : 0;
}
void host_pthread_rwlock_unlock(void* lock)
{
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_t tid = pthread_self();
if(p_lo->lo_owner == tid)
host_pthread_rwlock_wunlock(lock);
else host_pthread_rwlock_runlock(lock);
}
/*
* condition
*/
void* host_pthread_cond_init()
{
pthread_cond_t *p_cond;
p_cond = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
pthread_cond_init(p_cond, NULL);
return p_cond;
}
void host_pthread_cond_destroy(void* cond)
{
pthread_cond_t *p_cond = (pthread_cond_t*)cond;
pthread_cond_destroy(p_cond);
free(p_cond);
}
int host_pthread_cond_wait(void* cond, void* lock)
{
pthread_cond_t *p_cond = (pthread_cond_t*)cond;
struct lock_object *p_lo = (struct lock_object *)lock;
pthread_mutex_t *p_mutex = (pthread_mutex_t*)p_lo->ext_lock;
int error;
host_thread_enter_wait_region();
if(p_lo->lo_flags & LO_RECURSABLE){
p_lo->lo_data --;
p_lo->lo_owner = (unsigned long int)pthread_self();
}else{
if(p_lo->lo_data != 1){
printf("panic\n");
exit(-1);
}
p_lo->lo_data --;
p_lo->lo_owner = (unsigned long int)pthread_self();
}
error = pthread_cond_wait(p_cond, p_mutex);
if(p_lo->lo_flags & LO_RECURSABLE){
p_lo->lo_data ++;
p_lo->lo_owner = (unsigned long int)pthread_self();
}else{
if(p_lo->lo_data != 0){
printf("panic\n");
exit(-1);
}
p_lo->lo_data ++;
p_lo->lo_owner = (unsigned long int)pthread_self();
}
host_thread_exit_wait_region();
return (error == 0) ? 0 : 1;
}
void host_pthread_cond_signal(void* cond)
{
pthread_cond_t *p_cond = (pthread_cond_t*)cond;
pthread_cond_signal(p_cond);
}