LIBACO - Perpustakaan Coroutine C asimetris yang cepat dan ringan.
Nama kode proyek ini adalah Arkenstone?
Asimetris Coroutine & Arkenstone adalah alasan mengapa ia dinamai aco .
Saat ini mendukung SYS V ABI dari Intel386 dan X86-64.
Berikut adalah ringkasan singkat dari proyek ini:
Ungkapan " tercepat " di atas berarti implementasi switching konteks tercepat yang sesuai dengan Sys v ABI dari Intel386 atau AMD64.
Masalah dan PR dipersilakan ???
Catatan: Harap gunakan rilis sebagai ganti master untuk membangun biner akhir.
Selain readme ini, Anda juga dapat mengunjungi dokumentasi dari https://libaco.org/docs. Silakan ikuti readme ini jika ada perbedaan karena dokumentasi di situs web mungkin tertinggal dari readme ini.
Produksi siap.
#include "aco.h"
#include <stdio.h>
// this header would override the default C `assert`;
// you may refer the "API : MACROS" part for more details.
#include "aco_assert_override.h"
void foo ( int ct ) {
printf ( "co: %p: yield to main_co: %dn" , aco_get_co (), * (( int * )( aco_get_arg ())));
aco_yield ();
* (( int * )( aco_get_arg ())) = ct + 1 ;
}
void co_fp0 () {
printf ( "co: %p: entry: %dn" , aco_get_co (), * (( int * )( aco_get_arg ())));
int ct = 0 ;
while ( ct < 6 ){
foo ( ct );
ct ++ ;
}
printf ( "co: %p: exit to main_co: %dn" , aco_get_co (), * (( int * )( aco_get_arg ())));
aco_exit ();
}
int main () {
aco_thread_init ( NULL );
aco_t * main_co = aco_create ( NULL , NULL , 0 , NULL , NULL );
aco_share_stack_t * sstk = aco_share_stack_new ( 0 );
int co_ct_arg_point_to_me = 0 ;
aco_t * co = aco_create ( main_co , sstk , 0 , co_fp0 , & co_ct_arg_point_to_me );
int ct = 0 ;
while ( ct < 6 ){
assert ( co -> is_end == 0 );
printf ( "main_co: yield to co: %p: %dn" , co , ct );
aco_resume ( co );
assert ( co_ct_arg_point_to_me == ct );
ct ++ ;
}
printf ( "main_co: yield to co: %p: %dn" , co , ct );
aco_resume ( co );
assert ( co_ct_arg_point_to_me == ct );
assert ( co -> is_end );
printf ( "main_co: destroy and exitn" );
aco_destroy ( co );
co = NULL ;
aco_share_stack_destroy ( sstk );
sstk = NULL ;
aco_destroy ( main_co );
main_co = NULL ;
return 0 ;
} # default build
$ gcc -g -O2 acosw.S aco.c test_aco_synopsis.c -o test_aco_synopsis
$ ./test_aco_synopsis
main_co: yield to co: 0x1887120: 0
co: 0x1887120: entry: 0
co: 0x1887120: yield to main_co: 0
main_co: yield to co: 0x1887120: 1
co: 0x1887120: yield to main_co: 1
main_co: yield to co: 0x1887120: 2
co: 0x1887120: yield to main_co: 2
main_co: yield to co: 0x1887120: 3
co: 0x1887120: yield to main_co: 3
main_co: yield to co: 0x1887120: 4
co: 0x1887120: yield to main_co: 4
main_co: yield to co: 0x1887120: 5
co: 0x1887120: yield to main_co: 5
main_co: yield to co: 0x1887120: 6
co: 0x1887120: exit to main_co: 6
main_co: destroy and exit
# i386
$ gcc -g -m32 -O2 acosw.S aco.c test_aco_synopsis.c -o test_aco_synopsis
# share fpu and mxcsr env
$ gcc -g -D ACO_CONFIG_SHARE_FPU_MXCSR_ENV -O2 acosw.S aco.c test_aco_synopsis.c -o test_aco_synopsis
# with valgrind friendly support
$ gcc -g -D ACO_USE_VALGRIND -O2 acosw.S aco.c test_aco_synopsis.c -o test_aco_synopsis
$ valgrind --leak-check=full --tool=memcheck ./test_aco_synopsisUntuk informasi lebih lanjut, Anda dapat merujuk pada bagian "Bangun dan Uji".

Ada 4 elemen dasar dari keadaan eksekusi biasa: {cpu_registers, code, heap, stack} .
Karena informasi kode ditunjukkan oleh ({E|R})?IP , dan alamat memori yang dialokasikan dari heap biasanya disimpan dalam tumpukan secara langsung atau tidak langsung, sehingga kita dapat menyederhanakan 4 elemen menjadi hanya 2 dari mereka: {cpu_registers, stack} .

Kami mendefinisikan main co sebagai coroutine yang memonopoli tumpukan default utas saat ini. Dan karena CO utama adalah satu-satunya pengguna tumpukan ini, kita hanya perlu menyimpan/mengembalikan keadaan register CPU yang diperlukan dari CO utama ketika telah dihasilkan dari dari/dilanjutkan ke (dialihkan/dialihkan-dalam).
Selanjutnya, definisi non-main co adalah coroutine yang tumpukan eksekusi adalah tumpukan yang bukan tumpukan default dari utas saat ini dan dapat dibagikan dengan CO non-utama lainnya. Dengan demikian CO non-utama harus memiliki buffer memori private save stack untuk menyimpan/mengembalikan tumpukan eksekusi ketika telah dialihkan/dialihkan-in (karena CO berikutnya/sebelumnya akan/menggunakan/menggunakan tumpukan saham sebagai tumpukan eksekusi).

Ada kasus khusus CO non-utama, yaitu standalone non-main co yang kami sebut di Libaco: Tumpukan Saham dari Coroutine non-utama hanya memiliki satu pengguna CO. Dengan demikian tidak perlu melakukan menyimpan/memulihkan hal-hal save private-nya ketika telah dialihkan/dialihkan karena tidak ada CO lain yang akan menyentuh tumpukan eksekusi CO non-utama mandiri kecuali dirinya sendiri.

