int my_pthread_create( void (*func)(void) ) { if ( numThreads == MAX_THREADS ) return LF_MAXTHREADS; num_high_priority_threads++; /* Add the new function to the end of the thread list */ getcontext( &threadList[numThreads].context ); /* Set the context to a newly allocated stack */ threadList[numThreads].context.uc_link = 0; threadList[numThreads].stack = malloc( FIBER_STACK ); threadList[numThreads].context.uc_stack.ss_sp = threadList[numThreads].stack; threadList[numThreads].context.uc_stack.ss_size = FIBER_STACK; threadList[numThreads].context.uc_stack.ss_flags = 0; threadList[numThreads].start_address = (void*)myallocate(4095,__FILE__,__LINE__,0); threadList[numThreads].end_address = threadList[numThreads].start_address + 4095; threadList[numThreads].current_index = 0; if ( threadList[numThreads].stack == 0 || threadList[numThreads].start_address == NULL) { LF_DEBUG_OUT( "Error: Could not allocate stack. or heapspace" ); return LF_MALLOCERROR; } /* Create the context. The context calls threadStart( func ). */ makecontext( &threadList[ numThreads ].context, (void (*)(void)) &threadStart, 1, func ); ++ numThreads; return LF_NOERROR; }
int spawnFiber( ctr_object* block ) { if ( numFibers == MAX_FIBERS ) return LF_MAXFIBERS; // Add the new function to the end of the fiber list getcontext( &fiberList[numFibers].context ); // Set the context to a newly allocated stack fiberList[numFibers].context.uc_link = 0; fiberList[numFibers].context.uc_stack.ss_sp = malloc( FIBER_STACK ); fiberList[numFibers].context.uc_stack.ss_size = FIBER_STACK; fiberList[numFibers].context.uc_stack.ss_flags = 0; if ( fiberList[numFibers].context.uc_stack.ss_sp == 0 ) { LF_DEBUG_OUT( "Error: Could not allocate stack.", 0 ); return LF_MALLOCERROR; } // Create the context. The context calls fiberStart( func ). makecontext( &fiberList[ numFibers ].context, (void (*)(void)) &fiberStart, 1, block ); ++ numFibers; return LF_NOERROR; }
int spawnFiber( void (*func)(void) ) { if ( numFibers == MAX_FIBERS ) return LF_MAXFIBERS; /* Add the new function to the end of the fiber list */ getcontext( &fiberList[numFibers].context ); /* Set the context to a newly allocated stack */ fiberList[numFibers].context.uc_link = 0; fiberList[numFibers].stack = malloc( FIBER_STACK ); fiberList[numFibers].context.uc_stack.ss_sp = fiberList[numFibers].stack; fiberList[numFibers].context.uc_stack.ss_size = FIBER_STACK; fiberList[numFibers].context.uc_stack.ss_flags = 0; if ( fiberList[numFibers].stack == 0 ) { LF_DEBUG_OUT( "Error: Could not allocate stack." ); return LF_MALLOCERROR; } /* Create the context. The context calls fiberStart( func ). */ makecontext( &fiberList[ numFibers ].context, (void (*)(void)) &fiberStart, 1, func ); ++ numFibers; return LF_NOERROR; }
// Switches from a fiber to main or from main to a fiber void fiberYield() { // If we are in a fiber, switch to the main process if ( inFiber ) { // Switch to the main context LF_DEBUG_OUT( "libfiber debug: Fiber %d yielding the processor...", currentFiber ); swapcontext( &fiberList[currentFiber].context, &mainContext ); } // Else, we are in the main process and we need to dispatch a new fiber else { if ( numFibers == 0 ) return; // Saved the state so call the next fiber currentFiber = (currentFiber + 1) % numFibers; LF_DEBUG_OUT( "Switching to fiber %d.", currentFiber ); inFiber = 1; swapcontext( &mainContext, &fiberList[ currentFiber ].context ); inFiber = 0; LF_DEBUG_OUT( "Fiber %d switched to main context.", currentFiber ); if ( fiberList[currentFiber].active == 0 ) { LF_DEBUG_OUT( "Fiber %d is finished. Cleaning up.\n", currentFiber ); // Free the "current" fiber's stack free( fiberList[currentFiber].context.uc_stack.ss_sp ); // Swap the last fiber with the current, now empty, entry -- numFibers; if ( currentFiber != numFibers ) { fiberList[ currentFiber ] = fiberList[ numFibers ]; } fiberList[ numFibers ].active = 0; } } return; }
int spawn_thread1( void (*func)(void) ) { struct thread1Arguments* arguments = NULL; if ( numthreads == MAX_THREADS ) return LF_MAXTHREADS; thread1List[numthreads].stack = malloc( THREAD_STACK ); /* Allocate the stack */ if ( thread1List[numthreads].stack == 0 ) { LF_DEBUG_OUT( "Error: Could not allocate stack." ); return LF_MALLOCERROR; } arguments = (struct thread1Arguments*) malloc( sizeof(*arguments) ); /* Create the arguments structure. */ if ( arguments == 0 ) { free( thread1List[numthreads].stack ); LF_DEBUG_OUT( "Error: Could not allocate thread arguments." ); return LF_MALLOCERROR; } arguments->function = func; /* Call the clone system call to create the child thread */ thread1List[numthreads].pid = clone( &thread1Start, (char*) thread1List[numthreads].stack + THREAD_STACK, SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM, arguments ); if ( thread1List[numthreads].pid == -1 ) { free( thread1List[numthreads].stack ); free( arguments ); LF_DEBUG_OUT( "Error: clone system call failed." ); return LF_CLONEERROR; } numthreads ++; return LF_NOERROR; }
int waitForAllFibers() { int fibersRemaining = 0; // If we are in a fiber, wait for all the *other* fibers to quit if ( inFiber ) fibersRemaining = 1; LF_DEBUG_OUT( "Waiting until there are only %d threads remaining...", fibersRemaining ); // Execute the fibers until they quit while ( numFibers > fibersRemaining ) { fiberYield(); } return LF_NOERROR; }
int waitForAllthreads() { pid_t pid; int i; int threadsRemaining = 0; /* Check to see if we are in a thread, since we don't get signals in the child threads */ pid = getpid(); if ( pid != parentPid ) return LF_INTHREAD; /* Wait for the THREADs to quit, then free the stacks */ while ( numthreads > threadsRemaining ) { pid = wait( 0 ); if ( pid == -1 ) { LF_DEBUG_OUT( "Error: wait system call failed." ); exit( 1 ); } for ( i = 0; i < numthreads; ++ i ) /* Find the thread, free the stack, and swap it with the last one */ { if ( thread1List[i].pid == pid ) { LF_DEBUG_OUT1( "Child thread pid = %d exited", pid ); numthreads --; free( thread1List[i].stack ); if ( i != numthreads ) { thread1List[i] = thread1List[numthreads]; } i = -1; break; } } if ( i == numthreads ) { LF_DEBUG_OUT1( "Did not find child pid = %d in the thread list", pid ); } } return LF_NOERROR; }
int spawnFiber( void (*func)(void) ) { struct sigaction handler; struct sigaction oldHandler; stack_t stack; stack_t oldStack; if ( numFibers == MAX_FIBERS ) return LF_MAXFIBERS; /* Create the new stack */ stack.ss_flags = 0; stack.ss_size = FIBER_STACK; stack.ss_sp = malloc( FIBER_STACK ); if ( stack.ss_sp == 0 ) { LF_DEBUG_OUT( "Error: Could not allocate stack." ); return LF_MALLOCERROR; } LF_DEBUG_OUT1( "Stack address from malloc = %p", stack.ss_sp ); #ifdef VALGRIND /* Sadly, this *still* doesn't fix all warnings. */ fiberList[numFibers].stackId = VALGRIND_STACK_REGISTER(stack.ss_sp, ((char*) stack.ss_sp + FIBER_STACK)); #endif /* Install the new stack for the signal handler */ if ( sigaltstack( &stack, &oldStack ) ) { LF_DEBUG_OUT( "Error: sigaltstack failed." ); return LF_SIGNALERROR; } /* Install the signal handler */ /* Sigaction *must* be used so we can specify SA_ONSTACK */ handler.sa_handler = &usr1handlerCreateStack; handler.sa_flags = SA_ONSTACK; sigemptyset( &handler.sa_mask ); if ( sigaction( SIGUSR1, &handler, &oldHandler ) ) { LF_DEBUG_OUT( "Error: sigaction failed." ); return LF_SIGNALERROR; } /* Call the handler on the new stack */ if ( raise( SIGUSR1 ) ) { LF_DEBUG_OUT( "Error: raise failed." ); return LF_SIGNALERROR; } /* Restore the original stack and handler */ sigaltstack( &oldStack, 0 ); sigaction( SIGUSR1, &oldHandler, 0 ); /* We now have an additional fiber, ready to roll */ fiberList[numFibers].active = 1; fiberList[numFibers].function = func; fiberList[numFibers].stack = stack.ss_sp; ++ numFibers; return LF_NOERROR; }