Skip to content

Commit 58f437c

Browse files
committed
add aco_yield_to()
1 parent e3058b3 commit 58f437c

File tree

3 files changed

+131
-92
lines changed

3 files changed

+131
-92
lines changed

β€ŽREADME.mdβ€Ž

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Note: Please use [releases][github-release] instead of the `master` to build the
5050
* [aco_create](#aco_create)
5151
* [aco_resume](#aco_resume)
5252
* [aco_yield](#aco_yield)
53+
* [aco_yield_to](#aco_yield_to)
5354
* [aco_get_co](#aco_get_co)
5455
* [aco_get_arg](#aco_get_arg)
5556
* [aco_exit](#aco_exit)
@@ -375,6 +376,18 @@ Yield the execution of `co` and resume `co->main_co`. The caller of this functio
375376

376377
After the call of `aco_yield`, we name the state of the caller β€” `co` as "yielded".
377378

379+
## aco_yield_to
380+
381+
```c
382+
void aco_yield_to(aco_t* resume_co);
383+
```
384+
385+
Yield the execution of `co` and resume `resume_co`. The caller of this function must be a non-main co. And `co->main_co` and `resume_co->main_co` must be equal to each other and different of NULL.
386+
387+
After the call of `aco_yield_to`, we name the state of the caller β€” `co` as "yielded".
388+
389+
`aco_yield_to()` is useful when a non-main co wants to yield to another co with a single switch. Without `aco_yield_to()`, one has to go through two switches: one switch back to main co and another switch to the desired non-main co.
390+
378391
## aco_get_co
379392
380393
```c

β€Žaco.cβ€Ž

Lines changed: 115 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -361,121 +361,144 @@ aco_t* aco_create(
361361
}
362362

363363
aco_attr_no_asan
364-
void aco_resume(aco_t* resume_co){
365-
assert(resume_co != NULL && resume_co->main_co != NULL
366-
&& resume_co->is_end == 0
367-
);
368-
if(resume_co->share_stack->owner != resume_co){
369-
if(resume_co->share_stack->owner != NULL){
370-
aco_t* owner_co = resume_co->share_stack->owner;
371-
assert(owner_co->share_stack == resume_co->share_stack);
364+
static void aco_own_stack(aco_t* co){
365+
if(co->share_stack->owner == co){
366+
return;
367+
}
368+
369+
if(co->share_stack->owner != NULL){
370+
aco_t* owner_co = co->share_stack->owner;
371+
assert(owner_co->share_stack == co->share_stack);
372372
#if defined(__i386__) || defined(__x86_64__)
373-
assert(
374-
(
375-
(uintptr_t)(owner_co->share_stack->align_retptr)
376-
>=
377-
(uintptr_t)(owner_co->reg[ACO_REG_IDX_SP])
378-
)
379-
&&
380-
(
381-
(uintptr_t)(owner_co->share_stack->align_highptr)
382-
-
383-
(uintptr_t)(owner_co->share_stack->align_limit)
384-
<=
385-
(uintptr_t)(owner_co->reg[ACO_REG_IDX_SP])
386-
)
387-
);
388-
owner_co->save_stack.valid_sz =
373+
assert(
374+
(
389375
(uintptr_t)(owner_co->share_stack->align_retptr)
376+
>=
377+
(uintptr_t)(owner_co->reg[ACO_REG_IDX_SP])
378+
)
379+
&&
380+
(
381+
(uintptr_t)(owner_co->share_stack->align_highptr)
390382
-
391-
(uintptr_t)(owner_co->reg[ACO_REG_IDX_SP]);
392-
if(owner_co->save_stack.sz < owner_co->save_stack.valid_sz){
393-
free(owner_co->save_stack.ptr);
394-
owner_co->save_stack.ptr = NULL;
395-
while(1){
396-
owner_co->save_stack.sz = owner_co->save_stack.sz << 1;
397-
assert(owner_co->save_stack.sz > 0);
398-
if(owner_co->save_stack.sz >= owner_co->save_stack.valid_sz){
399-
break;
400-
}
383+
(uintptr_t)(owner_co->share_stack->align_limit)
384+
<=
385+
(uintptr_t)(owner_co->reg[ACO_REG_IDX_SP])
386+
)
387+
);
388+
owner_co->save_stack.valid_sz =
389+
(uintptr_t)(owner_co->share_stack->align_retptr)
390+
-
391+
(uintptr_t)(owner_co->reg[ACO_REG_IDX_SP]);
392+
if(owner_co->save_stack.sz < owner_co->save_stack.valid_sz){
393+
free(owner_co->save_stack.ptr);
394+
owner_co->save_stack.ptr = NULL;
395+
while(1){
396+
owner_co->save_stack.sz = owner_co->save_stack.sz << 1;
397+
assert(owner_co->save_stack.sz > 0);
398+
if(owner_co->save_stack.sz >= owner_co->save_stack.valid_sz){
399+
break;
401400
}
402-
owner_co->save_stack.ptr = malloc(owner_co->save_stack.sz);
403-
assertalloc_ptr(owner_co->save_stack.ptr);
404401
}
405-
// TODO: optimize the performance penalty of memcpy function call
406-
// for very short memory span
407-
if(owner_co->save_stack.valid_sz > 0) {
408-
#ifdef __x86_64__
409-
aco_amd64_optimized_memcpy_drop_in(
410-
owner_co->save_stack.ptr,
411-
owner_co->reg[ACO_REG_IDX_SP],
412-
owner_co->save_stack.valid_sz
413-
);
414-
#else
415-
memcpy(
416-
owner_co->save_stack.ptr,
417-
owner_co->reg[ACO_REG_IDX_SP],
418-
owner_co->save_stack.valid_sz
419-
);
420-
#endif
421-
owner_co->save_stack.ct_save++;
422-
}
423-
if(owner_co->save_stack.valid_sz > owner_co->save_stack.max_cpsz){
424-
owner_co->save_stack.max_cpsz = owner_co->save_stack.valid_sz;
425-
}
426-
owner_co->share_stack->owner = NULL;
427-
owner_co->share_stack->align_validsz = 0;
428-
#else
429-
#error "platform no support yet"
430-
#endif
402+
owner_co->save_stack.ptr = malloc(owner_co->save_stack.sz);
403+
assertalloc_ptr(owner_co->save_stack.ptr);
431404
}
432-
assert(resume_co->share_stack->owner == NULL);
433-
#if defined(__i386__) || defined(__x86_64__)
434-
assert(
435-
resume_co->save_stack.valid_sz
436-
<=
437-
resume_co->share_stack->align_limit - sizeof(void*)
438-
);
439405
// TODO: optimize the performance penalty of memcpy function call
440406
// for very short memory span
441-
if(resume_co->save_stack.valid_sz > 0) {
442-
#ifdef __x86_64__
407+
if(owner_co->save_stack.valid_sz > 0) {
408+
#ifdef __x86_64__
443409
aco_amd64_optimized_memcpy_drop_in(
444-
(void*)(
445-
(uintptr_t)(resume_co->share_stack->align_retptr)
446-
-
447-
resume_co->save_stack.valid_sz
448-
),
449-
resume_co->save_stack.ptr,
450-
resume_co->save_stack.valid_sz
410+
owner_co->save_stack.ptr,
411+
owner_co->reg[ACO_REG_IDX_SP],
412+
owner_co->save_stack.valid_sz
451413
);
452-
#else
414+
#else
453415
memcpy(
454-
(void*)(
455-
(uintptr_t)(resume_co->share_stack->align_retptr)
456-
-
457-
resume_co->save_stack.valid_sz
458-
),
459-
resume_co->save_stack.ptr,
460-
resume_co->save_stack.valid_sz
416+
owner_co->save_stack.ptr,
417+
owner_co->reg[ACO_REG_IDX_SP],
418+
owner_co->save_stack.valid_sz
461419
);
462-
#endif
463-
resume_co->save_stack.ct_restore++;
420+
#endif
421+
owner_co->save_stack.ct_save++;
464422
}
465-
if(resume_co->save_stack.valid_sz > resume_co->save_stack.max_cpsz){
466-
resume_co->save_stack.max_cpsz = resume_co->save_stack.valid_sz;
423+
if(owner_co->save_stack.valid_sz > owner_co->save_stack.max_cpsz){
424+
owner_co->save_stack.max_cpsz = owner_co->save_stack.valid_sz;
467425
}
468-
resume_co->share_stack->align_validsz = resume_co->save_stack.valid_sz + sizeof(void*);
469-
resume_co->share_stack->owner = resume_co;
426+
owner_co->share_stack->owner = NULL;
427+
owner_co->share_stack->align_validsz = 0;
470428
#else
471429
#error "platform no support yet"
472430
#endif
473431
}
432+
assert(co->share_stack->owner == NULL);
433+
#if defined(__i386__) || defined(__x86_64__)
434+
assert(
435+
co->save_stack.valid_sz
436+
<=
437+
co->share_stack->align_limit - sizeof(void*)
438+
);
439+
// TODO: optimize the performance penalty of memcpy function call
440+
// for very short memory span
441+
if(co->save_stack.valid_sz > 0) {
442+
#ifdef __x86_64__
443+
aco_amd64_optimized_memcpy_drop_in(
444+
(void*)(
445+
(uintptr_t)(co->share_stack->align_retptr)
446+
-
447+
co->save_stack.valid_sz
448+
),
449+
co->save_stack.ptr,
450+
co->save_stack.valid_sz
451+
);
452+
#else
453+
memcpy(
454+
(void*)(
455+
(uintptr_t)(co->share_stack->align_retptr)
456+
-
457+
co->save_stack.valid_sz
458+
),
459+
co->save_stack.ptr,
460+
co->save_stack.valid_sz
461+
);
462+
#endif
463+
co->save_stack.ct_restore++;
464+
}
465+
if(co->save_stack.valid_sz > co->save_stack.max_cpsz){
466+
co->save_stack.max_cpsz = co->save_stack.valid_sz;
467+
}
468+
co->share_stack->align_validsz = co->save_stack.valid_sz + sizeof(void*);
469+
co->share_stack->owner = co;
470+
#else
471+
#error "platform no support yet"
472+
#endif
473+
}
474+
475+
aco_attr_no_asan
476+
void aco_resume(aco_t* resume_co){
477+
assert(resume_co != NULL && resume_co->main_co != NULL
478+
&& resume_co->is_end == 0
479+
);
480+
aco_own_stack(resume_co);
474481
aco_gtls_co = resume_co;
475482
acosw(resume_co->main_co, resume_co);
476483
aco_gtls_co = resume_co->main_co;
477484
}
478485

486+
aco_attr_no_asan
487+
void aco_yield_to(aco_t* resume_co){
488+
assert(resume_co != NULL && resume_co->main_co != NULL
489+
&& resume_co->is_end == 0
490+
);
491+
if(aco_unlikely(resume_co == aco_gtls_co)){
492+
// Nothing to do
493+
return;
494+
}
495+
assert(resume_co->main_co == aco_gtls_co->main_co);
496+
aco_own_stack(resume_co);
497+
aco_t* yield_co = aco_gtls_co;
498+
aco_gtls_co = resume_co;
499+
acosw(yield_co, resume_co);
500+
}
501+
479502
void aco_destroy(aco_t* co){
480503
assertptr(co);
481504
if(aco_is_main_co(co)){

β€Žaco.hβ€Ž

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ extern __thread aco_t* aco_gtls_co;
186186
aco_attr_no_asan
187187
extern void aco_resume(aco_t* resume_co);
188188

189+
aco_attr_no_asan
190+
void aco_yield_to(aco_t* yield_co);
191+
189192
//extern void aco_yield1(aco_t* yield_co);
190193
#define aco_yield1(yield_co) do { \
191194
aco_assertptr((yield_co)); \

0 commit comments

Comments
Β (0)