#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <string.h>
#include <sys/queue.h>
#include <stdarg.h>
#include <errno.h>
#include <getopt.h>
#include <unistd.h>
#include <sched.h>
#include <pthread.h>
#include "lthread_api.h"
#include "lthread_diag_api.h"
#include "pthread_shim.h"
#define DEBUG_APP 0
#define HELLOW_WORLD_MAX_LTHREADS 10
#ifndef __GLIBC__ 
#define sched_getcpu() rte_lcore_id()
#endif
__thread int print_count;
__thread pthread_mutex_t print_lock;
__thread pthread_mutex_t exit_lock;
__thread pthread_cond_t exit_cond;
void *helloworld_pthread(void *arg);
void *helloworld_pthread(void *arg)
{
    pthread_key_t key;
    
    pthread_key_create(&key, NULL);
    
    pthread_setspecific(key, arg);
    
    pthread_mutex_lock(&print_lock);
    print_count++;
    
    pthread_yield();
    
    uint64_t thread_no = (uint64_t) pthread_getspecific(key);
    printf("Hello - lcore = %d count = %d thread_no = %d thread_id = %p\n",
            sched_getcpu(),
            print_count,
            (int) thread_no,
            (void *)pthread_self());
    
    pthread_mutex_unlock(&print_lock);
    
    pthread_mutex_lock(&exit_lock);
    pthread_cond_wait(&exit_cond, &exit_lock);
    pthread_mutex_unlock(&exit_lock);
    
    pthread_exit((void *) thread_no);
}
__thread pthread_t tid[HELLOW_WORLD_MAX_LTHREADS];
static void *initial_lthread(void *args __attribute__((unused)))
{
    
    pthread_override_set(1);
    uint64_t i;
    int ret;
    
    print_count = 0;
    pthread_mutex_init(&print_lock, NULL);
    
    pthread_mutex_init(&exit_lock, NULL);
    pthread_cond_init(&exit_cond, NULL);
    
    for (i = 0; i < HELLOW_WORLD_MAX_LTHREADS; i++) {
        
        pthread_attr_t attr;
        rte_cpuset_t cpuset;
        CPU_ZERO(&cpuset);
        CPU_SET(lcore, &cpuset);
        pthread_attr_init(&attr);
        pthread_attr_setaffinity_np(&attr, sizeof(rte_cpuset_t), &cpuset);
        
        ret = pthread_create(&tid[i], &attr,
                helloworld_pthread, (void *) i);
        if (ret != 0)
            rte_exit(EXIT_FAILURE, 
"Cannot create helloworld thread\n");
     }
    
    struct timespec time;
    time.tv_sec = 1;
    time.tv_nsec = 0;
    nanosleep(&time, NULL);
    
    pthread_cond_broadcast(&exit_cond);
    
    for (i = 0; i < HELLOW_WORLD_MAX_LTHREADS; i++) {
        uint64_t thread_no;
        pthread_join(tid[i], (void *) &thread_no);
        if (thread_no != i)
            printf("error on thread exit\n");
    }
    pthread_cond_destroy(&exit_cond);
    pthread_mutex_destroy(&print_lock);
    pthread_mutex_destroy(&exit_lock);
    
    lthread_detach();
    return NULL;
}
static int
lthread_scheduler(void *args __attribute__((unused)))
{
    
    struct lthread *lt;
    lthread_create(<, -1, initial_lthread, (void *) NULL);
    
    lthread_run();
    
    pthread_override_set(0);
    return 0;
}
int main(int argc, char **argv)
{
    int num_sched = 0;
    
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Invalid EAL parameters\n");
     
#if DEBUG_APP
    lthread_diagnostic_set_mask(LT_DIAG_ALL);
#endif
    
    unsigned lcore_id;
    for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
            num_sched++;
    }
    
    lthread_num_schedulers_set(num_sched);
    
    
    }
    return 0;
}