|  |  | @ -6,7 +6,7 @@ pool_t* tiny_pool_create(uint32_t size) { | 
			
		
	
		
			
				
					|  |  |  |     /// thread pool struct create
 | 
			
		
	
		
			
				
					|  |  |  |     pool_t *pool = (pool_t*)malloc(sizeof(pool_t)); | 
			
		
	
		
			
				
					|  |  |  |     if (pool == NULL) { | 
			
		
	
		
			
				
					|  |  |  |         return NULL; // malloc pool failed -> stop create
 | 
			
		
	
		
			
				
					|  |  |  |         return NULL; // malloc pool failed -> revoke create
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /// threads memory initialize
 | 
			
		
	
	
		
			
				
					|  |  | @ -14,7 +14,7 @@ pool_t* tiny_pool_create(uint32_t size) { | 
			
		
	
		
			
				
					|  |  |  |     pool->threads = (pthread_t*)malloc(sizeof(pthread_t) * size); | 
			
		
	
		
			
				
					|  |  |  |     if (pool->threads == NULL) { | 
			
		
	
		
			
				
					|  |  |  |         free(pool); | 
			
		
	
		
			
				
					|  |  |  |         return NULL; // malloc threads failed -> stop create
 | 
			
		
	
		
			
				
					|  |  |  |         return NULL; // malloc threads failed -> revoke create
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     memset(pool->threads, 0, sizeof(pthread_t) * size); // clean thread ids as zero
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -25,64 +25,30 @@ pool_t* tiny_pool_create(uint32_t size) { | 
			
		
	
		
			
				
					|  |  |  |     pool->task_queue_rear = NULL; | 
			
		
	
		
			
				
					|  |  |  |     pool->task_queue_front = NULL; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /// thread mutex initialization
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     pthread_mutex_init(&pool->mutex, NULL); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    if (pthread_mutex_init(&pool->status_mutex, NULL)) {
 | 
			
		
	
		
			
				
					|  |  |  | //        free(pool->threads);
 | 
			
		
	
		
			
				
					|  |  |  | //        free(pool);
 | 
			
		
	
		
			
				
					|  |  |  | //        return NULL; // status mutex init error -> stop create
 | 
			
		
	
		
			
				
					|  |  |  | //    }
 | 
			
		
	
		
			
				
					|  |  |  | //    if (pthread_mutex_init(&pool->task_queue_busy, NULL)) {
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_destroy(&pool->status_mutex);
 | 
			
		
	
		
			
				
					|  |  |  | //        free(pool->threads);
 | 
			
		
	
		
			
				
					|  |  |  | //        free(pool);
 | 
			
		
	
		
			
				
					|  |  |  | //        return NULL; // queue mutex init error -> stop create
 | 
			
		
	
		
			
				
					|  |  |  | //    }
 | 
			
		
	
		
			
				
					|  |  |  | //    if (pthread_mutex_init(&pool->busy_thr_num_mutex, NULL)) {
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_destroy(&pool->task_queue_busy);
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_destroy(&pool->status_mutex);
 | 
			
		
	
		
			
				
					|  |  |  | //        free(pool->threads);
 | 
			
		
	
		
			
				
					|  |  |  | //        free(pool);
 | 
			
		
	
		
			
				
					|  |  |  | //        return NULL; // busy thread num mutex init error -> stop create
 | 
			
		
	
		
			
				
					|  |  |  | //    }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /// thread condition variable initialization
 | 
			
		
	
		
			
				
					|  |  |  |     /// mutex and conditions initialization
 | 
			
		
	
		
			
				
					|  |  |  |     if (pthread_mutex_init(&pool->mutex, NULL)) { | 
			
		
	
		
			
				
					|  |  |  |         free(pool->threads); | 
			
		
	
		
			
				
					|  |  |  |         free(pool); | 
			
		
	
		
			
				
					|  |  |  |         return NULL; // global mutex init error -> revoke create
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     if (pthread_cond_init(&pool->task_queue_empty, NULL)) { | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_destroy(&pool->busy_thr_num_mutex);
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_destroy(&pool->task_queue_busy);
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_destroy(&pool->status_mutex);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         pthread_mutex_destroy(&pool->mutex); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         free(pool->threads); | 
			
		
	
		
			
				
					|  |  |  |         free(pool); | 
			
		
	
		
			
				
					|  |  |  |         return NULL; // pthread cond init error -> stop create
 | 
			
		
	
		
			
				
					|  |  |  |         return NULL; // task queue cond init error -> revoke create
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     if (pthread_cond_init(&pool->task_queue_not_empty, NULL)) { | 
			
		
	
		
			
				
					|  |  |  |         pthread_cond_destroy(&pool->task_queue_empty); | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_destroy(&pool->busy_thr_num_mutex);
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_destroy(&pool->task_queue_busy);
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_destroy(&pool->status_mutex);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         pthread_mutex_destroy(&pool->mutex); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         free(pool->threads); | 
			
		
	
		
			
				
					|  |  |  |         free(pool); | 
			
		
	
		
			
				
					|  |  |  |         return NULL; | 
			
		
	
		
			
				
					|  |  |  |         return NULL; // task queue cond init error -> revoke create
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     return pool; // tiny thread pool create success
 | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void task_queue_push(pool_t *pool, task_t *task) { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("push one task\n"); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    pthread_mutex_lock(&pool->task_queue_busy); // lock task queue
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("start push process\n"); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("push new task\n"); | 
			
		
	
		
			
				
					|  |  |  |     if (pool->task_queue_rear == NULL) { // task queue is empty
 | 
			
		
	
		
			
				
					|  |  |  |         pool->task_queue_front = task; | 
			
		
	
		
			
				
					|  |  |  |         pool->task_queue_rear = task; // init task queue with one element
 | 
			
		
	
	
		
			
				
					|  |  | @ -91,188 +57,119 @@ void task_queue_push(pool_t *pool, task_t *task) { | 
			
		
	
		
			
				
					|  |  |  |         pool->task_queue_rear = task; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     ++pool->task_queue_size; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("push success -> size = %d\n", pool->task_queue_size); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    bool signal_flag = false;
 | 
			
		
	
		
			
				
					|  |  |  | //    if (pool->status > PREPARING) {
 | 
			
		
	
		
			
				
					|  |  |  | //        signal_flag = true;
 | 
			
		
	
		
			
				
					|  |  |  | //    }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    pthread_mutex_unlock(&pool->task_queue_busy); // unlock task queue
 | 
			
		
	
		
			
				
					|  |  |  |     pthread_mutex_unlock(&pool->mutex); // unlock task queue
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    if (pool->status > PREPARING) { // avoid send signal in PREPARING stage
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    if (signal_flag) {
 | 
			
		
	
		
			
				
					|  |  |  | //
 | 
			
		
	
		
			
				
					|  |  |  | //        printf("signal -> queue not empty\n");
 | 
			
		
	
		
			
				
					|  |  |  | //
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_cond_signal(&pool->task_queue_not_empty); // active one blocking thread
 | 
			
		
	
		
			
				
					|  |  |  | //    }
 | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | task_t* task_queue_pop(pool_t *pool) { // pop one task with blocking wait
 | 
			
		
	
		
			
				
					|  |  |  |     printf("%lu -> pop one task\n", pthread_self()); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("%lu -> try pop one task\n", pthread_self()); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    pthread_mutex_lock(&pool->task_queue_busy); // lock task queue
 | 
			
		
	
		
			
				
					|  |  |  |     pthread_mutex_lock(&pool->mutex); // lock task queue
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /// wait until task queue not empty
 | 
			
		
	
		
			
				
					|  |  |  |     pthread_mutex_lock(&pool->mutex); // lock pool struct
 | 
			
		
	
		
			
				
					|  |  |  |     while (pool->task_queue_front == NULL) { // loop until task queue not empty
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         printf("%lu -> pop start wait\n", pthread_self()); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // TODO: at EXITING process may receive active broadcast -> we should stop pop task here
 | 
			
		
	
		
			
				
					|  |  |  |         //       should we cancel thread here directly, or return NULL for sub thread loop?
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_cond_wait(&pool->task_queue_not_empty, &pool->task_queue_busy); // wait new task added
 | 
			
		
	
		
			
				
					|  |  |  |         pthread_cond_wait(&pool->task_queue_not_empty, &pool->mutex); // wait new task added
 | 
			
		
	
		
			
				
					|  |  |  |         // TODO: for now, it seems that first one is more suitable
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         printf("%lu -> pop exit wait\n", pthread_self()); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         if (pool->status == EXITING) { | 
			
		
	
		
			
				
					|  |  |  |             pthread_exit(NULL); // sub thread exit at EXITING stage
 | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("%lu -> pop new task\n", pthread_self()); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     bool queue_empty = false; | 
			
		
	
		
			
				
					|  |  |  |     /// pop first task from queue
 | 
			
		
	
		
			
				
					|  |  |  |     bool empty_flag = false; | 
			
		
	
		
			
				
					|  |  |  |     task_t *front = pool->task_queue_front; | 
			
		
	
		
			
				
					|  |  |  |     if (pool->task_queue_front == pool->task_queue_rear) { // only one element
 | 
			
		
	
		
			
				
					|  |  |  |         pool->task_queue_front = NULL; // clear task queue
 | 
			
		
	
		
			
				
					|  |  |  |         pool->task_queue_rear = NULL; | 
			
		
	
		
			
				
					|  |  |  |         queue_empty = true; | 
			
		
	
		
			
				
					|  |  |  |     } else { | 
			
		
	
		
			
				
					|  |  |  |     pool->task_queue_front = front->next; // pop first task
 | 
			
		
	
		
			
				
					|  |  |  |     if (front->next == NULL) { // only one element
 | 
			
		
	
		
			
				
					|  |  |  |         pool->task_queue_rear = NULL; // clear task queue
 | 
			
		
	
		
			
				
					|  |  |  |         empty_flag = true; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     --pool->task_queue_size; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     ++pool->busy_thr_num; // task must pop by one ready thread
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("%lu -> pop success -> size = %d\n", pthread_self(), pool->task_queue_size); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    pthread_mutex_unlock(&pool->task_queue_busy); // unlock task queue
 | 
			
		
	
		
			
				
					|  |  |  |     pthread_mutex_unlock(&pool->mutex); // unlock task queue
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     if (queue_empty) { // send signal after mutex unlocked
 | 
			
		
	
		
			
				
					|  |  |  |         pthread_cond_signal(&pool->task_queue_empty); // active blocking pool join thread
 | 
			
		
	
		
			
				
					|  |  |  |     /// send signal to active blocking thread
 | 
			
		
	
		
			
				
					|  |  |  |     if (empty_flag) { // send signal after mutex unlocked
 | 
			
		
	
		
			
				
					|  |  |  |         pthread_cond_signal(&pool->task_queue_empty); // active pool join thread
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     return front; // success pop one task
 | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | bool tiny_pool_submit(pool_t *pool, void (*func)(void*), void *arg) { | 
			
		
	
		
			
				
					|  |  |  |     /// pre-check to avoid invalid mutex waiting
 | 
			
		
	
		
			
				
					|  |  |  |     if (pool->status > RUNNING) { | 
			
		
	
		
			
				
					|  |  |  |         return false; // allow to add task at PREPARING and RUNNING stage
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // TODO: pre-check status here: if > RUNNING --> return false
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /// initialize task structure
 | 
			
		
	
		
			
				
					|  |  |  |     task_t *new_task = (task_t*)malloc(sizeof(task_t)); | 
			
		
	
		
			
				
					|  |  |  |     if (new_task == NULL) { | 
			
		
	
		
			
				
					|  |  |  |         return false; // malloc new task error -> stop submit
 | 
			
		
	
		
			
				
					|  |  |  |         return false; // malloc new task error -> failed submit
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     new_task->entry = func; // load custom task
 | 
			
		
	
		
			
				
					|  |  |  |     new_task->arg = arg; | 
			
		
	
		
			
				
					|  |  |  |     new_task->next = NULL; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // TODO: warning -> check dead lock here
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    pthread_mutex_lock(&pool->status_mutex);
 | 
			
		
	
		
			
				
					|  |  |  |     /// handle task submit
 | 
			
		
	
		
			
				
					|  |  |  |     pthread_mutex_lock(&pool->mutex); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     //    pthread_mutex_lock(&pool->mutex); // lock task queue
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     if (pool->status > RUNNING) { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     if (pool->status > RUNNING) { // pool stage recheck after mutex lock
 | 
			
		
	
		
			
				
					|  |  |  |         pthread_mutex_unlock(&pool->mutex); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         free(new_task); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         return false; // adding task is prohibited after STOPPING
 | 
			
		
	
		
			
				
					|  |  |  |     } else { | 
			
		
	
		
			
				
					|  |  |  |         task_queue_push(pool, new_task); // push into task queue
 | 
			
		
	
		
			
				
					|  |  |  |         return false; // adding task is prohibited after RUNNING
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     task_queue_push(pool, new_task); // push into task queue
 | 
			
		
	
		
			
				
					|  |  |  |     bool signal_flag = false; | 
			
		
	
		
			
				
					|  |  |  |     if (pool->status > PREPARING) { | 
			
		
	
		
			
				
					|  |  |  |     if (pool->status > PREPARING) { // only send active signal at RUNNING stage
 | 
			
		
	
		
			
				
					|  |  |  |         signal_flag = true; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     pthread_mutex_unlock(&pool->mutex); // send signal after mutex unlock -> reduce thread churn
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    pthread_mutex_unlock(&pool->status_mutex);
 | 
			
		
	
		
			
				
					|  |  |  |     pthread_mutex_unlock(&pool->mutex); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /// send signal to active blocking thread
 | 
			
		
	
		
			
				
					|  |  |  |     if (signal_flag) { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         printf("signal -> queue not empty\n"); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         pthread_cond_signal(&pool->task_queue_not_empty); // active one blocking thread
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     return true; // task push success
 | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | void* thread_entry(void *pool_ptr) { // main loop for sub thread
 | 
			
		
	
		
			
				
					|  |  |  |     pool_t *pool = (pool_t*)pool_ptr; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("start thread %lu\n", pthread_self()); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     while (pool->status != EXITING) { // loop until enter EXITING mode
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("%lu -> sub thread begin\n", pthread_self()); | 
			
		
	
		
			
				
					|  |  |  |     while (pool->status != EXITING) { // loop until enter EXITING stage
 | 
			
		
	
		
			
				
					|  |  |  |         printf("%lu -> sub thread working\n", pthread_self()); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         /// pop a task and execute it
 | 
			
		
	
		
			
				
					|  |  |  |         task_t *task = task_queue_pop(pool); // pop one task -> blocking function
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_lock(&pool->busy_thr_num_mutex);
 | 
			
		
	
		
			
				
					|  |  |  | //        ++pool->busy_thr_num; // change busy thread number
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_unlock(&pool->busy_thr_num_mutex);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         task->entry(task->arg); // start running task function
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         free(task); // free allocated memory
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_lock(&pool->busy_thr_num_mutex);
 | 
			
		
	
		
			
				
					|  |  |  |         /// mark thread as idle
 | 
			
		
	
		
			
				
					|  |  |  |         pthread_mutex_lock(&pool->mutex); | 
			
		
	
		
			
				
					|  |  |  |         --pool->busy_thr_num; // change busy thread number
 | 
			
		
	
		
			
				
					|  |  |  |         pthread_mutex_unlock(&pool->mutex); | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_unlock(&pool->busy_thr_num_mutex);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("%lu -> sub thread exit\n", pthread_self()); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     pthread_exit(NULL); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     return NULL; // sub thread exit
 | 
			
		
	
		
			
				
					|  |  |  |     pthread_exit(NULL); // sub thread exit
 | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | // TODO: should we return a bool value?
 | 
			
		
	
		
			
				
					|  |  |  | void tiny_pool_boot(pool_t *pool) { | 
			
		
	
		
			
				
					|  |  |  |     /// pre-check to avoid invalid mutex waiting
 | 
			
		
	
		
			
				
					|  |  |  |     if (pool->status != PREPARING) { | 
			
		
	
		
			
				
					|  |  |  |         return; // only allow to boot at PREPARING stage
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // TODO: avoid booting multi-times
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // TODO: pre-check pool status: if != PREPARING --> return
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    pthread_mutex_lock(&pool->status_mutex);
 | 
			
		
	
		
			
				
					|  |  |  |     /// handle pool thread booting
 | 
			
		
	
		
			
				
					|  |  |  |     pthread_mutex_lock(&pool->mutex); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     if (pool->status != PREPARING) { | 
			
		
	
		
			
				
					|  |  |  | //        pthread_mutex_unlock(&pool->status_mutex);
 | 
			
		
	
		
			
				
					|  |  |  |         pthread_mutex_unlock(&pool->mutex); | 
			
		
	
		
			
				
					|  |  |  |         return; | 
			
		
	
		
			
				
					|  |  |  |         return; // only allow to boot at PREPARING stage
 | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     pool->status = RUNNING; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    pthread_mutex_lock(&pool->task_queue_busy);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     for (uint32_t i = 0; i < pool->thread_num; ++i) { | 
			
		
	
		
			
				
					|  |  |  |     for (uint32_t i = 0; i < pool->thread_num; ++i) { // create working threads
 | 
			
		
	
		
			
				
					|  |  |  |         pthread_create(&(pool->threads[i]), NULL, thread_entry, (void*)pool); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("thread boot complete\n"); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    pthread_mutex_unlock(&pool->task_queue_busy);
 | 
			
		
	
		
			
				
					|  |  |  | //    pthread_mutex_unlock(&pool->status_mutex);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     pthread_mutex_unlock(&pool->mutex); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | bool tiny_pool_join(pool_t *pool) { | 
			
		
	
	
		
			
				
					|  |  | @ -285,7 +182,6 @@ bool tiny_pool_join(pool_t *pool) { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // TODO: signal broadcast -> wait all thread exit
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     printf("start pool join\n"); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | //    pthread_mutex_lock(&pool->status_mutex);
 | 
			
		
	
	
		
			
				
					|  |  | 
 |