Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Here's the code with the requested changes:
- ```c
- #define _GNU_SOURCE
- #include <stdio.h>
- #include <stdlib.h>
- #include <sched.h>
- #include <setjmp.h>
- #include <unistd.h>
- #include <signal.h>
- #include <sys/wait.h>
- #include <sys/mman.h>
- #define MAX_THREADS 10 // Define the maximum number of threads
- #define STACK_SIZE (1 << 20) // 1MB stack size, adjust as needed
- int NUM_ALIVE_THREADS = 1;
- int THREAD_COMPLETED = 0;
- int current_thread = 0;
- mythread_t* threads[MAX_THREADS]; // Array to hold thread pointers
- void* routine_wrapper(void *arg) {
- mythread_t* t = (mythread_t *)arg;
- if (setjmp(t->env) == 0) { // Only enter here on initial setup, not on longjmp
- t->res = t->start_routine(t->arg);
- t->completed = 1;
- schedule();
- } else {
- if (__sync_fetch_and_add(&THREAD_COMPLETED, 1) == NUM_ALIVE_THREADS - 1) {
- // All threads completed, resume the main thread
- __sync_synchronize();
- schedule();
- } else {
- pause(); // Suspend the current thread until all other threads complete
- }
- }
- }
- void schedule() {
- int start_thread = current_thread;
- do {
- current_thread = (current_thread + 1) % NUM_ALIVE_THREADS;
- if (threads[current_thread] != NULL && threads[current_thread]->joined && threads[current_thread]->active && !threads[current_thread]->completed) {
- longjmp(threads[current_thread]->env, 1);
- }
- } while (current_thread != start_thread);
- }
- void mythread_yield() {
- threads[current_thread]->active = 0; // Mark current thread as inactive
- schedule(); // Find the next thread to execute
- threads[current_thread]->active = 1; // Mark next thread as active
- }
- int mythread_create(mythread_t *thread, void *(*start_routine)(void *), void *arg) {
- thread->arg = arg;
- thread->stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (thread->stack == MAP_FAILED) {
- perror("mmap");
- return -1;
- }
- thread->start_routine = start_routine;
- if (clone((int (*)(void *)) routine_wrapper, (char*)thread->stack + STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD, thread) == -1) {
- perror("clone");
- return -1;
- }
- thread->joined = 1;
- thread->completed = 0;
- thread->active = 1; // Mark the thread as active
- threads[NUM_ALIVE_THREADS - 1] = thread; // Add the thread to the array
- __sync_fetch_and_add(&NUM_ALIVE_THREADS, 1);
- return 0;
- }
- void mythread_detach(mythread_t *t) {
- t->joined = 0;
- }
- int mythread_join(mythread_t *thread, void **ret_val) {
- if (thread->joined == 0) {
- return -1; // Thread is not joinable
- }
- while (thread->completed == 0) {
- sched_yield(); // Suspend the current thread until the thread completes
- }
- if (ret_val != NULL) {
- *ret_val = thread->res;
- }
- munmap(thread->stack, STACK_SIZE); // Free the stack memory
- return 0;
- }
- void mythread_exit() {
- threads[current_thread]->active = 0; // Mark current thread as inactive
- if (__sync_fetch_and_add(&NUM_ALIVE_THREADS, -1) != 1) {
- // There are other threads, switch to another thread
- mythread_yield();
- } else {
- exit(0);
- }
- }
- void *work(void *arg) {
- for(int i = 0; i < 100; i++){
- printf("hello world %d\n", i);
- }
- return NULL;
- }
- void *work2(void *arg) {
- for(int i = 0; i < 10; i++){
- printf("ADS %d\n", i);
- }
- return (void *) 10;
- }
- int main(int argc, char *argv[]) {
- mythread_t t, t2;
- mythread_create(&t, work, NULL);
- mythread_create(&t2, work2, NULL);
- mythread_detach(&t);
- int *res = malloc(sizeof(int));
- mythread_join(&t2, (void **) res);
- mythread_exit();
- return 0;
- }
- ```
- In this code, I've made the changes according to your request. The threads should switch automatically after a thread completes its execution without manually calling `mythread_yield()`.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement