/* mythread_create function creates a new thread using clone system call.
   It passes wrapper function to the clone system which invokes the user function.
   attr can also be passed, if not passed, then default attr will be used. 
 */
int mythread_create(mythread_t* new_thread,
		    mythread_attr_t * attr,
		    void *(*start_func) (void *), void *arg)
{
	/* Global thread queue would be empty on first mythread_create call. 
	   This would add the main thread in the queue and also an idle thread, 
 	   and then proceed with the new thread creation */

	if (mythread_queue_globalVar == NULL) {
		mythread_queue_globalVar = malloc(sizeof(struct mythread_queue));
		mythread_t *main_t_tcb = (mythread_t *) malloc(sizeof(mythread_t));

		/* Initializing TCB values for main thread */

		main_t_tcb->start_func = NULL; /* There is no explicit function to call for the main thread */
		main_t_tcb->state = READY;
		main_t_tcb->returnValue = NULL;
		main_t_tcb->arg = NULL;
		main_t_tcb->joinq.headNode = NULL;
		main_t_tcb->joinq.tailNode = NULL;
		main_t_tcb->tid = (pid_t) syscall(SYS_gettid);

		/* Initialize main thread futex */
		futex_init(&main_t_tcb->futex, 0);

		/* Adding main thread to the queue */
		queue_add_element(mythread_queue_globalVar, main_t_tcb);

		/* Initialise the yeild futex */
		futex_init(&yield_futex, 1);

		/* Recursive call to mythread_create for the idle thread creation*/
		mythread_create(&idle_tcb, NULL, idle_thread, NULL);
	}

	mythread_t *new_mythread_t = (mythread_t *) malloc(sizeof(mythread_t));
	pid_t tid;

	/* Clone flags to be passed, taken from pthread source code - CLONE_PTRACE is removed */
	int clone_flags = (CLONE_VM | CLONE_FS  
			   | CLONE_FILES | CLONE_SIGHAND 
			   | CLONE_PARENT_SETTID | CLONE_THREAD
			   | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM);

	/* Check if attr is passed, if not, initialize with default attr */
	if (attr == NULL || (attr->stackbase == NULL && attr->stacksize != 0)){
		mythread_attr_t attr_new;
		mythread_attr_init(&attr_new);
		attr = &attr_new;
	}

	/* Initialize new thread's TCB */
	new_mythread_t->arg = arg;
	new_mythread_t->state = READY;
	new_mythread_t->start_func = start_func;
	new_mythread_t->joinq.headNode = NULL;
	new_mythread_t->joinq.tailNode = NULL;
	new_mythread_t->returnValue = NULL;

	/* Initialize the tcb's futex to zero. */
	futex_init(&new_mythread_t->futex, 0);

	/* Clone system call. This will invoke the wrapper_function. */
	tid = clone(wrapper_function, (char *)attr->stackbase, clone_flags,new_mythread_t);

	new_mythread_t->tid = tid;
	/* Returning the reference of the created TCB */
	*new_thread = *new_mythread_t;

	/* Adding the thread to the global TCB queue */
	queue_add_element(mythread_queue_globalVar, new_mythread_t);
	return 0;
}
Example #2
0
int main(int argc, char *argv[]) {
	int rc = 0;
	mythread_t th[THREAD_COUNT];
	mythread_attr_t *attr[THREAD_COUNT];
	struct sched_param sparam1;
	long i;

	mythread_setconcurrency(CONCURRENCY_COUNT);

	//printf("concurrency is %d\n", mythread_getconcurrency());

	mythread_mutex_init(&mutex, NULL);

	for (i = 0; i < THREAD_COUNT; i++) {
		attr[i] = malloc(sizeof(mythread_attr_t));
		mythread_attr_init(attr[i]);
		switch (i) {
		case 2:
			sparam1.__sched_priority = 9;
			mythread_attr_setschedparam(attr[i], &sparam1);
			break;
		case 3:
			sparam1.__sched_priority = 8;
			mythread_attr_setschedparam(attr[i], &sparam1);
			break;
		case 4:
			sparam1.__sched_priority = 7;
			mythread_attr_setschedparam(attr[i], &sparam1);
			break;
		case 5:
			sparam1.__sched_priority = 6;
			mythread_attr_setschedparam(attr[i], &sparam1);
			break;
		case 6:
			sparam1.__sched_priority = 5;
			mythread_attr_setschedparam(attr[i], &sparam1);
			break;
		default:
			break;
		}

		mythread_create(&th[i], attr[i], thread_func, (void*) i);
	}

	for (i = 0; i < THREAD_COUNT; i++) {
		mythread_join(th[i], NULL);
	}

	/* Test: mythread_attr_getschedparam()*/
	for (i = 0; i < THREAD_COUNT; i++) {
		int rc = 0;
		struct sched_param sparam2;
		rc = mythread_attr_getschedparam(attr[i], &sparam2);
		if(!rc){
			switch (i) {
			case 2:
				sparam2.__sched_priority = 9;
				score = score + 0.7;
				break;
			case 3:
				sparam2.__sched_priority = 8;
				score = score + 0.7;
				break;
			case 4:
				sparam2.__sched_priority = 7;
				score = score + 0.7;
				break;
			case 5:
				sparam2.__sched_priority = 6;
				score = score + 0.7;
				break;
			case 6:
				sparam2.__sched_priority = 5;
				score = score + 0.7;
				break;
			default:
				break;
			}
		}
//		printf("sparam2.sched_priority = %d\n",
//				sparam2.__sched_priority);
		//show_sched_param(attr[i]);

	}

	/* Test 1*/
	printf("# Test Case 1:");
	//printf("Expected Output: %s\n", EXPECTED_OUTPUT1);
	//printf("Actual Output: %s\n", actualOutput);
	if (!strcmp(EXPECTED_OUTPUT1, actualOutput) ||
			!strcmp(EXPECTED_OUTPUT2, actualOutput)) {
		printf("PASS\n");
		score = score + 25;
	} else {
		printf("FAIL\n");
	}


	/*Test: mythread_attr_destroy() */
	int deduction = 0;
	for (i = 0; i < THREAD_COUNT; i++) {
		rc = mythread_attr_destroy(attr[i]);
		if(rc){
			deduction = deduction + 0.5;
		}
		free(attr[i]);
	}
	if(rc){
		score = score - deduction;
		printf("Deduction occurred.\n");
	}

	mythread_mutex_destroy(&mutex);

	printf("## Score: %d\n", score);

	return 0;
}