co_routine.cpp/.h/inner.h(第三部分)—— libco源碼分析、學習筆記

博客一級目錄

二級目錄——libco源碼分析/學習筆記

由於本源代碼蠻長的,所以按照功能劃分模塊來分析,分爲若干部分,詳見二級目錄↑

代碼文件:co_routine.hco_routine.cppco_routine_inner.h

三、協程的執行

void co_yield_env( stCoRoutineEnv_t *env );//將當前執行的env從協程棧中出棧並將執行權交給父協程。

void co_yield_env( stCoRoutineEnv_t *env )
{
	
	stCoRoutine_t *last = env->pCallStack[ env->iCallStackSize - 2 ];
	stCoRoutine_t *curr = env->pCallStack[ env->iCallStackSize - 1 ];

	env->iCallStackSize--;

	co_swap( curr, last);
}
//切出到主協程
void co_yield_ct()
{
	co_yield_env( co_get_curr_thread_env() );
}
//跟co_yield_env功能一樣只是參數不同。
void co_yield( stCoRoutine_t *co )
{
	co_yield_env( co->env );
}

static int CoRoutineFunc( stCoRoutine_t *co,void * );函數內調用了pfn函數(pfn函數就是協程的主函數)
執行完畢後cEnd標記爲1

這裏修改了子協程的env就完成了出棧工作,說明,env是父子協程共享的。

static int CoRoutineFunc( stCoRoutine_t *co,void * )
{
	if( co->pfn )
	{
		co->pfn( co->arg );//執行主函數,內部允許嵌套有限數量的協程調用
	}
	co->cEnd = 1;//執行完畢後標記爲1

	stCoRoutineEnv_t *env = co->env;//env是指針,修改後co的原內容也同步改變。其實下面可以直接寫co->env,因爲下面的函數沒有改變env指針值。

	co_yield_env( env );//將當前執行的co從協程棧中出棧並將執行權交給父協程。

	return 0;
}

void co_free( stCoRoutine_t *co );//負責協程銷燬工作。主要是提前銷燬用戶棧。推測這裏的用戶棧不能是從share棧上摘下來的。

void co_free( stCoRoutine_t *co )
{
    if (!co->cIsShareStack) 
    {    
        free(co->stack_mem->stack_buffer);
        free(co->stack_mem);
    }   
    free( co );
}

void co_release( stCoRoutine_t *co );//銷燬co但是不銷燬用戶棧,推測是因爲這裏的用戶棧是從share棧上摘下來的,所以不需要歸還os還可以重複利用。

void co_release( stCoRoutine_t *co )//銷燬co但是不銷燬用戶棧
{
    co_free( co );
}

void save_stack_buffer(stCoRoutine_t* occupy_co);//用於備份用戶棧有效數據。

void save_stack_buffer(stCoRoutine_t* occupy_co)
{
	///copy out
	stStackMem_t* stack_mem = occupy_co->stack_mem;//取用戶棧
	int len = stack_mem->stack_bp - occupy_co->stack_sp;//計算有效數據長度

	if (occupy_co->save_buffer)
	{
		free(occupy_co->save_buffer), occupy_co->save_buffer = NULL;
	}

	occupy_co->save_buffer = (char*)malloc(len); //malloc buf;
	occupy_co->save_size = len;

	memcpy(occupy_co->save_buffer, occupy_co->stack_sp, len);
}

co_swap,沒看懂,佔坑待補

在一些參考博客fork的代碼中,發現沒有此函數(一些occupy之類的東西也沒有),所以這個函數可能是是官方後來更新上去的。其功能先認爲跟coctx_swap相同吧(學習要連猜帶蒙......)。

void co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co)
{
 	stCoRoutineEnv_t* env = co_get_curr_thread_env();

	//get curr stack sp
	char c;
	curr->stack_sp= &c;

	if (!pending_co->cIsShareStack)    
	{
		env->pending_co = NULL;
		env->occupy_co = NULL;
	}
	else 
	{
		env->pending_co = pending_co;
		//get last occupy co on the same stack mem
		stCoRoutine_t* occupy_co = pending_co->stack_mem->occupy_co;
		//set pending co to occupy thest stack mem;
		pending_co->stack_mem->occupy_co = pending_co;

		env->occupy_co = occupy_co;
		if (occupy_co && occupy_co != pending_co)
		{
			save_stack_buffer(occupy_co);
		}
	}

	//swap context
	coctx_swap(&(curr->ctx),&(pending_co->ctx) );

	//stack buffer may be overwrite, so get again;
	stCoRoutineEnv_t* curr_env = co_get_curr_thread_env();
	stCoRoutine_t* update_occupy_co =  curr_env->occupy_co;
	stCoRoutine_t* update_pending_co = curr_env->pending_co;
	
	if (update_occupy_co && update_pending_co && update_occupy_co != update_pending_co)
	{
		//resume stack buffer
		if (update_pending_co->save_buffer && update_pending_co->save_size > 0)
		{
			memcpy(update_pending_co->stack_sp, update_pending_co->save_buffer, update_pending_co->save_size);
		}
	}
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章