前段时间实现的C协程依赖栈传递参数,在开启优化时会导致错误,于是实现了一个ucontext的版本,但ucontext的切换效率太差了,
在我的机器上执行4000W次切换需要11秒左右,这达不到我的要求,所以重新设计了实现,使得在开启优化时也能得到正确的结果.
并且效率也令人满意,4000W次切换仅需要730ms左右,足足比ucontext的实现快乐近15倍。
下面贴出实现:
1 #include "uthread.h" 2 #include <stdlib.h> 3 #include <ucontext.h> 4 #include <pthread.h> 5 #include "link_list.h" 6 7 struct uthread 8 { 9 int32_t reg[8];//0:esp,1:ebp,2:eax,3:ebx,4:ecx,5:edx,6:edi,7:esi 10 void *para; 11 uthread_t parent; 12 void*(*main_fun)(void*); 13 void *stack; 14 int32_t ssize; 15 int8_t first_run; 16 }; 17 18 #ifdef _DEBUG 19 //for debug version 20 void uthread_main_function() 21 { 22 int32_t arg; 23 __asm__ volatile( 24 "movl %%eax,%0 " 25 : 26 :"m"(arg) 27 ); 28 29 uthread_t u = (uthread_t)arg; 30 void *ret = u->main_fun(u->para); 31 if(u->parent) 32 uthread_switch(u,u->parent,ret); 33 else 34 exit(0); 35 } 36 #else 37 //for release version 38 void __attribute__((regparm(1))) uthread_main_function(void *arg) 39 { 40 uthread_t u = (uthread_t)arg; 41 void *ret = u->main_fun(u->para); 42 if(u->parent) 43 uthread_switch(u,u->parent,ret); 44 else 45 exit(0); 46 } 47 #endif 48 uthread_t uthread_create(uthread_t parent,void*stack,uint32_t stack_size,void*(*fun)(void*)) 49 { 50 uthread_t u = (uthread_t)calloc(1,sizeof(*u)); 51 u->parent = parent; 52 u->main_fun = fun; 53 u->stack = stack; 54 u->ssize = stack_size; 55 if(stack) 56 { 57 u->reg[0] = (int32_t)stack+stack_size-4; 58 u->reg[1] = (int32_t)stack+stack_size-4; 59 } 60 if(u->main_fun) 61 u->first_run = 1; 62 return u; 63 } 64 65 void uthread_destroy(uthread_t *u) 66 { 67 free(*u); 68 *u = NULL; 69 } 70 71 #ifdef _DEBUG 72 void* __attribute__((regparm(3))) uthread_switch(uthread_t from,uthread_t to,void *para) 73 { 74 if(!from) 75 return NULL; 76 to->para = para; 77 int32_t esp,ebp,eax,ebx,ecx,edx,edi,esi; 78 //save current registers 79 //the order is important 80 __asm__ volatile( 81 "movl %%eax,%2 " 82 "movl %%ebx,%3 " 83 "movl %%ecx,%4 " 84 "movl %%edx,%5 " 85 "movl %%edi,%6 " 86 "movl %%esi,%7 " 87 "movl %%ebp,%1 " 88 "movl %%esp,%0 " 89 : 90 :"m"(esp),"m"(ebp),"m"(eax),"m"(ebx),"m"(ecx),"m"(edx),"m"(edi),"m"(esi) 91 ); 92 from->reg[0] = esp; 93 from->reg[1] = ebp; 94 from->reg[2] = eax; 95 from->reg[3] = ebx; 96 from->reg[4] = ecx; 97 from->reg[5] = edx; 98 from->reg[6] = edi; 99 from->reg[7] = esi; 100 if(to->first_run) 101 { 102 to->first_run = 0; 103 esp = to->reg[0]; 104 //use eax to pass arg 105 eax = (int32_t)to; 106 __asm__ volatile ( 107 "movl %1,%%eax " 108 "movl %0,%%ebp " 109 "movl %%ebp,%%esp " 110 : 111 :"m"(esp),"m"(eax) 112 ); 113 uthread_main_function(); 114 } 115 else 116 { 117 esp = to->reg[0]; 118 ebp = to->reg[1]; 119 eax = to->reg[2]; 120 ebx = to->reg[3]; 121 ecx = to->reg[4]; 122 edx = to->reg[5]; 123 edi = to->reg[6]; 124 esi = to->reg[7]; 125 //the order is important 126 __asm__ volatile ( 127 "movl %2,%%eax " 128 "movl %3,%%ebx " 129 "movl %4,%%ecx " 130 "movl %5,%%edx " 131 "movl %6,%%edi " 132 "movl %7,%%esi " 133 "movl %1,%%ebp " 134 "movl %0,%%esp " 135 : 136 :"m"(esp),"m"(ebp),"m"(eax),"m"(ebx),"m"(ecx),"m"(edx),"m"(edi),"m"(esi) 137 ); 138 } 139 return from->para; 140 } 141 #else 142 void* __attribute__((regparm(3))) uthread_switch(uthread_t from,uthread_t to,void *para) 143 { 144 if(!from) 145 return NULL; 146 to->para = para; 147 int32_t esp,ebp,edi,esi; 148 //save current registers 149 //the order is important 150 __asm__ volatile( 151 "movl %%eax,%2 " 152 "movl %%ebx,%3 " 153 "movl %%ecx,%4 " 154 "movl %%edx,%5 " 155 "movl %%edi,%6 " 156 "movl %%esi,%7 " 157 "movl %%ebp,%1 " 158 "movl %%esp,%0 " 159 : 160 :"m"(from->reg[0]),"m"(from->reg[1]),"m"(from->reg[2]),"m"(from->reg[3]) 161 ,"m"(from->reg[4]),"m"(from->reg[5]),"m"(from->reg[6]),"m"(from->reg[7]) 162 ); 163 if(to->first_run) 164 { 165 to->first_run = 0; 166 //change stack 167 //the order is important 168 __asm__ volatile ( 169 "movl %0,%%ebp " 170 "movl %%ebp,%%esp " 171 : 172 :"m"(to->reg[0]) 173 ); 174 uthread_main_function((void*)to); 175 } 176 else 177 { 178 esp = to->reg[0]; 179 ebp = to->reg[1]; 180 edi = to->reg[6]; 181 esi = to->reg[7]; 182 //the order is important 183 __asm__ volatile ( 184 "movl %2,%%eax " 185 "movl %3,%%ebx " 186 "movl %4,%%ecx " 187 "movl %5,%%edx " 188 "movl %6,%%edi " 189 "movl %7,%%esi " 190 "movl %1,%%ebp " 191 "movl %0,%%esp " 192 : 193 :"m"(esp),"m"(ebp),"m"(to->reg[2]),"m"(to->reg[3]) 194 ,"m"(to->reg[4]),"m"(to->reg[5]),"m"(edi),"m"(esi) 195 ); 196 } 197 return from->para; 198 } 199 #endif
test.c
1 #include <stdio.h> 2 #include "uthread.h" 3 #include "SysTime.h" 4 #include <stdlib.h> 5 void* ufun2(void *arg) 6 { 7 printf("ufun2 "); 8 char **tmp = (char**)arg; 9 uthread_t self = (uthread_t)tmp[0]; 10 uthread_t parent = (uthread_t)tmp[1]; 11 volatile void *ptr = self; 12 while(ptr) 13 { 14 ptr = uthread_switch(self,parent,NULL); 15 } 16 return NULL; 17 } 18 19 char *stack1; 20 char *stack2; 21 22 void* ufun1(void *arg) 23 { 24 uthread_t self = (uthread_t)arg; 25 uthread_t u = uthread_create(self,stack2,4096,ufun2); 26 char* _arg[2]; 27 _arg[0] = (char*)u; 28 _arg[1] = (char*)self; 29 int i = 0; 30 uint32_t tick = GetSystemMs(); 31 for( ; i < 20000000; ++i) 32 { 33 uthread_switch(self,u,&_arg[0]); 34 } 35 printf("%d ",GetSystemMs()-tick); 36 uthread_switch(self,u,NULL); 37 return arg; 38 } 39 40 int main() 41 { 42 stack1 = (char*)malloc(4096); 43 stack2 = (char*)malloc(4096); 44 /* 45 * if use ucontext version 46 char dummy_stack[4096]; 47 uthread_t p = uthread_create(NULL,dummy_stack,0,NULL); 48 */ 49 uthread_t p = uthread_create(NULL,NULL,0,NULL); 50 uthread_t u = uthread_create(p,stack1,4096,ufun1); 51 uthread_switch(p,u,u); 52 printf("main end "); 53 return 0; 54 };
转自:https://www.cnblogs.com/sniperHW/archive/2012/08/05/2624334.html