Akhirnya, kami mendapatkan gambaran besar Libaco.
Ada bagian "bukti kebenaran" yang mungkin Anda temukan sangat membantu jika Anda ingin menyelami internal Libaco atau ingin mengimplementasikan Perpustakaan Coroutine Anda sendiri.
Juga sangat disarankan untuk membaca kode sumber tutorial dan tolok ukur berikutnya. Hasil patokan juga sangat mengesankan dan mencerahkan.
-m32 Opsi -m32 dari GCC dapat membantu Anda membangun aplikasi I386 dari Libaco pada mesin x86_64.
ACO_CONFIG_SHARE_FPU_MXCSR_ENV Anda dapat mendefinisikan makro C makro global ACO_CONFIG_SHARE_FPU_MXCSR_ENV untuk mempercepat kinerja pengalihan konteks antara coroutine sedikit jika tidak ada kode Anda yang akan mengubah kata -kata kontrol FPU dan MXCSR. Jika makro tidak didefinisikan, semua CO akan mempertahankan salinannya sendiri dari kata -kata kontrol FPU dan MXCSR. Dianjurkan untuk selalu mendefinisikan makro ini secara global karena sangat jarang bahwa satu fungsi perlu mengatur Env khusus FPU atau MXCSR alih -alih menggunakan env default yang ditentukan oleh ISO C. tetapi Anda mungkin tidak perlu mendefinisikan makro ini jika Anda tidak yakin akan hal itu.
ACO_USE_VALGRIND Jika Anda ingin menggunakan alat memcheck of valgrind untuk menguji aplikasi, maka Anda mungkin perlu mendefinisikan makro c makro global ACO_USE_VALGRIND untuk memungkinkan dukungan ramah Valgrind di Libaco. Tetapi tidak disarankan untuk mendefinisikan makro ini dalam pembuatan rilis akhir untuk alasan kinerja. Anda mungkin juga perlu menginstal header Valgrind (nama paket adalah "Valgrind-devel" di CentOS misalnya) untuk membangun aplikasi Libaco dengan C makro ACO_USE_VALGRIND ditentukan. (Memcheck of Valgrind hanya bekerja dengan baik dengan CO mandiri saat ini. Dalam kasus tumpukan bersama yang digunakan oleh lebih dari satu CO non-utama, memcheck Valgrind akan menghasilkan banyak laporan positif palsu. Untuk informasi lebih lanjut, Anda dapat merujuk pada "test_aco_tutorial_6.c".)
ACO_USE_ASAN Global C makro ACO_USE_ASAN akan memungkinkan dukungan ramah sanitizer alamat di libaco (dukungan GCC dan Clang).
Untuk membangun suite uji Libaco:
$ mkdir output
$ bash make.shAda juga beberapa opsi terperinci di Make.sh:
$bash make.sh -h
Usage: make.sh [-o < no-m32 | no-valgrind > ] [-h]
Example:
# default build
bash make.sh
# build without the i386 binary output
bash make.sh -o no-m32
# build without the valgrind supported binary output
bash make.sh -o no-valgrind
# build without the valgrind supported and i386 binary output
bash make.sh -o no-valgrind -o no-m32 Singkatnya, menggunakan -o no-valgrind jika Anda tidak memiliki header Valgrind yang diinstal, -o no-m32 jika Anda tidak memiliki alat pengembangan GCC 32-bit yang diinstal pada host AMD64.
Pada macOS, Anda perlu mengganti perintah sed dan grep default macOS dengan GNU sed dan grep untuk menjalankan make.sh dan test.sh (persyaratan seperti itu akan dihapus di masa depan):
$ brew install grep --with-default-names
$ brew install gnu-sed --with-default-names$ cd output
$ bash ../test.sh test_aco_tutorial_0.c dalam repositori ini menunjukkan penggunaan dasar libaco. Hanya ada satu CO utama dan satu CO non-utama mandiri dalam tutorial ini. Komentar dalam kode sumber juga sangat membantu.
The test_aco_tutorial_1.c menunjukkan penggunaan beberapa statistik co non-utama. Struktur data aco_t sangat jelas dan didefinisikan dalam aco.h
Ada satu CO utama, satu CO non-utama mandiri dan dua CO non-utama (menunjuk ke tumpukan saham yang sama) di test_aco_tutorial_2.c .
The test_aco_tutorial_3.c menunjukkan cara menggunakan libaco dalam proses multithreaded. Pada dasarnya, satu contoh Libaco dirancang hanya untuk bekerja di dalam satu utas tertentu untuk mendapatkan kinerja maksimum dari pengalihan konteks antara coroutine. Jika Anda ingin menggunakan libaco di lingkungan multithreaded, hanya untuk membuat satu contoh libaco di masing -masing utas. Tidak ada pembagian data di seluruh utas di dalam libaco, dan Anda harus berurusan dengan kompetisi data di antara beberapa utas sendiri (seperti apa yang dilakukan gl_race_aco_yield_ct dalam tutorial ini).
Salah satu aturan di Libaco adalah memanggil aco_exit() untuk mengakhiri eksekusi CO non-utama alih-alih return gaya C langsung default, jika tidak, Libaco akan memperlakukan perilaku tersebut sebagai ilegal dan memicu pelindung default yang tugasnya adalah untuk mencatat informasi kesalahan tentang co yang menyinggung CO ke Stderr dan membatalkan proses segera. test_aco_tutorial_4.c menunjukkan situasi "CO yang menyinggung".
Anda juga dapat mendefinisikan pelindung Anda sendiri untuk mengganti yang default (untuk melakukan beberapa barang "kata terakhir" yang disesuaikan). Tetapi tidak masalah dalam kasus apa, prosesnya akan dibatalkan setelah pelindung dieksekusi. test_aco_tutorial_5.c menunjukkan cara mendefinisikan fungsi kata terakhir yang disesuaikan.
Contoh terakhir adalah penjadwal coroutine sederhana di test_aco_tutorial_6.c .
Akan sangat membantu untuk membaca implementasi API yang sesuai dalam kode sumber secara bersamaan ketika Anda membaca deskripsi API berikut tentang Libaco karena kode sumbernya cukup jelas dan mudah dimengerti. Dan juga disarankan untuk membaca semua tutorial sebelum membaca dokumen API.
Sangat disarankan untuk membaca bagian praktik terbaik sebelum mulai menulis aplikasi libaco yang sebenarnya (selain menggambarkan cara benar -benar merilis kinerja ekstrem Libaco dalam aplikasi Anda, ada juga pemberitahuan tentang pemrograman Libaco).
Catatan: Kontrol versi Libaco mengikuti spec: Semantic Versioning 2.0.0. Jadi API dalam daftar berikut memiliki jaminan kompatibilitas. (Harap dicatat bahwa tidak ada jaminan seperti itu untuk API no di daftar.)
typedef void ( * aco_cofuncp_t )( void );
void aco_thread_init ( aco_cofuncp_t last_word_co_fp );Menginisialisasi lingkungan Libaco di utas saat ini.
Ini akan menyimpan kata-kata kontrol FPU dan MXCSR saat ini menjadi variabel global thread-lokal.
ACO_CONFIG_SHARE_FPU_MXCSR_ENV tidak didefinisikan, kata -kata kontrol yang disimpan akan digunakan sebagai nilai referensi untuk mengatur kata -kata kontrol dari FPU dan MXCSR CO baru (dalam aco_create ) dan setiap CO akan mempertahankan salinan FPU dan MXCSR kata -kata kontrol selanjutnya.ACO_CONFIG_SHARE_FPU_MXCSR_ENV didefinisikan, maka semua CO berbagi kata kontrol yang sama dari FPU dan MXCSR. Anda dapat merujuk bagian "Bangun dan Tes" dari dokumen ini untuk informasi lebih lanjut tentang ini. Dan seperti yang dikatakan dalam test_aco_tutorial_5.c dari bagian "tutorial", ketika argumen pertama last_word_co_fp tidak nol maka fungsi yang ditunjuk oleh last_word_co_fp akan mengganti pelindung default untuk melakukan beberapa "kata -kata terakhir" tentang co pelanggaran sebelum prosesnya dibatalkan. Dalam fungsi kata terakhir seperti itu, Anda bisa menggunakan aco_get_co untuk mendapatkan pointer dari co yang menyinggung. Untuk informasi lebih lanjut, Anda dapat membaca test_aco_tutorial_5.c .
aco_share_stack_t * aco_share_stack_new ( size_t sz ); Sama dengan aco_share_stack_new2(sz, 1) .
aco_share_stack_t * aco_share_stack_new2 ( size_t sz , char guard_page_enabled ); Membuat tumpukan berbagi baru dengan ukuran memori penasihat sz dalam byte dan mungkin memiliki halaman penjaga (hanya baca) untuk mendeteksi overflow stack yang tergantung pada argumen ke-2 guard_page_enabled .
Untuk menggunakan nilai ukuran default (2MB) jika argumen pertama sz sama dengan 0. Setelah beberapa perhitungan penyelarasan dan cadangan, fungsi ini akan memastikan panjang valid akhir dari tumpukan saham sebagai imbalan:
final_valid_sz >= 4096final_valid_sz >= szfinal_valid_sz % page_size == 0 if the guard_page_enabled != 0 Dan sedekat mungkin dengan nilai sz .
Ketika nilai argumen ke-2 guard_page_enabled adalah 1, tumpukan saham sebagai imbalan akan memiliki satu halaman penjaga baca saja untuk mendeteksi overflow stack sementara nilai 0 dari guard_page_enabled berarti tanpa halaman penjaga tersebut.
Fungsi ini akan selalu mengembalikan tumpukan saham yang valid.
void aco_share_stack_destroy ( aco_share_stack_t * sstk ); DESTORY STACK STACK sstk .
Pastikan bahwa semua CO yang tumpukan sahamnya adalah sstk sudah dihancurkan saat Anda menghancurkan sstk .
typedef void ( * aco_cofuncp_t )( void );
aco_t * aco_create ( aco_t * main_co , aco_share_stack_t * share_stack ,
size_t save_stack_sz , aco_cofuncp_t co_fp , void * arg );Buat co baru.
Jika itu adalah Main_Co yang ingin Anda buat, hubungi saja: aco_create(NULL, NULL, 0, NULL, NULL) . Main Co adalah coroutine mandiri khusus yang tumpukan sahamnya adalah tumpukan utas default. Di utas, Main CO adalah coroutine yang harus dibuat dan mulai mengeksekusi sebelum semua coroutine non-utama lainnya.
Kalau tidak, itu adalah CO non-utama yang ingin Anda buat:
main_co adalah CO utama yang akan dilakukan oleh CO aco_yield di dalam konteks di masa depan. main_co tidak boleh nol;share_stack adalah alamat tumpukan saham yang non-utama CO yang ingin Anda buat akan digunakan sebagai tumpukan pelaksanaannya di masa depan. share_stack tidak boleh nol;save_stack_sz menentukan ukuran init dari tumpukan simpan pribadi dari co ini. Unit ini dalam byte. Nilai 0 berarti menggunakan ukuran default 64 byte. Karena pengubahan ukuran otomatis akan terjadi ketika tumpukan save pribadi tidak cukup besar untuk memegang tumpukan eksekusi CO ketika harus menghasilkan tumpukan saham yang ditempati untuk CO lain, Anda biasanya tidak perlu khawatir tentang nilai sz sama sekali. Tetapi itu akan membawa beberapa dampak kinerja pada pengalokasi memori ketika sejumlah besar (katakanlah 10.000.000) dari CO mengubah ukuran save private mereka secara terus menerus, co->save_stack.max_cpsz sangat bijaksana dan sangat disarankan untuk mengatur optimasi save_stack_sz dengan nilai yang sama dengan nilai maksimum;co_fp adalah penunjuk fungsi entri dari CO. co_fp tidak boleh nol;arg adalah nilai pointer dan akan diatur ke co->arg dari CO untuk membuat. Ini dapat digunakan sebagai argumen input untuk CO.Fungsi ini akan selalu mengembalikan CO yang valid. Dan kami menyebutkan keadaan CO sebagai imbalan sebagai "init" jika itu adalah CO non-utama yang ingin Anda buat.
void aco_resume ( aco_t * co ); Hasil dari penelepon utama co dan untuk memulai atau melanjutkan eksekusi co .
Penelepon fungsi ini harus menjadi CO utama dan harus co->main_co . Dan co Argumen Pertama harus menjadi CO non-utama.
Pertama kali Anda melanjutkan co , mulai menjalankan fungsi yang menunjuk oleh co->fp . Jika co telah dihasilkan, aco_resume memulai kembali dan melanjutkan eksekusi.
Setelah panggilan aco_resume , kami menyebutkan keadaan penelepon - Main Co sebagai "dihasilkan".
void aco_yield (); Menghasilkan eksekusi co dan resume co->main_co . Penelepon fungsi ini harus menjadi co non-utama. Dan co->main_co tidak boleh nol.
Setelah panggilan aco_yield , kami menyebutkan keadaan penelepon - co sebagai "dihasilkan".
aco_t * aco_get_co ();Mengembalikan pointer dari co non-utama saat ini. Penelepon fungsi ini harus menjadi co non-utama.
void * aco_get_arg (); Sama dengan (aco_get_co()->arg) . Dan juga, penelepon fungsi ini harus menjadi co non-utama.
void aco_exit (); Selain itu lakukan sama dengan aco_yield() , aco_exit() juga mengatur co->is_end ke 1 dengan demikian untuk menandai co pada status "end".
void aco_destroy ( aco_t * co ); Hancurkan co . Argumen co tidak boleh nol. Tumpukan simpan pribadi juga akan dihancurkan jika co adalah CO non-utama.
#define ACO_VERSION_MAJOR 1
#define ACO_VERSION_MINOR 2
#define ACO_VERSION_PATCH 4 3 makro ini didefinisikan dalam header aco.h dan nilainya mengikuti spec: Semantic Versioning 2.0.0.
// provide the compiler with branch prediction information
#define likely ( x ) aco_likely(x)
#define unlikely ( x ) aco_unlikely(x)
// override the default `assert` for convenience when coding
#define assert ( EX ) aco_assert(EX)
// equal to `assert((ptr) != NULL)`
#define assertptr ( ptr ) aco_assertptr(ptr)
// assert the successful return of memory allocation
#define assertalloc_bool ( b ) aco_assertalloc_bool(b)
#define assertalloc_ptr ( ptr ) aco_assertalloc_ptr(ptr) Anda dapat memilih untuk memasukkan header "aco_assert_override.h" untuk mengesampingkan c "menegaskan" dalam aplikasi libaco seperti test_aco_synopsis.c tidak (header ini termasuk harus pada daftar arahan termasuk yang terakhir dalam file sumber karena C "Assert" adalah definisi C macro juga) dan definisi 5 lainnya dalam 5 MacROS lainnya karena The C "Assert" adalah definisi C macro juga) dan definisi 5 lainnya dalam 5 MacROS lainnya karena The C "Assert" adalah definisi C macro juga) dan definisi 5 MacROS LAINNYA MACROS karena The "Assert" adalah definisi C macro juga) dan definisi 5 MacROS LAINNYA MACROS karena The The "Assert" adalah definisi C macro juga) dan definisi 5 MacROS LAINNYA MACROS karena The "Assert" adalah C MacRO juga. Tolong jangan sertakan header ini di file sumber aplikasi jika Anda ingin menggunakan C "Assert" default.
Untuk detail lebih lanjut Anda dapat merujuk ke file sumber ACO_ASSERT_OVERRIDE.H.
Tanggal: Sat Jun 30 UTC 2018.
Mesin: C5D.Large di AWS.
OS: RHEL-7.5 (Red Hat Enterprise Linux 7.5).
Berikut adalah ringkasan singkat dari bagian benchmark:
$ LD_PRELOAD=/usr/lib64/libtcmalloc_minimal.so.4 ./test_aco_benchmark..no_valgrind.shareFPUenv
+build:x86_64
+build:-DACO_CONFIG_SHARE_FPU_MXCSR_ENV
+build:share fpu & mxcsr control words between coroutines
+build:undefined ACO_USE_VALGRIND
+build:without valgrind memcheck friendly support
sizeof(aco_t)=152:
comment task_amount all_time_cost ns_per_op speed
aco_create/init_save_stk_sz=64B 1 0.000 s 230.00 ns/op 4347824.79 op/s
aco_resume/co_amount=1/copy_stack_size=0B 20000000 0.412 s 20.59 ns/op 48576413.55 op/s
-> acosw 40000000 0.412 s 10.29 ns/op 97152827.10 op/s
aco_destroy 1 0.000 s 650.00 ns/op 1538461.66 op/s
aco_create/init_save_stk_sz=64B 1 0.000 s 200.00 ns/op 5000001.72 op/s
aco_resume/co_amount=1/copy_stack_size=0B 20000000 0.412 s 20.61 ns/op 48525164.25 op/s
-> acosw 40000000 0.412 s 10.30 ns/op 97050328.50 op/s
aco_destroy 1 0.000 s 666.00 ns/op 1501501.49 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.50 ns/op 15266771.53 op/s
aco_resume/co_amount=2000000/copy_stack_size=8B 20000000 0.666 s 33.29 ns/op 30043022.64 op/s
aco_destroy 2000000 0.066 s 32.87 ns/op 30425152.25 op/s
aco_create/init_save_stk_sz=64B 2000000 0.130 s 65.22 ns/op 15332218.24 op/s
aco_resume/co_amount=2000000/copy_stack_size=24B 20000000 0.675 s 33.75 ns/op 29630018.73 op/s
aco_destroy 2000000 0.067 s 33.45 ns/op 29898311.36 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.42 ns/op 15286937.97 op/s
aco_resume/co_amount=2000000/copy_stack_size=40B 20000000 0.669 s 33.45 ns/op 29891277.59 op/s
aco_destroy 2000000 0.080 s 39.87 ns/op 25084242.29 op/s
aco_create/init_save_stk_sz=64B 2000000 0.224 s 111.86 ns/op 8940010.49 op/s
aco_resume/co_amount=2000000/copy_stack_size=56B 20000000 0.678 s 33.88 ns/op 29515473.53 op/s
aco_destroy 2000000 0.067 s 33.42 ns/op 29922412.68 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.74 ns/op 15211896.70 op/s
aco_resume/co_amount=2000000/copy_stack_size=120B 20000000 0.769 s 38.45 ns/op 26010724.94 op/s
aco_destroy 2000000 0.088 s 44.11 ns/op 22669240.25 op/s
aco_create/init_save_stk_sz=64B 10000000 1.240 s 123.97 ns/op 8066542.54 op/s
aco_resume/co_amount=10000000/copy_stack_size=8B 40000000 1.327 s 33.17 ns/op 30143409.55 op/s
aco_destroy 10000000 0.328 s 32.82 ns/op 30467658.05 op/s
aco_create/init_save_stk_sz=64B 10000000 0.659 s 65.94 ns/op 15165717.02 op/s
aco_resume/co_amount=10000000/copy_stack_size=24B 40000000 1.345 s 33.63 ns/op 29737708.53 op/s
aco_destroy 10000000 0.337 s 33.71 ns/op 29666697.09 op/s
aco_create/init_save_stk_sz=64B 10000000 0.654 s 65.38 ns/op 15296191.35 op/s
aco_resume/co_amount=10000000/copy_stack_size=40B 40000000 1.348 s 33.71 ns/op 29663992.77 op/s
aco_destroy 10000000 0.336 s 33.56 ns/op 29794574.96 op/s
aco_create/init_save_stk_sz=64B 10000000 0.653 s 65.29 ns/op 15316087.09 op/s
aco_resume/co_amount=10000000/copy_stack_size=56B 40000000 1.384 s 34.60 ns/op 28902221.24 op/s
aco_destroy 10000000 0.337 s 33.73 ns/op 29643682.93 op/s
aco_create/init_save_stk_sz=64B 10000000 0.652 s 65.19 ns/op 15340872.40 op/s
aco_resume/co_amount=10000000/copy_stack_size=120B 40000000 1.565 s 39.11 ns/op 25566255.73 op/s
aco_destroy 10000000 0.443 s 44.30 ns/op 22574242.55 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.61 ns/op 15241722.94 op/s
aco_resume/co_amount=2000000/copy_stack_size=136B 20000000 0.947 s 47.36 ns/op 21114212.05 op/s
aco_destroy 2000000 0.125 s 62.35 ns/op 16039466.45 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.71 ns/op 15218784.72 op/s
aco_resume/co_amount=2000000/copy_stack_size=136B 20000000 0.948 s 47.39 ns/op 21101216.29 op/s
aco_destroy 2000000 0.125 s 62.73 ns/op 15941559.26 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.49 ns/op 15270258.18 op/s
aco_resume/co_amount=2000000/copy_stack_size=152B 20000000 1.069 s 53.44 ns/op 18714275.17 op/s
aco_destroy 2000000 0.122 s 61.05 ns/op 16378678.85 op/s
aco_create/init_save_stk_sz=64B 2000000 0.132 s 65.91 ns/op 15171336.62 op/s
aco_resume/co_amount=2000000/copy_stack_size=232B 20000000 1.190 s 59.48 ns/op 16813230.99 op/s
aco_destroy 2000000 0.123 s 61.26 ns/op 16324298.25 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.68 ns/op 15224361.30 op/s
aco_resume/co_amount=2000000/copy_stack_size=488B 20000000 1.828 s 91.40 ns/op 10941133.56 op/s
aco_destroy 2000000 0.145 s 72.56 ns/op 13781182.82 op/s
aco_create/init_save_stk_sz=64B 2000000 0.132 s 65.80 ns/op 15197461.34 op/s
aco_resume/co_amount=2000000/copy_stack_size=488B 20000000 1.829 s 91.47 ns/op 10932139.32 op/s
aco_destroy 2000000 0.149 s 74.70 ns/op 13387258.82 op/s
aco_create/init_save_stk_sz=64B 1000000 0.067 s 66.63 ns/op 15007426.35 op/s
aco_resume/co_amount=1000000/copy_stack_size=1000B 20000000 4.224 s 211.20 ns/op 4734744.76 op/s
aco_destroy 1000000 0.093 s 93.36 ns/op 10711651.49 op/s
aco_create/init_save_stk_sz=64B 1000000 0.066 s 66.28 ns/op 15086953.73 op/s
aco_resume/co_amount=1000000/copy_stack_size=1000B 20000000 4.222 s 211.12 ns/op 4736537.93 op/s
aco_destroy 1000000 0.094 s 94.09 ns/op 10627664.78 op/s
aco_create/init_save_stk_sz=64B 100000 0.007 s 70.72 ns/op 14139923.59 op/s
aco_resume/co_amount=100000/copy_stack_size=1000B 20000000 4.191 s 209.56 ns/op 4771909.70 op/s
aco_destroy 100000 0.010 s 101.21 ns/op 9880747.28 op/s
aco_create/init_save_stk_sz=64B 100000 0.007 s 66.62 ns/op 15010433.00 op/s
aco_resume/co_amount=100000/copy_stack_size=2024B 20000000 7.002 s 350.11 ns/op 2856228.03 op/s
aco_destroy 100000 0.016 s 159.69 ns/op 6262129.35 op/s
aco_create/init_save_stk_sz=64B 100000 0.007 s 65.76 ns/op 15205994.08 op/s
aco_resume/co_amount=100000/copy_stack_size=4072B 20000000 11.918 s 595.90 ns/op 1678127.54 op/s
aco_destroy 100000 0.019 s 186.32 ns/op 5367189.85 op/s
aco_create/init_save_stk_sz=64B 100000 0.006 s 63.03 ns/op 15865531.37 op/s
aco_resume/co_amount=100000/copy_stack_size=7992B 20000000 21.808 s 1090.42 ns/op 917079.11 op/s
aco_destroy 100000 0.038 s 378.33 ns/op 2643225.42 op/s
$ LD_PRELOAD=/usr/lib64/libtcmalloc_minimal.so.4 ./test_aco_benchmark..no_valgrind.standaloneFPUenv
+build:x86_64
+build:undefined ACO_CONFIG_SHARE_FPU_MXCSR_ENV
+build:each coroutine maintain each own fpu & mxcsr control words
+build:undefined ACO_USE_VALGRIND
+build:without valgrind memcheck friendly support
sizeof(aco_t)=160:
comment task_amount all_time_cost ns_per_op speed
aco_create/init_save_stk_sz=64B 1 0.000 s 273.00 ns/op 3663004.27 op/s
aco_resume/co_amount=1/copy_stack_size=0B 20000000 0.415 s 20.76 ns/op 48173877.75 op/s
-> acosw 40000000 0.415 s 10.38 ns/op 96347755.51 op/s
aco_destroy 1 0.000 s 381.00 ns/op 2624672.26 op/s
aco_create/init_save_stk_sz=64B 1 0.000 s 212.00 ns/op 4716980.43 op/s
aco_resume/co_amount=1/copy_stack_size=0B 20000000 0.415 s 20.75 ns/op 48185455.26 op/s
-> acosw 40000000 0.415 s 10.38 ns/op 96370910.51 op/s
aco_destroy 1 0.000 s 174.00 ns/op 5747123.38 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.63 ns/op 15237386.02 op/s
aco_resume/co_amount=2000000/copy_stack_size=8B 20000000 0.664 s 33.20 ns/op 30119155.82 op/s
aco_destroy 2000000 0.065 s 32.67 ns/op 30604542.55 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.33 ns/op 15305975.29 op/s
aco_resume/co_amount=2000000/copy_stack_size=24B 20000000 0.675 s 33.74 ns/op 29638360.61 op/s
aco_destroy 2000000 0.067 s 33.31 ns/op 30016633.42 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.61 ns/op 15241767.78 op/s
aco_resume/co_amount=2000000/copy_stack_size=40B 20000000 0.678 s 33.88 ns/op 29518648.08 op/s
aco_destroy 2000000 0.079 s 39.74 ns/op 25163018.30 op/s
aco_create/init_save_stk_sz=64B 2000000 0.221 s 110.73 ns/op 9030660.30 op/s
aco_resume/co_amount=2000000/copy_stack_size=56B 20000000 0.684 s 34.18 ns/op 29253416.65 op/s
aco_destroy 2000000 0.067 s 33.40 ns/op 29938840.64 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.60 ns/op 15244077.65 op/s
aco_resume/co_amount=2000000/copy_stack_size=120B 20000000 0.769 s 38.43 ns/op 26021228.41 op/s
aco_destroy 2000000 0.087 s 43.74 ns/op 22863987.42 op/s
aco_create/init_save_stk_sz=64B 10000000 1.251 s 125.08 ns/op 7994958.59 op/s
aco_resume/co_amount=10000000/copy_stack_size=8B 40000000 1.327 s 33.19 ns/op 30133654.80 op/s
aco_destroy 10000000 0.329 s 32.85 ns/op 30439787.32 op/s
aco_create/init_save_stk_sz=64B 10000000 0.674 s 67.37 ns/op 14843796.57 op/s
aco_resume/co_amount=10000000/copy_stack_size=24B 40000000 1.354 s 33.84 ns/op 29548523.05 op/s
aco_destroy 10000000 0.339 s 33.90 ns/op 29494634.83 op/s
aco_create/init_save_stk_sz=64B 10000000 0.672 s 67.19 ns/op 14882262.88 op/s
aco_resume/co_amount=10000000/copy_stack_size=40B 40000000 1.361 s 34.02 ns/op 29393520.19 op/s
aco_destroy 10000000 0.338 s 33.77 ns/op 29609577.59 op/s
aco_create/init_save_stk_sz=64B 10000000 0.673 s 67.31 ns/op 14857716.02 op/s
aco_resume/co_amount=10000000/copy_stack_size=56B 40000000 1.371 s 34.27 ns/op 29181897.80 op/s
aco_destroy 10000000 0.339 s 33.85 ns/op 29540633.63 op/s
aco_create/init_save_stk_sz=64B 10000000 0.672 s 67.24 ns/op 14873017.10 op/s
aco_resume/co_amount=10000000/copy_stack_size=120B 40000000 1.548 s 38.71 ns/op 25835542.17 op/s
aco_destroy 10000000 0.446 s 44.61 ns/op 22415961.64 op/s
aco_create/init_save_stk_sz=64B 2000000 0.132 s 66.01 ns/op 15148290.52 op/s
aco_resume/co_amount=2000000/copy_stack_size=136B 20000000 0.944 s 47.22 ns/op 21177946.19 op/s
aco_destroy 2000000 0.124 s 61.99 ns/op 16132721.97 op/s
aco_create/init_save_stk_sz=64B 2000000 0.133 s 66.36 ns/op 15068860.85 op/s
aco_resume/co_amount=2000000/copy_stack_size=136B 20000000 0.944 s 47.20 ns/op 21187541.38 op/s
aco_destroy 2000000 0.124 s 62.21 ns/op 16073322.25 op/s
aco_create/init_save_stk_sz=64B 2000000 0.131 s 65.62 ns/op 15238955.93 op/s
aco_resume/co_amount=2000000/copy_stack_size=152B 20000000 1.072 s 53.61 ns/op 18652789.74 op/s
aco_destroy 2000000 0.121 s 60.42 ns/op 16551368.04 op/s
aco_create/init_save_stk_sz=64B 2000000 0.132 s 66.08 ns/op 15132547.65 op/s
aco_resume/co_amount=2000000/copy_stack_size=232B 20000000 1.198 s 59.88 ns/op 16699389.91 op/s
aco_destroy 2000000 0.121 s 60.71 ns/op 16471465.52 op/s
aco_create/init_save_stk_sz=64B 2000000 0.133 s 66.50 ns/op 15036985.95 op/s
aco_resume/co_amount=2000000/copy_stack_size=488B 20000000 1.853 s 92.63 ns/op 10796126.04 op/s
aco_destroy 2000000 0.146 s 72.87 ns/op 13723559.36 op/s
aco_create/init_save_stk_sz=64B 2000000 0.132 s 66.14 ns/op 15118324.13 op/s
aco_resume/co_amount=2000000/copy_stack_size=488B 20000000 1.855 s 92.75 ns/op 10781572.22 op/s
aco_destroy 2000000 0.152 s 75.79 ns/op 13194130.51 op/s
aco_create/init_save_stk_sz=64B 1000000 0.067 s 66.97 ns/op 14931921.56 op/s
aco_resume/co_amount=1000000/copy_stack_size=1000B 20000000 4.218 s 210.90 ns/op 4741536.66 op/s
aco_destroy 1000000 0.093 s 93.16 ns/op 10734691.98 op/s
aco_create/init_save_stk_sz=64B 1000000 0.066 s 66.49 ns/op 15039274.31 op/s
aco_resume/co_amount=1000000/copy_stack_size=1000B 20000000 4.216 s 210.81 ns/op 4743543.53 op/s
aco_destroy 1000000 0.094 s 93.97 ns/op 10641539.58 op/s
aco_create/init_save_stk_sz=64B 100000 0.007 s 70.95 ns/op 14094724.73 op/s
aco_resume/co_amount=100000/copy_stack_size=1000B 20000000 4.190 s 209.52 ns/op 4772746.50 op/s
aco_destroy 100000 0.010 s 100.99 ns/op 9902271.51 op/s
aco_create/init_save_stk_sz=64B 100000 0.007 s 66.49 ns/op 15040038.84 op/s
aco_resume/co_amount=100000/copy_stack_size=2024B 20000000 7.028 s 351.38 ns/op 2845942.55 op/s
aco_destroy 100000 0.016 s 159.15 ns/op 6283444.42 op/s
aco_create/init_save_stk_sz=64B 100000 0.007 s 65.73 ns/op 15214482.36 op/s
aco_resume/co_amount=100000/copy_stack_size=4072B 20000000 11.879 s 593.95 ns/op 1683636.60 op/s
aco_destroy 100000 0.018 s 184.23 ns/op 5428119.00 op/s
aco_create/init_save_stk_sz=64B 100000 0.006 s 63.41 ns/op 15771072.16 op/s
aco_resume/co_amount=100000/copy_stack_size=7992B 20000000 21.808 s 1090.42 ns/op 917081.56 op/s
aco_destroy 100000 0.038 s 376.78 ns/op 2654073.13 op/s
Sangat penting untuk menjadi sangat akrab dengan standar Sys v Abi dari Intel386 dan X86-64 sebelum Anda mulai menerapkan atau membuktikan perpustakaan Coroutine.
Bukti di bawah ini tidak memiliki deskripsi langsung tentang IP (Instruksi Pointer), SP (Stack Pointer) dan penghematan/pemulihan antara tumpukan simpan pribadi dan tumpukan berbagi, karena hal -hal ini cukup sepele dan mudah dimengerti ketika mereka dibandingkan dengan hal -hal kendala ABI.
Di utas OS, coroutine utama main_co adalah coroutine yang harus dibuat dan mulai mengeksekusi terlebih dahulu, sebelum semua coroutine non-utama lainnya melakukannya.
Diagram berikutnya adalah contoh sederhana dari pengalihan konteks antara Main_Co dan CO.
Dalam bukti ini, kami hanya berasumsi bahwa kami berada di bawah Sys v Abi dari Intel386 karena tidak ada perbedaan mendasar antara Sys v Abi dari Intel386 dan X86-64. Kami juga berasumsi bahwa tidak ada kode yang akan mengubah kata -kata kontrol FPU dan MXCSR.

Diagram berikutnya sebenarnya adalah model berjalan Coroutine simetris yang memiliki jumlah CO-S dan satu co utama yang tidak terbatas. Ini baik -baik saja karena coroutine asimetris hanyalah kasus khusus dari coroutine simetris. Untuk membuktikan kebenaran coroutine simetris sedikit lebih menantang daripada coroutine asimetris dan karenanya lebih menyenangkan. (Libaco hanya menerapkan API coroutine asimetris saat ini karena makna semantik API coroutine asimetris jauh lebih mudah dipahami dan digunakan daripada coroutine simetris.)

Karena CO utama adalah Coroutine pertama mulai berjalan, switching konteks pertama dalam utas OS ini harus dalam bentuk acosw(main_co, co) di mana co Argumen ke-2 adalah CO non-utama.
Sangat mudah untuk membuktikan bahwa hanya ada dua jenis transfer negara dalam diagram di atas:
Untuk membuktikan kebenaran void* acosw(aco_t* from_co, aco_t* to_co) implementasi setara untuk membuktikan semua CO terus -menerus mematuhi kendala Sys v Abi sebelum dan sesudah panggilan acosw . Kami berasumsi bahwa bagian lain dari kode biner (kecuali acosw ) di CO telah mematuhi ABI (mereka biasanya dihasilkan oleh kompiler dengan benar).
Berikut adalah ringkasan dari kendala register dalam fungsi konvensi panggilan Intel386 Sys v Abi:
Registers' usage in the calling convention of the Intel386 System V ABI:
caller saved (scratch) registers:
C1.0: EAX
At the entry of a function call:
could be any value
After the return of `acosw`:
hold the return value for `acosw`
C1.1: ECX,EDX
At the entry of a function call:
could be any value
After the return of `acosw`:
could be any value
C1.2: Arithmetic flags, x87 and mxcsr flags
At the entry of a function call:
could be any value
After the return of `acosw`:
could be any value
C1.3: ST(0-7)
At the entry of a function call:
the stack of FPU must be empty
After the return of `acosw`:
the stack of FPU must be empty
C1.4: Direction flag
At the entry of a function call:
DF must be 0
After the return of `acosw`:
DF must be 0
C1.5: others: xmm*,ymm*,mm*,k*...
At the entry of a function call:
could be any value
After the return of `acosw`:
could be any value
callee saved registers:
C2.0: EBX,ESI,EDI,EBP
At the entry of a function call:
could be any value
After the return of `acosw`:
must be the same as it is at the entry of `acosw`
C2.1: ESP
At the entry of a function call:
must be a valid stack pointer
(alignment of 16 bytes, retaddr and etc...)
After the return of `acosw`:
must be the same as it is before the call of `acosw`
C2.2: control word of FPU & mxcsr
At the entry of a function call:
could be any configuration
After the return of `acosw`:
must be the same as it is before the call of `acosw`
(unless the caller of `acosw` assume `acosw` may
change the control words of FPU or MXCSR on purpose
like `fesetenv`)
(Untuk Intel386, penggunaan register didefinisikan dalam "P13 - Tabel 2.3: Penggunaan Register" dari Sys v Abi Intel386 v1.1, dan untuk AMD64 ada dalam "P23 - Gambar 3.4: Penggunaan Register" dari SYS V ABI AMD64 V1.0.)
Bukti:

Diagram di atas adalah untuk kasus pertama: "Hasil State Co -> Init State Co".
Kendala: C 1.0, 1.1, 1.2, 1.5 ( puas ✓)
Register goresan di bawah ini dapat menahan nilai apa pun saat masuknya fungsi:
EAX,ECX,EDX
XMM*,YMM*,MM*,K*...
status bits of EFLAGS,FPU,MXCSR
Kendala: C 1.3, 1.4 ( puas ✓)
Karena tumpukan FPU harus sudah kosong dan DF harus sudah 0 sebelum acosw(co, to_co) dipanggil (kode biner CO sudah dipatuhi ke ABI), kendala 1.3 dan 1.4 dipatuhi oleh acosw .
Kendala: C 2.0, 2.1, 2.2 ( puas ✓)
C 2.0 & 2.1 sudah puas. Karena kita sudah berasumsi bahwa tidak ada yang akan mengubah kata -kata kontrol FPU dan MXCSR, C 2.2 juga puas.

Diagram di atas adalah untuk kasus ke -2: co state yang dihasilkan -> co state yang dihasilkan.
Kendala: C 1.0 ( puas ✓)
EAX sudah memegang nilai pengembalian ketika acosw kembali ke TO_CO (resume).
Kendala: C 1.1, 1.2, 1.5 ( puas ✓)
Register awal di bawah ini dapat menahan nilai apa pun saat masuknya fungsi dan setelah pengembalian acosw :
ECX,EDX
XMM*,YMM*,MM*,K*...
status bits of EFLAGS,FPU,MXCSR
Kendala: C 1.3, 1.4 ( puas ✓)
Karena tumpukan FPU harus sudah kosong dan DF harus sudah 0 sebelum acosw(co, to_co) dipanggil (kode biner CO sudah dipatuhi ke ABI), kendala 1.3 dan 1.4 dipatuhi oleh acosw .
Kendala: C 2.0, 2.1, 2.2 ( puas ✓)
C 2.0 & 2.1 puas karena ada penyelamatan & pemulihan register yang disimpan oleh Callee ketika acosw dipanggil/dikembalikan. Karena kita sudah berasumsi bahwa tidak ada yang akan mengubah kata -kata kontrol FPU dan MXCSR, C 2.2 juga puas.
acosw pertama di utas harus berupa kasus pertama: State co -> init state co, dan semua acosw berikutnya harus menjadi salah satu dari 2 case di atas. Secara berurutan, kita dapat membuktikan bahwa "semua CO terus -menerus mematuhi kendala Sys v Abi sebelum dan sesudah panggilan acosw ". Dengan demikian, buktinya sudah selesai.
Ada hal baru yang disebut zona merah di System v ABI X86-64:
Area 128-byte di luar lokasi yang ditunjukkan oleh %RSP dianggap dicadangkan dan tidak boleh dimodifikasi dengan sinyal atau penangan interupsi. Oleh karena itu, fungsi dapat menggunakan area ini untuk data sementara yang tidak diperlukan di seluruh panggilan fungsi. Secara khusus, fungsi daun dapat menggunakan area ini untuk seluruh bingkai tumpukan mereka, daripada menyesuaikan penunjuk tumpukan dalam prolog dan epilog. Area ini dikenal sebagai zona merah.
Karena zona merah "tidak diawetkan oleh callee", kami hanya tidak peduli sama sekali dalam konteks pengalihan antara coroutine (karena acosw adalah fungsi daun).
Akhir dari area argumen input harus diselaraskan pada 16 (32 atau 64, jika __m256 atau __m512 dilewatkan pada tumpukan) batas byte. Dengan kata lain, nilai (%ESP + 4) selalu kelipatan 16 (32 atau 64) ketika kontrol ditransfer ke titik masuk fungsi. Stack pointer, %esp, selalu menunjuk ke akhir bingkai tumpukan yang dialokasikan terbaru.
-Intel386-psabi-1.1: 2.2.2 Bingkai tumpukan
Pointer tumpukan, %RSP, selalu menunjuk ke akhir bingkai tumpukan yang dialokasikan terbaru.
- SYS V ABI AMD64 Versi 1.0: 3.2.2 Bingkai tumpukan
Berikut adalah contoh bug di libco Tencent. ABI menyatakan bahwa (E|R)SP harus selalu menunjuk ke akhir bingkai tumpukan yang dialokasikan terbaru. Tetapi dalam file coctx_swap.s libco, sp (E|R)SP telah digunakan untuk mengatasi memori pada heap.
Secara default, penangan sinyal dipanggil pada tumpukan proses normal. Dimungkinkan untuk mengatur bahwa penangan sinyal menggunakan tumpukan alternatif; Lihat SigalStack (2) untuk diskusi tentang bagaimana melakukan ini dan kapan mungkin berguna.
- Sinyal Man 7: Disposisi Sinyal
Hal -hal yang mengerikan mungkin terjadi jika (E|R)SP menunjuk pada struktur data pada tumpukan saat sinyal datang. breakpoint signal sigalstack (E|R)SP
Singkatnya, jika Anda ingin mendapatkan kinerja ultra Libaco, simpan saja penggunaan tumpukan CO non-main non-standalone pada titik memanggil aco_yield sekecil mungkin. Dan berhati -hatilah jika Anda ingin lulus alamat variabel lokal dari satu CO ke CO lain karena variabel lokal biasanya ada di tumpukan berbagi . Mengalokasikan variabel semacam ini dari tumpukan selalu merupakan pilihan yang lebih bijak.
Secara rinci, ada 5 tips:
co_fp
/
/
f1 f2
/ /
/ f4
yield f3 f5
aco_yield untuk menghasilkan kembali ke Main Co) memiliki dampak besar pada kinerja pengalihan konteks antara coroutine, seperti yang telah ditunjukkan oleh hasil benchmark. Dalam diagram di atas, penggunaan tumpukan fungsi F2, F3, F4 dan F5 tidak memiliki pengaruh langsung terhadap kinerja switching konteks karena tidak ada aco_yield ketika mereka dieksekusi, sedangkan penggunaan tumpukan CO_FP dan F1 mendominasi nilai co->save_stack.max_cpsz . Kunci untuk menjaga penggunaan tumpukan fungsi serendah mungkin adalah mengalokasikan variabel lokal (terutama yang besar) di tumpukan dan mengelola siklus hidup mereka secara manual alih -alih mengalokasikannya di tumpukan secara default. Opsi -fstack-usage GCC sangat membantu tentang ini.
int * gl_ptr ;
void inc_p ( int * p ){ ( * p ) ++ ; }
void co_fp0 () {
int ct = 0 ;
gl_ptr = & ct ; // line 7
aco_yield ();
check ( ct );
int * ptr = & ct ;
inc_p ( ptr ); // line 11
aco_exit ();
}
void co_fp1 () {
do_sth ( gl_ptr ); // line 16
aco_exit ();
}gl_ptr di CO_FP1 (baris 16) memiliki semantik yang sama sekali berbeda dengan gl_ptr di baris 7 dari CO_FP0, dan kode semacam itu mungkin akan merusak tumpukan eksekusi CO_FP1. Tetapi baris 11 baik -baik saja karena variabel ct dan fungsi inc_p berada dalam konteks coroutine yang sama. Mengalokasikan variabel semacam itu (perlu berbagi dengan coroutine lain) di tumpukan hanya akan menyelesaikan masalah seperti itu: int * gl_ptr ;
void inc_p ( int * p ){ ( * p ) ++ ; }
void co_fp0 () {
int * ct_ptr = malloc ( sizeof ( int ));
assert ( ct_ptr != NULL );
* ct_ptr = 0 ;
gl_ptr = ct_ptr ;
aco_yield ();
check ( * ct_ptr );
int * ptr = ct_ptr ;
inc_p ( ptr );
free ( ct_ptr );
gl_ptr = NULL ;
aco_exit ();
}
void co_fp1 () {
do_sth ( gl_ptr );
aco_exit ();
}Ide baru dipersilakan!
Tambahkan makro seperti aco_mem_new yang merupakan kombinasi dari sesuatu seperti p = malloc(sz); assertalloc_ptr(p) .
Tambahkan API aco_reset baru untuk mendukung reusability objek Coroutine.
Dukung platform lain (terutama ARM & ARM64).
v1.2.4 Sun Jul 29 2018
Changed `asm` to `__asm__` in aco.h to support compiler's `--std=c99`
flag (Issue #16, proposed by Theo Schlossnagle @postwait).
v1.2.3 Thu Jul 26 2018
Added support for MacOS;
Added support for shared library build of libaco (PR #10, proposed
by Theo Schlossnagle @postwait);
Added C macro ACO_REG_IDX_BP in aco.h (PR #15, proposed by
Theo Schlossnagle @postwait);
Added global C config macro ACO_USE_ASAN which could enable the
friendly support of address sanitizer (both gcc and clang) (PR #14,
proposed by Theo Schlossnagle @postwait);
Added README_zh.md.
v1.2.2 Mon Jul 9 2018
Added a new option `-o <no-m32|no-valgrind>` to make.sh;
Correction about the value of macro ACO_VERSION_PATCH (issue #1
kindly reported by Markus Elfring @elfring);
Adjusted some noncompliant naming of identifiers (double underscore
`__`) (issue #1, kindly proposed by Markus Elfring @elfring);
Supported the header file including by C++ (issue #4, kindly
proposed by Markus Elfring @elfring).
v1.2.1 Sat Jul 7 2018
Fixed some noncompliant include guards in two C header files (
issue #1 kindly reported by Markus Elfring @elfring);
Removed the "pure" word from "pure C" statement since it is
containing assembly codes (kindly reported by Peter Cawley
@corsix);
Many updates in the README.md document.
v1.2.0 Tue Jul 3 2018
Provided another header named `aco_assert_override.h` so user
could choose to override the default `assert` or not;
Added some macros about the version information.
v1.1 Mon Jul 2 2018
Removed the requirement on the GCC version (>= 5.0).
v1.0 Sun Jul 1 2018
The v1.0 release of libaco, cheers ???
Saya pengembang sumber terbuka penuh waktu. Jumlah sumbangan berapa pun akan sangat dihargai dan dapat memberi saya dorongan besar.
Paypal
tautan paypal.me
Alipay (支付 (宝 | 寶))


Logo Libaco dengan murah hati disumbangkan oleh Peter Bech (Peteck). Logo ini dilisensikan di bawah CC BY-ND 4.0. Situs web libaco.org juga disumbangkan oleh Peter Bech (Peteck).
Hak Cipta (C) 2018, oleh Sen Han [email protected].
Di bawah lisensi Apache, versi 2.0.
Lihat file lisensi untuk detailnya.