Repository: akopytov/sysbench Branch: master Commit: 3ceba0b1e115 Files: 685 Total size: 3.2 MB Directory structure: gitextract_6o7n74ws/ ├── .github/ │ └── workflows/ │ └── ci.yml ├── .gitignore ├── .travis.yml ├── COPYING ├── ChangeLog ├── Dockerfile ├── Makefile.am ├── README.md ├── autogen.sh ├── config/ │ └── config.rpath ├── configure.ac ├── debian/ │ ├── changelog │ ├── compat │ ├── control │ ├── copyright │ ├── dirs │ ├── docs │ ├── install │ ├── rules │ └── source/ │ └── format ├── install-sh ├── m4/ │ ├── ac_check_aio.m4 │ ├── ac_check_pgsql.m4 │ ├── acx_pthread.m4 │ ├── ax_check_compile_flag.m4 │ ├── ax_compiler_vendor.m4 │ ├── ax_gcc_archflag.m4 │ ├── ax_gcc_func_attribute.m4 │ ├── ax_gcc_x86_cpuid.m4 │ ├── ax_tls.m4 │ ├── extensions.m4 │ ├── host-cpu-c-abi.m4 │ ├── lib-ld.m4 │ ├── lib-link.m4 │ ├── lib-prefix.m4 │ ├── pkg.m4 │ ├── sb_autoconf_compat.m4 │ ├── sb_check_mysql.m4 │ ├── sb_concurrency_kit.m4 │ └── sb_luajit.m4 ├── missing ├── mkinstalldirs ├── rpm/ │ └── sysbench.spec ├── scripts/ │ └── buildpack.sh ├── snap/ │ └── snapcraft.yaml.in ├── src/ │ ├── Makefile.am │ ├── db_driver.c │ ├── db_driver.h │ ├── drivers/ │ │ ├── Makefile.am │ │ ├── mysql/ │ │ │ ├── Makefile.am │ │ │ └── drv_mysql.c │ │ └── pgsql/ │ │ ├── Makefile.am │ │ └── drv_pgsql.c │ ├── lua/ │ │ ├── Makefile.am │ │ ├── bulk_insert.lua │ │ ├── empty-test.lua │ │ ├── internal/ │ │ │ ├── Makefile.am │ │ │ ├── sysbench.cmdline.lua │ │ │ ├── sysbench.histogram.lua │ │ │ ├── sysbench.lua │ │ │ ├── sysbench.rand.lua │ │ │ └── sysbench.sql.lua │ │ ├── oltp_common.lua │ │ ├── oltp_delete.lua │ │ ├── oltp_insert.lua │ │ ├── oltp_point_select.lua │ │ ├── oltp_read_only.lua │ │ ├── oltp_read_write.lua │ │ ├── oltp_update_index.lua │ │ ├── oltp_update_non_index.lua │ │ ├── oltp_write_only.lua │ │ ├── prime-test.lua │ │ ├── select_random_points.lua │ │ └── select_random_ranges.lua │ ├── sb_barrier.c │ ├── sb_barrier.h │ ├── sb_ck_pr.h │ ├── sb_counter.c │ ├── sb_counter.h │ ├── sb_global.h │ ├── sb_histogram.c │ ├── sb_histogram.h │ ├── sb_list.h │ ├── sb_logger.c │ ├── sb_logger.h │ ├── sb_lua.c │ ├── sb_lua.h │ ├── sb_options.c │ ├── sb_options.h │ ├── sb_rand.c │ ├── sb_rand.h │ ├── sb_thread.c │ ├── sb_thread.h │ ├── sb_timer.c │ ├── sb_timer.h │ ├── sb_util.c │ ├── sb_util.h │ ├── sysbench.c │ ├── sysbench.h │ ├── tests/ │ │ ├── Makefile.am │ │ ├── cpu/ │ │ │ ├── Makefile.am │ │ │ └── sb_cpu.c │ │ ├── fileio/ │ │ │ ├── Makefile.am │ │ │ ├── crc32.c │ │ │ ├── crc32.h │ │ │ ├── crc32tbl.h │ │ │ └── sb_fileio.c │ │ ├── memory/ │ │ │ ├── Makefile.am │ │ │ └── sb_memory.c │ │ ├── mutex/ │ │ │ ├── Makefile.am │ │ │ └── sb_mutex.c │ │ ├── sb_cpu.h │ │ ├── sb_fileio.h │ │ ├── sb_memory.h │ │ ├── sb_mutex.h │ │ ├── sb_threads.h │ │ └── threads/ │ │ ├── Makefile.am │ │ └── sb_threads.c │ └── xoroshiro128plus.h ├── tests/ │ ├── Makefile.am │ ├── README.md │ ├── include/ │ │ ├── api_sql_common.sh │ │ ├── config.sh.in │ │ ├── drv_common.sh │ │ ├── inspect.lua │ │ ├── mysql_common.sh │ │ ├── pgsql_common.sh │ │ ├── script_bulk_insert_common.sh │ │ ├── script_oltp_common.sh │ │ └── script_select_random_common.sh │ ├── t/ │ │ ├── 1st.t │ │ ├── api_basic.t │ │ ├── api_histogram.t │ │ ├── api_rand.t │ │ ├── api_reports.t │ │ ├── api_sql_mysql.t │ │ ├── api_sql_pgsql.t │ │ ├── cmd_cleanup.t │ │ ├── cmd_help.t │ │ ├── cmd_prepare.t │ │ ├── cmd_run.t │ │ ├── cmdline.t │ │ ├── commands.t │ │ ├── drivers.t │ │ ├── drv_mysql.t │ │ ├── drv_pgsql.t │ │ ├── help_drv_mysql.t │ │ ├── help_drv_pgsql.t │ │ ├── opt_help.t │ │ ├── opt_histogram.t │ │ ├── opt_luajit_cmd.t │ │ ├── opt_rate.t │ │ ├── opt_report_checkpoints.t │ │ ├── opt_report_interval.t │ │ ├── opt_version.t │ │ ├── opt_warmup_time.t │ │ ├── script_bulk_insert_mysql.t │ │ ├── script_bulk_insert_pgsql.t │ │ ├── script_oltp_delete_mysql.t │ │ ├── script_oltp_delete_pgsql.t │ │ ├── script_oltp_general_mysql.t │ │ ├── script_oltp_help.t │ │ ├── script_oltp_insert_mysql.t │ │ ├── script_oltp_insert_pgsql.t │ │ ├── script_oltp_point_select_mysql.t │ │ ├── script_oltp_point_select_pgsql.t │ │ ├── script_oltp_read_write_mysql.t │ │ ├── script_oltp_read_write_pgsql.t │ │ ├── script_select_random_mysql.t │ │ ├── script_select_random_pgsql.t │ │ ├── test_cpu.t │ │ ├── test_fileio.t │ │ ├── test_memory.t │ │ ├── test_mutex.t │ │ ├── test_threads.t │ │ └── tests.t │ └── test_run.sh └── third_party/ ├── concurrency_kit/ │ ├── Makefile.am │ └── ck/ │ ├── .gitignore │ ├── LICENSE │ ├── README │ ├── build/ │ │ ├── ck.build.aarch64 │ │ ├── ck.build.arm │ │ ├── ck.build.in │ │ ├── ck.build.ppc │ │ ├── ck.build.ppc64 │ │ ├── ck.build.s390x │ │ ├── ck.build.sparcv9 │ │ ├── ck.build.x86 │ │ ├── ck.build.x86_64 │ │ ├── ck.pc.in │ │ ├── ck.spec.in │ │ └── regressions.build.in │ ├── configure │ ├── doc/ │ │ ├── CK_ARRAY_FOREACH │ │ ├── CK_COHORT_INIT │ │ ├── CK_COHORT_INSTANCE │ │ ├── CK_COHORT_LOCK │ │ ├── CK_COHORT_PROTOTYPE │ │ ├── CK_COHORT_TRYLOCK │ │ ├── CK_COHORT_TRYLOCK_PROTOTYPE │ │ ├── CK_COHORT_UNLOCK │ │ ├── CK_HS_HASH │ │ ├── CK_RHS_HASH │ │ ├── CK_RWCOHORT_INIT │ │ ├── CK_RWCOHORT_INSTANCE │ │ ├── CK_RWCOHORT_PROTOTYPE │ │ ├── CK_RWCOHORT_READ_LOCK │ │ ├── CK_RWCOHORT_READ_UNLOCK │ │ ├── CK_RWCOHORT_WRITE_LOCK │ │ ├── CK_RWCOHORT_WRITE_UNLOCK │ │ ├── ck_array_buffer │ │ ├── ck_array_commit │ │ ├── ck_array_deinit │ │ ├── ck_array_init │ │ ├── ck_array_initialized │ │ ├── ck_array_length │ │ ├── ck_array_put │ │ ├── ck_array_put_unique │ │ ├── ck_array_remove │ │ ├── ck_bitmap_base │ │ ├── ck_bitmap_bits │ │ ├── ck_bitmap_bts │ │ ├── ck_bitmap_buffer │ │ ├── ck_bitmap_clear │ │ ├── ck_bitmap_init │ │ ├── ck_bitmap_iterator_init │ │ ├── ck_bitmap_next │ │ ├── ck_bitmap_reset │ │ ├── ck_bitmap_set │ │ ├── ck_bitmap_size │ │ ├── ck_bitmap_test │ │ ├── ck_bitmap_union │ │ ├── ck_brlock │ │ ├── ck_cohort │ │ ├── ck_elide │ │ ├── ck_epoch_barrier │ │ ├── ck_epoch_begin │ │ ├── ck_epoch_call │ │ ├── ck_epoch_end │ │ ├── ck_epoch_init │ │ ├── ck_epoch_poll │ │ ├── ck_epoch_reclaim │ │ ├── ck_epoch_recycle │ │ ├── ck_epoch_register │ │ ├── ck_epoch_synchronize │ │ ├── ck_epoch_unregister │ │ ├── ck_hs_apply │ │ ├── ck_hs_count │ │ ├── ck_hs_destroy │ │ ├── ck_hs_fas │ │ ├── ck_hs_gc │ │ ├── ck_hs_get │ │ ├── ck_hs_grow │ │ ├── ck_hs_init │ │ ├── ck_hs_iterator_init │ │ ├── ck_hs_move │ │ ├── ck_hs_next │ │ ├── ck_hs_put │ │ ├── ck_hs_put_unique │ │ ├── ck_hs_rebuild │ │ ├── ck_hs_remove │ │ ├── ck_hs_reset │ │ ├── ck_hs_reset_size │ │ ├── ck_hs_set │ │ ├── ck_hs_stat │ │ ├── ck_ht_count │ │ ├── ck_ht_destroy │ │ ├── ck_ht_entry_empty │ │ ├── ck_ht_entry_key │ │ ├── ck_ht_entry_key_direct │ │ ├── ck_ht_entry_key_length │ │ ├── ck_ht_entry_key_set │ │ ├── ck_ht_entry_key_set_direct │ │ ├── ck_ht_entry_set │ │ ├── ck_ht_entry_set_direct │ │ ├── ck_ht_entry_value │ │ ├── ck_ht_entry_value_direct │ │ ├── ck_ht_gc │ │ ├── ck_ht_get_spmc │ │ ├── ck_ht_grow_spmc │ │ ├── ck_ht_hash │ │ ├── ck_ht_hash_direct │ │ ├── ck_ht_init │ │ ├── ck_ht_iterator_init │ │ ├── ck_ht_next │ │ ├── ck_ht_put_spmc │ │ ├── ck_ht_remove_spmc │ │ ├── ck_ht_reset_size_spmc │ │ ├── ck_ht_reset_spmc │ │ ├── ck_ht_set_spmc │ │ ├── ck_ht_stat │ │ ├── ck_pflock │ │ ├── ck_pr │ │ ├── ck_pr_add │ │ ├── ck_pr_and │ │ ├── ck_pr_barrier │ │ ├── ck_pr_btc │ │ ├── ck_pr_btr │ │ ├── ck_pr_bts │ │ ├── ck_pr_cas │ │ ├── ck_pr_dec │ │ ├── ck_pr_faa │ │ ├── ck_pr_fas │ │ ├── ck_pr_fence_acquire │ │ ├── ck_pr_fence_atomic │ │ ├── ck_pr_fence_atomic_load │ │ ├── ck_pr_fence_atomic_store │ │ ├── ck_pr_fence_load │ │ ├── ck_pr_fence_load_atomic │ │ ├── ck_pr_fence_load_depends │ │ ├── ck_pr_fence_load_store │ │ ├── ck_pr_fence_memory │ │ ├── ck_pr_fence_release │ │ ├── ck_pr_fence_store │ │ ├── ck_pr_fence_store_atomic │ │ ├── ck_pr_fence_store_load │ │ ├── ck_pr_inc │ │ ├── ck_pr_load │ │ ├── ck_pr_neg │ │ ├── ck_pr_not │ │ ├── ck_pr_or │ │ ├── ck_pr_rtm │ │ ├── ck_pr_stall │ │ ├── ck_pr_store │ │ ├── ck_pr_sub │ │ ├── ck_pr_xor │ │ ├── ck_queue │ │ ├── ck_rhs_apply │ │ ├── ck_rhs_count │ │ ├── ck_rhs_destroy │ │ ├── ck_rhs_fas │ │ ├── ck_rhs_gc │ │ ├── ck_rhs_get │ │ ├── ck_rhs_grow │ │ ├── ck_rhs_init │ │ ├── ck_rhs_iterator_init │ │ ├── ck_rhs_move │ │ ├── ck_rhs_next │ │ ├── ck_rhs_put │ │ ├── ck_rhs_put_unique │ │ ├── ck_rhs_rebuild │ │ ├── ck_rhs_remove │ │ ├── ck_rhs_reset │ │ ├── ck_rhs_reset_size │ │ ├── ck_rhs_set │ │ ├── ck_rhs_set_load_factor │ │ ├── ck_rhs_stat │ │ ├── ck_ring_capacity │ │ ├── ck_ring_dequeue_spmc │ │ ├── ck_ring_dequeue_spsc │ │ ├── ck_ring_enqueue_spmc │ │ ├── ck_ring_enqueue_spmc_size │ │ ├── ck_ring_enqueue_spsc │ │ ├── ck_ring_enqueue_spsc_size │ │ ├── ck_ring_init │ │ ├── ck_ring_size │ │ ├── ck_ring_trydequeue_spmc │ │ ├── ck_rwcohort │ │ ├── ck_rwlock │ │ ├── ck_sequence │ │ ├── ck_spinlock │ │ ├── ck_swlock │ │ ├── ck_tflock │ │ └── refcheck.pl │ ├── include/ │ │ ├── ck_array.h │ │ ├── ck_backoff.h │ │ ├── ck_barrier.h │ │ ├── ck_bitmap.h │ │ ├── ck_brlock.h │ │ ├── ck_bytelock.h │ │ ├── ck_cc.h │ │ ├── ck_cohort.h │ │ ├── ck_elide.h │ │ ├── ck_epoch.h │ │ ├── ck_fifo.h │ │ ├── ck_hp.h │ │ ├── ck_hp_fifo.h │ │ ├── ck_hp_stack.h │ │ ├── ck_hs.h │ │ ├── ck_ht.h │ │ ├── ck_limits.h │ │ ├── ck_malloc.h │ │ ├── ck_md.h.in │ │ ├── ck_pflock.h │ │ ├── ck_pr.h │ │ ├── ck_queue.h │ │ ├── ck_rhs.h │ │ ├── ck_ring.h │ │ ├── ck_rwcohort.h │ │ ├── ck_rwlock.h │ │ ├── ck_sequence.h │ │ ├── ck_spinlock.h │ │ ├── ck_stack.h │ │ ├── ck_stdbool.h │ │ ├── ck_stddef.h │ │ ├── ck_stdint.h │ │ ├── ck_stdlib.h │ │ ├── ck_string.h │ │ ├── ck_swlock.h │ │ ├── ck_tflock.h │ │ ├── gcc/ │ │ │ ├── aarch64/ │ │ │ │ ├── ck_f_pr.h │ │ │ │ ├── ck_pr.h │ │ │ │ ├── ck_pr_llsc.h │ │ │ │ └── ck_pr_lse.h │ │ │ ├── arm/ │ │ │ │ ├── ck_f_pr.h │ │ │ │ └── ck_pr.h │ │ │ ├── ck_cc.h │ │ │ ├── ck_f_pr.h │ │ │ ├── ck_pr.h │ │ │ ├── ppc/ │ │ │ │ ├── ck_f_pr.h │ │ │ │ └── ck_pr.h │ │ │ ├── ppc64/ │ │ │ │ ├── ck_f_pr.h │ │ │ │ └── ck_pr.h │ │ │ ├── s390x/ │ │ │ │ ├── ck_f_pr.h │ │ │ │ └── ck_pr.h │ │ │ ├── sparcv9/ │ │ │ │ ├── ck_f_pr.h │ │ │ │ └── ck_pr.h │ │ │ ├── x86/ │ │ │ │ ├── ck_f_pr.h │ │ │ │ └── ck_pr.h │ │ │ └── x86_64/ │ │ │ ├── ck_f_pr.h │ │ │ ├── ck_pr.h │ │ │ └── ck_pr_rtm.h │ │ └── spinlock/ │ │ ├── anderson.h │ │ ├── cas.h │ │ ├── clh.h │ │ ├── dec.h │ │ ├── fas.h │ │ ├── hclh.h │ │ ├── mcs.h │ │ └── ticket.h │ ├── regressions/ │ │ ├── Makefile.unsupported │ │ ├── ck_array/ │ │ │ └── validate/ │ │ │ └── serial.c │ │ ├── ck_backoff/ │ │ │ └── validate/ │ │ │ └── validate.c │ │ ├── ck_barrier/ │ │ │ ├── benchmark/ │ │ │ │ └── throughput.c │ │ │ └── validate/ │ │ │ ├── barrier_centralized.c │ │ │ ├── barrier_combining.c │ │ │ ├── barrier_dissemination.c │ │ │ ├── barrier_mcs.c │ │ │ └── barrier_tournament.c │ │ ├── ck_bitmap/ │ │ │ └── validate/ │ │ │ └── serial.c │ │ ├── ck_brlock/ │ │ │ ├── benchmark/ │ │ │ │ ├── latency.c │ │ │ │ └── throughput.c │ │ │ └── validate/ │ │ │ └── validate.c │ │ ├── ck_bytelock/ │ │ │ ├── benchmark/ │ │ │ │ └── latency.c │ │ │ └── validate/ │ │ │ └── validate.c │ │ ├── ck_cohort/ │ │ │ ├── benchmark/ │ │ │ │ ├── ck_cohort.c │ │ │ │ └── throughput.c │ │ │ ├── ck_cohort.h │ │ │ └── validate/ │ │ │ └── validate.c │ │ ├── ck_epoch/ │ │ │ └── validate/ │ │ │ ├── ck_epoch_call.c │ │ │ ├── ck_epoch_poll.c │ │ │ ├── ck_epoch_section.c │ │ │ ├── ck_epoch_section_2.c │ │ │ ├── ck_epoch_synchronize.c │ │ │ ├── ck_stack.c │ │ │ └── torture.c │ │ ├── ck_fifo/ │ │ │ ├── benchmark/ │ │ │ │ └── latency.c │ │ │ └── validate/ │ │ │ ├── ck_fifo_mpmc.c │ │ │ ├── ck_fifo_mpmc_iterator.c │ │ │ ├── ck_fifo_spsc.c │ │ │ └── ck_fifo_spsc_iterator.c │ │ ├── ck_hp/ │ │ │ ├── benchmark/ │ │ │ │ ├── fifo_latency.c │ │ │ │ └── stack_latency.c │ │ │ └── validate/ │ │ │ ├── ck_hp_fifo.c │ │ │ ├── ck_hp_fifo_donner.c │ │ │ ├── ck_hp_stack.c │ │ │ ├── nbds_haz_test.c │ │ │ └── serial.c │ │ ├── ck_hs/ │ │ │ ├── benchmark/ │ │ │ │ ├── apply.c │ │ │ │ ├── parallel_bytestring.c │ │ │ │ └── serial.c │ │ │ └── validate/ │ │ │ └── serial.c │ │ ├── ck_ht/ │ │ │ ├── benchmark/ │ │ │ │ ├── parallel_bytestring.c │ │ │ │ ├── parallel_direct.c │ │ │ │ └── serial.c │ │ │ └── validate/ │ │ │ └── serial.c │ │ ├── ck_pflock/ │ │ │ ├── benchmark/ │ │ │ │ ├── latency.c │ │ │ │ └── throughput.c │ │ │ └── validate/ │ │ │ └── validate.c │ │ ├── ck_pr/ │ │ │ ├── benchmark/ │ │ │ │ ├── benchmark.h │ │ │ │ ├── ck_pr_add_64.c │ │ │ │ ├── ck_pr_cas_64.c │ │ │ │ ├── ck_pr_cas_64_2.c │ │ │ │ ├── ck_pr_faa_64.c │ │ │ │ ├── ck_pr_fas_64.c │ │ │ │ ├── ck_pr_neg_64.c │ │ │ │ └── fp.c │ │ │ └── validate/ │ │ │ ├── ck_pr_add.c │ │ │ ├── ck_pr_and.c │ │ │ ├── ck_pr_bin.c │ │ │ ├── ck_pr_btc.c │ │ │ ├── ck_pr_btr.c │ │ │ ├── ck_pr_bts.c │ │ │ ├── ck_pr_btx.c │ │ │ ├── ck_pr_cas.c │ │ │ ├── ck_pr_dec.c │ │ │ ├── ck_pr_faa.c │ │ │ ├── ck_pr_fas.c │ │ │ ├── ck_pr_fax.c │ │ │ ├── ck_pr_inc.c │ │ │ ├── ck_pr_load.c │ │ │ ├── ck_pr_n.c │ │ │ ├── ck_pr_or.c │ │ │ ├── ck_pr_store.c │ │ │ ├── ck_pr_sub.c │ │ │ ├── ck_pr_unary.c │ │ │ └── ck_pr_xor.c │ │ ├── ck_queue/ │ │ │ └── validate/ │ │ │ ├── ck_list.c │ │ │ ├── ck_slist.c │ │ │ └── ck_stailq.c │ │ ├── ck_rhs/ │ │ │ ├── benchmark/ │ │ │ │ ├── parallel_bytestring.c │ │ │ │ └── serial.c │ │ │ └── validate/ │ │ │ └── serial.c │ │ ├── ck_ring/ │ │ │ ├── benchmark/ │ │ │ │ └── latency.c │ │ │ └── validate/ │ │ │ ├── ck_ring_mpmc.c │ │ │ ├── ck_ring_mpmc_template.c │ │ │ ├── ck_ring_spmc.c │ │ │ ├── ck_ring_spmc_template.c │ │ │ └── ck_ring_spsc.c │ │ ├── ck_rwcohort/ │ │ │ ├── benchmark/ │ │ │ │ ├── ck_neutral.c │ │ │ │ ├── ck_rp.c │ │ │ │ ├── ck_wp.c │ │ │ │ ├── latency.h │ │ │ │ └── throughput.h │ │ │ ├── ck_neutral.h │ │ │ ├── ck_rp.h │ │ │ ├── ck_wp.h │ │ │ └── validate/ │ │ │ ├── ck_neutral.c │ │ │ ├── ck_rp.c │ │ │ ├── ck_wp.c │ │ │ └── validate.h │ │ ├── ck_rwlock/ │ │ │ ├── benchmark/ │ │ │ │ ├── latency.c │ │ │ │ └── throughput.c │ │ │ └── validate/ │ │ │ └── validate.c │ │ ├── ck_sequence/ │ │ │ ├── benchmark/ │ │ │ │ └── ck_sequence.c │ │ │ └── validate/ │ │ │ └── ck_sequence.c │ │ ├── ck_spinlock/ │ │ │ ├── benchmark/ │ │ │ │ ├── ck_anderson.c │ │ │ │ ├── ck_cas.c │ │ │ │ ├── ck_clh.c │ │ │ │ ├── ck_dec.c │ │ │ │ ├── ck_fas.c │ │ │ │ ├── ck_hclh.c │ │ │ │ ├── ck_mcs.c │ │ │ │ ├── ck_spinlock.c │ │ │ │ ├── ck_ticket.c │ │ │ │ ├── ck_ticket_pb.c │ │ │ │ ├── latency.h │ │ │ │ ├── linux_spinlock.c │ │ │ │ └── throughput.h │ │ │ ├── ck_anderson.h │ │ │ ├── ck_cas.h │ │ │ ├── ck_clh.h │ │ │ ├── ck_dec.h │ │ │ ├── ck_fas.h │ │ │ ├── ck_hclh.h │ │ │ ├── ck_mcs.h │ │ │ ├── ck_spinlock.h │ │ │ ├── ck_ticket.h │ │ │ ├── ck_ticket_pb.h │ │ │ ├── linux_spinlock.h │ │ │ └── validate/ │ │ │ ├── ck_anderson.c │ │ │ ├── ck_cas.c │ │ │ ├── ck_clh.c │ │ │ ├── ck_dec.c │ │ │ ├── ck_fas.c │ │ │ ├── ck_hclh.c │ │ │ ├── ck_mcs.c │ │ │ ├── ck_spinlock.c │ │ │ ├── ck_ticket.c │ │ │ ├── ck_ticket_pb.c │ │ │ ├── linux_spinlock.c │ │ │ └── validate.h │ │ ├── ck_stack/ │ │ │ ├── benchmark/ │ │ │ │ └── latency.c │ │ │ └── validate/ │ │ │ ├── pair.c │ │ │ ├── pop.c │ │ │ ├── push.c │ │ │ └── serial.c │ │ ├── ck_swlock/ │ │ │ ├── benchmark/ │ │ │ │ ├── latency.c │ │ │ │ └── throughput.c │ │ │ └── validate/ │ │ │ └── validate.c │ │ ├── ck_tflock/ │ │ │ ├── benchmark/ │ │ │ │ ├── latency.c │ │ │ │ └── throughput.c │ │ │ └── validate/ │ │ │ └── validate.c │ │ └── common.h │ ├── src/ │ │ ├── ck_array.c │ │ ├── ck_barrier_centralized.c │ │ ├── ck_barrier_combining.c │ │ ├── ck_barrier_dissemination.c │ │ ├── ck_barrier_mcs.c │ │ ├── ck_barrier_tournament.c │ │ ├── ck_epoch.c │ │ ├── ck_hp.c │ │ ├── ck_hs.c │ │ ├── ck_ht.c │ │ ├── ck_ht_hash.h │ │ ├── ck_internal.h │ │ └── ck_rhs.c │ └── tools/ │ └── feature.sh ├── cram/ │ ├── .coveragerc │ ├── .gitignore │ ├── .hgignore │ ├── .hgtags │ ├── .pylintrc │ ├── .travis.yml │ ├── COPYING.txt │ ├── MANIFEST.in │ ├── NEWS.rst │ ├── README.rst │ ├── TODO.md │ ├── contrib/ │ │ ├── PKGBUILD │ │ └── cram.vim │ ├── cram/ │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── _cli.py │ │ ├── _diff.py │ │ ├── _encoding.py │ │ ├── _main.py │ │ ├── _process.py │ │ ├── _run.py │ │ ├── _test.py │ │ └── _xunit.py │ ├── examples/ │ │ ├── .hidden/ │ │ │ └── hidden.t │ │ ├── .hidden.t │ │ ├── bare.t │ │ ├── empty.t │ │ ├── env.t │ │ ├── fail.t │ │ ├── missingeol.t │ │ ├── skip.t │ │ └── test.t │ ├── requirements.txt │ ├── scripts/ │ │ └── cram │ ├── setup.cfg │ ├── setup.py │ └── tests/ │ ├── config.t │ ├── debug.t │ ├── dist.t │ ├── doctest.t │ ├── encoding.t │ ├── interactive.t │ ├── pep8.t │ ├── pyflakes.t │ ├── run-doctests.py │ ├── setup.sh │ ├── test.t │ ├── usage.t │ └── xunit.t └── luajit/ ├── Makefile.am └── luajit/ ├── .gitignore ├── COPYRIGHT ├── README ├── doc/ │ ├── bluequad-print.css │ ├── bluequad.css │ ├── contact.html │ ├── ext_buffer.html │ ├── ext_c_api.html │ ├── ext_ffi.html │ ├── ext_ffi_api.html │ ├── ext_ffi_semantics.html │ ├── ext_ffi_tutorial.html │ ├── ext_jit.html │ ├── ext_profiler.html │ ├── extensions.html │ ├── faq.html │ ├── install.html │ ├── luajit.html │ ├── running.html │ └── status.html ├── dynasm/ │ ├── dasm_arm.h │ ├── dasm_arm.lua │ ├── dasm_arm64.h │ ├── dasm_arm64.lua │ ├── dasm_mips.h │ ├── dasm_mips.lua │ ├── dasm_mips64.lua │ ├── dasm_ppc.h │ ├── dasm_ppc.lua │ ├── dasm_proto.h │ ├── dasm_x64.lua │ ├── dasm_x86.h │ ├── dasm_x86.lua │ └── dynasm.lua └── etc/ ├── luajit.1 └── luajit.pc ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: [push, pull_request] jobs: build: strategy: matrix: os: [ ubuntu-22.04, ubuntu-20.04 ] runs-on: ${{ matrix.os }} name: Build on ${{ matrix.os }} steps: - name: Checkout uses: actions/checkout@v3 - name: Autogen run: ./autogen.sh - name: Configure run: ./configure --with-mysql --with-pgsql - name: Build run: make - name: MySQL version run: mysql_config --version - name: Sysbench version run: ./src/sysbench --version - name: Test run: make test build_mariadb: runs-on: ubuntu-22.04 name: Build with MariaDB steps: - name: Setup MariaDB Repo run: | sudo apt-get install software-properties-common sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8 sudo add-apt-repository 'deb [arch=amd64] https://ftp.nluug.nl/db/mariadb/repo/11.0/ubuntu jammy main' - name: Setup MariaDB Libs run: sudo apt install libmariadb-dev libmariadb-dev-compat - name: Checkout uses: actions/checkout@v3 - name: Autogen run: ./autogen.sh - name: Configure run: ./configure --with-mysql --with-pgsql - name: Build run: make - name: MariaDB version run: mariadb_config --version - name: Sysbench version run: ./src/sysbench --version - name: Test run: make test ================================================ FILE: .gitignore ================================================ *.o *.a Makefile Makefile.in aclocal.m4 autom4te.cache /config/config.h /config/ltmain.sh /config/stamp-h1 /doc/manual.html /config.log /config.status /configure /libtool /doc/xsl/catalog.xml /src/.deps /src/.libs /src/sysbench /src/drivers/mysql/.deps /src/drivers/oracle/.deps /src/drivers/pgsql/.deps /src/tests/cpu/.deps /src/tests/fileio/.deps /src/tests/memory/.deps /src/tests/mutex/.deps /src/tests/oltp/.deps /src/tests/threads/.deps /TAGS /backup.bzr /config/config.guess /config/config.h.in /config/config.sub /src/TAGS /src/drivers/TAGS /src/drivers/mysql/TAGS /src/tests/TAGS /src/tests/cpu/TAGS /src/tests/fileio/TAGS /src/tests/memory/TAGS /src/tests/mutex/TAGS /src/tests/oltp/TAGS /src/tests/threads/TAGS /config/compile /config/depcomp /config/install-sh /config/missing /m4/libtool.m4 /m4/ltoptions.m4 /m4/ltsugar.m4 /m4/ltversion.m4 /m4/lt~obsolete.m4 /src/drivers/drizzle/.deps /src/scripting/.deps /src/scripting/lua/src/.deps GPATH GRTAGS GTAGS /config/ar-lib /src/drivers/attachsql/.deps/ /config/test-driver *.DS_Store /tests/*.log /tests/*.trs *.gcda *.gcno /tests/include/config.sh /third_party/concurrency_kit/include/ /third_party/concurrency_kit/lib/ /third_party/concurrency_kit/share/ /third_party/concurrency_kit/tmp/ third_party/luajit/bin/ third_party/luajit/inc/ third_party/luajit/lib/ third_party/luajit/share/ third_party/luajit/tmp/ src/lua/internal/sysbench.lua.h src/lua/internal/sysbench.sql.lua.h /src/lua/internal/sysbench.rand.lua.h /src/lua/internal/sysbench.opt.lua.h tests/t/*.err /src/lua/internal/sysbench.cmdline.lua.h /src/lua/internal/sysbench.compat.lua.h /src/lua/internal/sysbench.histogram.lua.h parts prime stage *.snap /snap/snapcraft.yaml ================================================ FILE: .travis.yml ================================================ # vim ft=yaml # # Travis CI configuration arch: - amd64 - arm64 dist: trusty sudo: required services: - docker - mysql - postgresql git: depth: 100500 language: c os: - linux - osx osx_image: xcode12.2 compiler: - gcc - clang env: matrix: - TARGET=distcheck - TARGET=test - TARGET=coverage - OS=el DIST=7 - OS=el DIST=8 - OS=fedora DIST=32 # Currently unsupported by packagecloud # - OS=fedora DIST=33 - OS=ubuntu DIST=xenial - OS=ubuntu DIST=bionic - OS=ubuntu DIST=focal - OS=ubuntu DIST=groovy - OS=debian DIST=stretch - OS=debian DIST=buster - OS=debian DIST=sid - OS=ubuntu DIST=xenial ARCH=i386 - OS=ubuntu DIST=bionic ARCH=i386 - OS=debian DIST=stretch ARCH=i386 - OS=debian DIST=buster ARCH=i386 - OS=debian DIST=sid ARCH=i386 matrix: exclude: - env: OS=el DIST=7 compiler: clang - env: OS=el DIST=8 compiler: clang - env: OS=fedora DIST=32 compiler: clang - env: OS=fedora DIST=33 compiler: clang - env: OS=ubuntu DIST=xenial compiler: clang - env: OS=ubuntu DIST=bionic compiler: clang - env: OS=ubuntu DIST=disco compiler: clang - env: OS=ubuntu DIST=focal compiler: clang - env: OS=ubuntu DIST=groovy compiler: clang - env: OS=debian DIST=stretch compiler: clang - env: OS=debian DIST=buster compiler: clang - env: OS=debian DIST=sid compiler: clang - env: OS=ubuntu DIST=xenial ARCH=i386 compiler: clang - env: OS=ubuntu DIST=bionic ARCH=i386 compiler: clang - env: OS=ubuntu DIST=disco ARCH=i386 compiler: clang - env: OS=debian DIST=stretch ARCH=i386 compiler: clang - env: OS=debian DIST=buster ARCH=i386 compiler: clang - env: OS=debian DIST=sid ARCH=i386 compiler: clang - env: OS=ubuntu DIST=xenial ARCH=i386 arch: arm64 - env: OS=ubuntu DIST=bionic ARCH=i386 arch: arm64 - env: OS=ubuntu DIST=disco ARCH=i386 arch: arm64 - env: OS=debian DIST=stretch ARCH=i386 arch: arm64 - env: OS=debian DIST=buster ARCH=i386 arch: arm64 - env: OS=debian DIST=sid ARCH=i386 arch: arm64 - env: OS=el DIST=7 os: osx - env: OS=el DIST=8 os: osx - env: OS=fedora DIST=32 os: osx - env: OS=fedora DIST=33 os: osx - env: OS=ubuntu DIST=xenial os: osx - env: OS=ubuntu DIST=bionic os: osx - env: OS=ubuntu DIST=disco os: osx - env: OS=ubuntu DIST=focal os: osx - env: OS=ubuntu DIST=groovy os: osx - env: OS=debian DIST=stretch os: osx - env: OS=debian DIST=buster os: osx - env: OS=debian DIST=sid os: osx - env: TARGET=distcheck compiler: clang - env: TARGET=distcheck os: osx - env: TARGET=distcheck arch: arm64 - env: TARGET=coverage os: osx - env: TARGET=coverage compiler: clang - env: TARGET=coverage arch: arm64 - os: osx compiler: gcc - os: osx arch: arm64 - arch: arm64 compiler: clang addons: apt: packages: - libmysqlclient-dev - libpq-dev - libaio-dev - clang-3.6 before_install: # Upload builds corresponding to release tags to the 'sysbench' # repository, push other ones to 'sysbench-prereleases' - git describe --long --always - commits=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\2/p') - > if [ ${commits:-0} = 0 ]; then export VERSION=$(git describe) PACKAGECLOUD_REPO=sysbench else PACKAGECLOUD_REPO=sysbench-prereleases fi - > if [ "x$TARGET" = "xtest" ]; then case "${TRAVIS_OS_NAME:-linux}" in osx) brew update brew install mysql postgresql # OS X requires servers to be started explicitly brew services start mysql cat /usr/local/var/mysql/*.err lsof -c mysql brew postgresql-upgrade-database brew services start postgresql echo "Starting PostgreSQL" pg_ctl -wD /usr/local/var/postgres start echo "Creating user postgres" createuser -s postgres ;; linux) export ASAN_OPTIONS="detect_leaks=0" if [ "${CC}" = "clang" ]; then CC=clang-3.6 fi ;; esac fi install: - > case "${TRAVIS_OS_NAME:-linux}" in osx) # OS X requires this for user-local pip packages export PATH=~/Library/Python/2.7/bin:$PATH ;; linux) pip install --user cpp-coveralls ;; esac before_script: - mysql -u root -e 'CREATE DATABASE sbtest' - psql -U postgres -c 'CREATE DATABASE sbtest' script: - > if [ -n "$TARGET" ]; then case "$TARGET" in test) ./autogen.sh && ./configure --with-mysql --with-pgsql make SBTEST_MYSQL_ARGS="--mysql-user=root" SBTEST_PGSQL_ARGS="--pgsql-user=postgres" make test ;; distcheck) ./autogen.sh && ./configure --without-mysql make make distcheck ;; coverage) ./autogen.sh && ./configure --enable-coverage --enable-asan --enable-msan --with-mysql --with-pgsql make -j2 SBTEST_MYSQL_ARGS="--mysql-user=root" SBTEST_PGSQL_ARGS="--pgsql-user=postgres" make test ;; esac else # To avoid name conflicts, deploy source packages only for # "default", i.e. x86_64 architecture if [[ -z "$ARCH" && "$TRAVIS_CPU_ARCH" == amd64 ]]; then PACKAGECLOUD_GLOB='build/*.{rpm,deb,dsc}' else # Exclude *.src.rpm and *.dsc PACKAGECLOUD_GLOB='build/*{[^c].rpm,.deb}' fi git clone https://github.com/akopytov/packpack.git packpack packpack/packpack fi deploy: # Deploy packages to PackageCloud - provider: packagecloud username: "${PACKAGECLOUD_USER}" repository: "${PACKAGECLOUD_REPO}" token: "${PACKAGECLOUD_TOKEN}" dist: "${OS}/${DIST}" package_glob: "${PACKAGECLOUD_GLOB}" skip_cleanup: true on: all_branches: true condition: -n "$OS" && -n "$DIST" && -n "$PACKAGECLOUD_TOKEN" && "$DIST" != "rawhide" && "$DIST" != "sid" after_success: - > if [ "x$TARGET" = "xcoverage" ]; then coveralls --exclude third_party/ --gcov-options '\-lp' fi # Local variables: # mode: yaml # End: ================================================ FILE: COPYING ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: ChangeLog ================================================ 2020-04-24 Alexey Kopytov * version 1.0.20 * build/CI/packaging: Add arm64 to Travis CI matrix (#358) * build/CI/packaging: add Ubuntu Focal * build/CI/packaging: remove Fedora Rawhide from CI matrix * build/CI/packaging: fix regression tests to work with MySQL 8.0.19+ * build/CI/packaging: fix macOS builds in Travis * build/CI/packaging: remove Ubuntu Disco (EOL) 2019-12-08 Alexey Kopytov * version 1.0.19 * build/CI/packaging: fix Ubuntu packaging for Bionic and later versions * regression tests: compatibility fix for PostgreSQL 12 * build/CI/packaging: fix macOs builds in Travis * build/CI/packaging: add Fedora 31. 2019-10-21 Alexey Kopytov * version 1.0.18 * build/CI/packaging: add Ubuntu Eoan. * build/CI/packaging: remove Ubuntu Cosmic (EOL). * build/CI/packaging: add CentOS 8. * build/CI/packaging: add Ubuntu Disco. * build/CI/packaging: remove Ubuntu Trusty (EOL). * build/CI/packaging: remove Fedora 28 (EOL). * build/CI/packaging: add Fedora 30. * build/CI/packaging: cherry-pick fix for LuaJIT/LuaJIT#484 to fix builds on macOS Mojave. * build/CI/packaging: add Debian Buster 2019-03-15 Alexey Kopytov * version 1.0.17 * build/CI/packaging: update RPM spec to support RHEL8-beta (thanks to Alexey Bychko for the patch) * regression tests: remove unnecessary error leading to opt_rate.t instability. * --rate mode: return a non-zero exit code on event queue overflow. * --rate mode: fix a bogus error about eventgen thread termination 2018-12-16 Alexey Kopytov * version 1.0.16 * build/CI/packaging: add Ubuntu Cosmic. * build/CI/packaging: add Fedora 29. * build/CI/packaging: remove Fedora 27 (EOL). * SQL API: fix GH-282 (Mysql's fetch_row() is broken) * --rate mode: fix latency stats skew on low rates * Lua: Add /usr/share/lua/5.1 to LUA_PATH and /usr/lib/lua/5.1 to LUA_CPATH. * build/CI/packaging: add -Wvla to default compiler flags. * build/CI/packaging: fix debian/changelog format * build/CI/packaging: fix buildpack.sh to not push multiple file types to packagecloud. * build/CI/packaging: add libaio-dev to Debian/Ubuntu build dependencies. 2018-07-03 Alexey Kopytov * version 1.0.15 * CI/build/packaging: add Fedora 28 * CI/build/packaging: add Ubuntu Bionic * CI/build/packaging: remove Fedora 26 (EOL) * CI/build/packaging: remove Debian Wheezy (EOL) * fileio: fix GH-229 (--file-fsync-freq=0 seems to prevent fsync() at the end of the test) * command line: improve parsing of boolean command line options * tests: fix GH-220 (Testsuite api_sql_mysql.t failed ...) * tests: fix GH-223 (test failure on ppc64) * tests: fix opt_help.t to pass when the binary is not configured with MySQL support * MySQL driver: use it by default in DB benchmarks 2018-04-01 Alexey Kopytov * version 1.0.14 * reports: fix JSON stats reporter to produce valid JSON (GH-195) * Lua SQL API: don't crash when query_row() is called with a SELECT returning empty result set * Lua SQL API: don't crash when bulk insert API calls are used out of order * regression tests: make PostgreSQL tests compatible with the new dump format introduced in 10.3 * regression tests: minor stability and coverage improvements 2018-02-17 Alexey Kopytov * version 1.0.13 * remove Ubuntu Zesty from CI/build/packaging matrices (EOL) * minor cleanups in build scripts * improve report formatting for long latency values * fileio: --file-extra-flags now accepts a list of flags rather than just a single value * OLTP: re-prepare prepared statements after reconnects, i.e. in cases when a server connection is lost and sysbench is configured to ignore such errors 2018-01-17 Alexey Kopytov * version 1.0.12 * improve --rate mode precision for high argument values * add Fedora Rawhide and Debian Sid to CI matrix * fix compile-time architecture detection for some Broadwell CPUs which were incorrectly identified as Core 2. * remove build dependency on xxd (and vim-minimal package) * fix Lua API to correctly stop the benchmark when event() returns a value other than nil or false (thanks to caojiafeng for the patch) * fix the fileio benchmark when the specified file size is not a multiple of block size * fix the fileio benchmark to throw a descriptive error when the specified file size does not match the size of files created by 'prepare' * remove Fedora 25 from CI/build/packaging matrices (EOL) * minor improvements in tests and documentation. 2017-12-09 Alexey Kopytov * version 1.0.11 * add Debian Stretch to CI/build/packaging matrices * add Fedora 27 to CI/build/packaging matrices * make statistic counters usable from Lua scripts * fix the PostgreSQL driver to be compatible with CockroachDB (GH-180) * fix oltp_insert.lua to work correctly when both --tables and --threads are greater than 1 (GH-178) * fix FreeBSD builds by adding -rdynamic to the default linker flags (GH-174) * minor documentation updates 2017-10-25 Alexey Kopytov * version 1.0.10 * fixed PK conflicts in oltp_insert.lua by creating empty tables on 'prepare' * made sysbench.opt available to init()/done() by exporting it to the global Lua state * added Fedora 26 (both x86_64 and AArch64) to the list of supported and tested distributions * fixed GH-172: sysbench 1.0.9 doesn't build with mariadb 10.2.8 * add the /usr/local LuaRocks root directory to default LUA_PATH and LUA_CPATH * removed Fedora 24, Ubuntu Precise, Yakkety from default build matrices * added Ubuntu Artful to default build matrices 2017-09-05 Alexey Kopytov * version 1.0.9 * fixed oltp_delete.lua to not use INSERT statements for consistency with other oltp_* benchmarks (GH-168) * added a workaround for MySQL bug #87337 "8.0.2 reintroduces my_bool to client API" * fixed building on on Debian GNU/kFreeBSD (GH-161) * fixed building against MariaDB 10.2 (thanks to Xavier Bachelot for the patch, GH-160) 2017-07-04 Alexey Kopytov * version 1.0.8 * fixed api_report test for slow machines (thanks to @jcfp) * fileio: suggest to run prepare step on missing files (thanks to Heinrich Schuchardt) * JSON reports: removed an erroneous trailing comma (GH-139) * added events per second to the CPU benchmark report (GH-140) * fixed db_connect() in legacy SQL API to use the default value for --db-driver (GH-146) * removed busy-wait in the bounded event generation mode (--rate) to avoid CPU hogging 2017-05-15 Alexey Kopytov * version 1.0.7 * Ubuntu Zesty added to package build matrix * fixed GH-130: Mutex Benchmark Documentation * fixed latency reports in the --rate mode * fixed compiler warnings when building against MySQL 8.0 client libraries 2017-04-13 Alexey Kopytov * version 1.0.6 * no functional changes * many build- and packaging-related improvements * Linux packages are now automatically built using Travis CI and packpack, hosted by packagecloud.io 2017-04-02 Alexey Kopytov * version 1.0.5 * various build-related documentation updates * benchmark can now be specified by a module name on the command line * memory benchmark: performance and scalability improvements * fix ARMv6 builds with system ConcurrencyKit * fix GH-123: Table already exists error on prepare * fix GH-121: make buildhost cpudetection optional 2017-03-13 Alexey Kopytov * version 1.0.4 * fixed a number of compilation errors and warnings that were specific to 32-bit platforms * bundle cram (regression tests framework) and use it by default in 'make test' * bundled ConcurrencyKit updated to 0.6.0 2017-02-26 Alexey Kopytov * version 1.0.3 * LuaJIT scalability improvements for non-x86 architectures * performance optimizations in oltp_read_write.lua to avoid Lua string management * fixed Illumos builds (thanks to Dillon Amburgey) 2017-02-17 Alexey Kopytov * version 1.0.2 * improved scalability for --report-checkpoints mode * fix builds on CentoOS 6 and autoconf 2.63 * support for Snap (http://snapcraft.io) packages 2017-02-05 Alexey Kopytov * version 1.0.1 * fix clock_gettime runtime failure built with macOS 10.11 and Xcode 8.x 2017-02-04 Aleksei Kopytov * version 1.0.0 * too much time and too many changes since the previous formal release, so briefly: * Lua scripts instead of hard-coded C tests for database ("oltp") benchmarks + ability to create custom workloads * much better single-threaded performance * much better scalability * improvements and cleanups in command line syntax and options * latency histograms in cumulative statistic reports * report hooks to print statistics in custom formats (CSV/JSON/XML/etc.) * Dropped Windows support * Dropped support for Oracle, Drizzle and libattachsql drivers 2006-10-10 Alexey Kopytov * Removed the debugging code in OLTP test which got into 0.4.7 by mistake * Handle ER_CHECKREAD in the same way as deadlocks in the MySQL driver * version 0.4.8 2006-05-28 Alexey Kopytov * count fsync() time as request execution time in file-fsync-all mode 2006-05-24 Alexey Kopytov * Added --oltp-reconnect option 2006-05-18 Alexey Kopytov * Allow build with non-gcc compilers * Fixed random numbers generation on Solaris * Added --mysql-ssl option * version 0.4.7 2006-04-03 Alexey Kopytov * Added a warning for inaccurate gettimeofday() implementations * version 0.4.6 2006-03-10 Alexey Kopytov * Fixed crash at the end of OLTP test 2006-03-03 Alexey Kopytov * Made auto_increment id column optional * Use TYPE= or ENGINE= in MySQL driver depending on the version of client libraries 2006-01-17 Alexey Kopytov * version 0.4.5 * Added several hosts capability to MySQL driver * Fixed several memory leaks in OLTP test 2005-12-14 Alexey Kopytov * Renamed option 'mysql-table-type' to 'mysql-table-engine' * It's now possible to pass arbitrary engine names to MySQL driver * Transactions support must be explicitly specified with 'mysql-engine-trx' option for those engines, which are unknown to SysBench 2005-09-27 Alexey Kopytov * Changed 'thread fairness' calculation from percents to stddev * Added validation mode to OLTP test (--validate switch) * Remove auto_increment from the 'id' field before running OLTP tests * Print separate time for query execution and result fetching in --debug mode * version 0.4.3 2005-07-25 Alexey Kopytov * Minor cleanups in help messages * Several FreeBSD-related fixes * Fixed the Oracle driver * Version 0.4.1 2005-03-04 Alexey Kopytov * Fixed a lot of small bugs, including portability issues on Mac OS X, 64-bit platforms and old MySQL versions * Documentation added to the main tree * New validation mode in fileio test 2005-01-27 Alexey Kopytov * Fixed compilation on Solaris * Added call to thr_setconcurrency() on Solaris * Fixed an overflow bug in sb_timer_current() * Changed the default number of threads to 1 * Added non-transactional mode to the OLTP test * Fixed bug with excessive number of connections in OLTP test * Handle ER_LOCK_WAIT_TIMEOUT in the same way as ER_LOCK_DEADLOCK * Version 0.3.2 2004-07-27 Alexey Kopytov * Fixed MySQL driver to use new PS API in MySQL >= 4.1.2 2004-07-12 Alexey Kopytov * Fixed final fsync in random I/O requests * Fixed several race conditions 2004-07-09 Alexey Kopytov * Removed --oltp-time-limit option (obsoleted by --max-time) 2004-07-06 Alexey Kopytov * Changed statistics output to more human-readable format 2004-07-04 Alexey Kopytov * Added new logger interface to internal API * Modified all tests to use the new logger interface 2004-06-17 Alexey Kopytov * Fixed table type autodetection with MySQL >= 4.1 2004-06-06 Alexey Kopytov * Added preliminary support of prepared statements to DB API 2004-05-31 Alexey Kopytov * Added slow-mmap mode for 32-bit boxes in fileio test 2004-05-30 Alexey Kopytov * Fixed compilation with gcc >= 3.3 * Fixed 'prepare' command for sequential write test 2004-05-26 Alexey Kopytov * Changed formatting of file sizes in output * Fixed type cast warning on SuSE 8.1 2004-05-21 Alexey Kopytov * Added mutex performance benchmark 2004-05-12 Alexey Kopytov * Extended memory benchmark to calculate more useful results 2004-05-10 Alexey Kopytov * Split test file creation, test running and cleaning up into separate commands (prepare, run, cleanup) for fileio test 2004-05-05 Alexey Kopytov * Removed limit on maximum block size for fileio test 2004-05-04 Alexey Kopytov * added --max-time option to limit total test execution time 2004-05-03 Alexey Kopytov * Fixed compilation with --without-mysql option. 2004-04-13 Alexey Kopytov * Added mmaped I/O support to fileio test 2004-04-11 Alexey Kopytov * Changed default table size to a lower value in OLTP test 2004-04-07 Alexey Kopytov * Added automatic table type detection to MySQL driver * Changed the default table type for MySQL driver to InnoDB * Added support for BDB and NDB table types 2004-04-06 Alexey Kopytov * Added autoconf macro to handle older (incompatible) version of libaio.h 2004-04-05 Alexey Kopytov * Fixed compilation on 64-bit systems * Replaced Linux AIO calls with more portable equivalents 2004-04-04 Alexey Kopytov * Added parameter to specify maximum number of queued operations in fileio async mode (file-async-backlog) * Added parameter to specify extra open() flags (file-extra-flags) * Fixed memory allocation bug in command line parser 2004-04-02 Alexey Kopytov * Added Linux asynchronous I/O support to fileio test * Fixed bug with statistic counters 2004-04-01 Alexey Kopytov * Added test file creation to fileio test * Added read-only mode to OLTP test 2004-03-31 Alexey Kopytov * Close database connections in OLTP test * Added file-fsync-all mode for fileio test 2004-03-30 Alexey Kopytov * Added myisam-max-rows option for MySQL driver * Fixed configure.ac for cases when no MySQL libraries found 2004-03-10 Alexey Kopytov * Implement proper handling of table locks in OLTP test 2004-03-09 Alexey Kopytov * Recognize MySQL table type when creating test database * Fix driver-specific options * Now it's possible to pass MySQL root directory in --with-mysql option * Trim trailing '.libs' if user passed it in --with-mysql-libs option to configure 2004-03-08 Alexey Kopytov * Build drivers and tests as separate libraries (first step to dynamically loaded modules) * Display help when required arguments are missing in fileio test * Changed code formatting to match MySQL coding guidelines 2004-03-04 Alexey Kopytov * Generalized DB-dependent code * Added 'database capabilities' feature 2004-02-28 Alexey Kopytov * Fixed possible memory leak in sql request generator 2004-03-27 Alexey Kopytov * Split OLTP code into DB-independent part and MySQL driver 2004-02-23 Alexey Kopytov * Use libtool for linking with external libraries * Statically link external libraries when they are not installed 2004-02-19 Alexey Kopytov * Print more info when configure finds no MySQL development files * Added --with-mysql-includes and --with-mysql-libs to configure * Fixed compilation error when compiling without MySQL support * Combine several inserts into one query to speed up database creation ================================================ FILE: Dockerfile ================================================ FROM ubuntu:xenial RUN apt-get update RUN apt-get -y install make automake libtool pkg-config libaio-dev git # For MySQL support RUN apt-get -y install libmysqlclient-dev libssl-dev # For PostgreSQL support RUN apt-get -y install libpq-dev RUN git clone https://github.com/akopytov/sysbench.git sysbench WORKDIR sysbench RUN ./autogen.sh RUN ./configure --with-mysql --with-pgsql RUN make -j RUN make install WORKDIR /root RUN rm -rf sysbench ENTRYPOINT sysbench ================================================ FILE: Makefile.am ================================================ # Copyright (C) 2004 MySQL AB # Copyright (C) 2004-2018 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ACLOCAL_AMFLAGS = -I m4 AM_DISTCHECK_CONFIGURE_FLAGS = --without-mysql if USE_BUNDLED_LUAJIT LUAJIT_DIR = third_party/luajit endif if USE_BUNDLED_CK CK_DIR = third_party/concurrency_kit endif SUBDIRS = $(LUAJIT_DIR) $(CK_DIR) src tests EXTRA_DIST = autogen.sh README.md ChangeLog \ snap/snapcraft.yaml.in third_party/cram \ debian/changelog debian/compat debian/control debian/copyright \ debian/dirs debian/docs debian/install debian/rules \ debian/source/format \ rpm/sysbench.spec \ scripts/buildpack.sh dist-hook: $(MAKE) -C $(distdir)/third_party/cram clean test: cd tests && $(MAKE) test clean-local: $(MAKE) -C $(top_srcdir)/third_party/cram clean ================================================ FILE: README.md ================================================ [![Latest Release][release-badge]][release-url] [![Build Status][action-badge]][action-url] [![Debian Packages][deb-badge]][deb-url] [![RPM Packages][rpm-badge]][rpm-url] [![Coverage Status][coveralls-badge]][coveralls-url] [![License][license-badge]][license-url] **Table of Contents** - [sysbench](#sysbench) - [Features](#features) - [Installing from Binary Packages](#installing-from-binary-packages) - [Linux](#linux) - [macOS](#macos) - [Windows](#windows) - [Building and Installing From Source](#building-and-installing-from-source) - [Build Requirements](#build-requirements) - [Windows](#windows) - [Debian/Ubuntu](#debianubuntu) - [RHEL/CentOS](#rhelcentos) - [Fedora](#fedora) - [macOS](#macos) - [Build and Install](#build-and-install) - [Usage](#usage) - [General Syntax](#general-syntax) - [General Command Line Options](#general-command-line-options) - [Random Numbers Options](#random-numbers-options) - [Versioning](#versioning) # sysbench sysbench is a scriptable multi-threaded benchmark tool based on LuaJIT. It is most frequently used for database benchmarks, but can also be used to create arbitrarily complex workloads that do not involve a database server. sysbench comes with the following bundled benchmarks: - `oltp_*.lua`: a collection of OLTP-like database benchmarks - `fileio`: a filesystem-level benchmark - `cpu`: a simple CPU benchmark - `memory`: a memory access benchmark - `threads`: a thread-based scheduler benchmark - `mutex`: a POSIX mutex benchmark ## Features - extensive statistics about rate and latency is available, including latency percentiles and histograms; - low overhead even with thousands of concurrent threads. sysbench is capable of generating and tracking hundreds of millions of events per second; - new benchmarks can be easily created by implementing pre-defined hooks in user-provided Lua scripts; - can be used as a general-purpose Lua interpreter as well, simply replace `#!/usr/bin/lua` with `#!/usr/bin/sysbench` in your script. # Installing from Binary Packages ## Linux The easiest way to download and install sysbench on Linux is using binary package repositories hosted by [packagecloud](https://packagecloud.io). The repositories are automatically updated on each sysbench release. Currently x86_64, i386 and aarch64 binaries are available. Multiple methods to download and install sysbench packages are available and described at . Quick install instructions: - Debian/Ubuntu ``` shell curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.deb.sh | sudo bash sudo apt -y install sysbench ``` - RHEL/CentOS: ``` shell curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash sudo yum -y install sysbench ``` - Fedora: ``` shell curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash sudo dnf -y install sysbench ``` - Arch Linux: ``` shell sudo pacman -Suy sysbench ``` ## macOS On macOS, up-to-date sysbench packages are available from Homebrew: ```shell # Add --with-postgresql if you need PostgreSQL support brew install sysbench ``` ## Windows As of sysbench 1.0 support for native Windows builds was dropped. It may be re-introduced in later releases. Currently, the recommended way to obtain sysbench on Windows is using [Windows Subsystem for Linux available in Windows 10](https://msdn.microsoft.com/en-us/commandline/wsl/about). After installing WSL and getting into he bash prompt on Windows following Debian/Ubuntu installation instructions is sufficient. Alternatively, one can use WSL to build and install sysbench from source, or use an older sysbench release to build a native binary. # Building and Installing From Source It is recommended to install sysbench from the official binary packages as described in [Installing from Binary Packages](#installing-from-binary-packages). Below are instruction for cases when you want to use sysbench on an architecture for which no binary packages are available. ## Build Requirements ### Windows As of sysbench 1.0 support for native Windows builds was dropped. It may be re-introduced in later versions. Currently, the recommended way to build sysbench on Windows is using [Windows Subsystem for Linux available in Windows 10](https://msdn.microsoft.com/en-us/commandline/wsl/about). After installing WSL and getting into bash prompt on Windows, following Debian/Ubuntu build instructions is sufficient. Alternatively, one can build and use an older 0.5 release on Windows. ### Debian/Ubuntu ``` shell apt -y install make automake libtool pkg-config libaio-dev # For MySQL support apt -y install libmysqlclient-dev libssl-dev # For PostgreSQL support apt -y install libpq-dev ``` ### RHEL/CentOS ``` shell yum -y install make automake libtool pkgconfig libaio-devel # For MySQL support, replace with mysql-devel on RHEL/CentOS 5 yum -y install mariadb-devel openssl-devel # For PostgreSQL support yum -y install postgresql-devel ``` ### Fedora ``` shell dnf -y install make automake libtool pkgconfig libaio-devel # For MySQL support dnf -y install mariadb-devel openssl-devel # For PostgreSQL support dnf -y install postgresql-devel ``` ### macOS Assuming you have Xcode (or Xcode Command Line Tools) and Homebrew installed: ``` shell brew install automake libtool openssl pkg-config # For MySQL support brew install mysql # For PostgreSQL support brew install postgresql # openssl is not linked by Homebrew, this is to avoid "ld: library not found for -lssl" export LDFLAGS=-L/usr/local/opt/openssl/lib ``` ## Build and Install ``` shell ./autogen.sh # Add --with-pgsql to build with PostgreSQL support ./configure make -j make install ``` The above will build sysbench with MySQL support by default. If you have MySQL headers and libraries in non-standard locations (and no `mysql_config` can be found in the `PATH`), you can specify them explicitly with `--with-mysql-includes` and `--with-mysql-libs` options to `./configure`. To compile sysbench without MySQL support, use `--without-mysql`. If no database drivers are available database-related scripts will not work, but other benchmarks will be functional. # Usage ## General Syntax The general command line syntax for sysbench is: sysbench [options]... [testname] [command] - *testname* is an optional name of a built-in test (e.g. `fileio`, `memory`, `cpu`, etc.), or a name of one of the bundled Lua scripts (e.g. `oltp_read_only`), or a *path* to a custom Lua script. If no test name is specified on the command line (and thus, there is no *command* too, as in that case it would be parsed as a *testname*), or the test name is a dash ("`-`"), then sysbench expects a Lua script to execute on its standard input. - *command* is an optional argument that will be passed by sysbench to the built-in test or script specified with *testname*. *command* defines the *action* that must be performed by the test. The list of available commands depends on a particular test. Some tests also implement their own custom commands. Below is a description of typical test commands and their purpose: + `prepare`: performs preparative actions for those tests which need them, e.g. creating the necessary files on disk for the `fileio` test, or filling the test database for database benchmarks. + `run`: runs the actual test specified with the *testname* argument. This command is provided by all tests. + `cleanup`: removes temporary data after the test run in those tests which create one. + `help`: displays usage information for the test specified with the *testname* argument. This includes the full list of commands provided by the test, so it should be used to get the available commands. - *options* is a list of zero or more command line options starting with `'--'`. As with commands, the `sysbench testname help` command should be used to describe available options provided by a particular test. See [General command line options](README.md#general-command-line-options) for a description of general options provided by sysbench itself. You can use `sysbench --help` to display the general command line syntax and options. ## General Command Line Options The table below lists the supported common options, their descriptions and default values: *Option* | *Description* | *Default value* ----------------------|---------------|---------------- | `--threads` | The total number of worker threads to create | 1 | | `--events` | Limit for total number of requests. 0 (the default) means no limit | 0 | | `--time` | Limit for total execution time in seconds. 0 means no limit | 10 | | `--warmup-time` | Execute events for this many seconds with statistics disabled before the actual benchmark run with statistics enabled. This is useful when you want to exclude the initial period of a benchmark run from statistics. In many benchmarks, the initial period is not representative because CPU/database/page and other caches need some time to warm up | 0 | | `--rate` | Average transactions rate. The number specifies how many events (transactions) per seconds should be executed by all threads on average. 0 (default) means unlimited rate, i.e. events are executed as fast as possible | 0 | | `--thread-init-timeout` | Wait time in seconds for worker threads to initialize | 30 | | `--thread-stack-size` | Size of stack for each thread | 32K | | `--report-interval` | Periodically report intermediate statistics with a specified interval in seconds. Note that statistics produced by this option is per-interval rather than cumulative. 0 disables intermediate reports | 0 | | `--debug` | Print more debug info | off | | `--validate` | Perform validation of test results where possible | off | | `--help` | Print help on general syntax or on a specified test, and exit | off | | `--verbosity` | Verbosity level (0 - only critical messages, 5 - debug) | 4 | | `--percentile` | sysbench measures execution times for all processed requests to display statistical information like minimal, average and maximum execution time. For most benchmarks it is also useful to know a request execution time value matching some percentile (e.g. 95% percentile means we should drop 5% of the most long requests and choose the maximal value from the remaining ones). This option allows to specify a percentile rank of query execution times to count | 95 | | `--luajit-cmd` | perform a LuaJIT control command. This option is equivalent to `luajit -j`. See [LuaJIT documentation](http://luajit.org/running.html#opt_j) for more information | | Note that numerical values for all *size* options (like `--thread-stack-size` in this table) may be specified by appending the corresponding multiplicative suffix (K for kilobytes, M for megabytes, G for gigabytes and T for terabytes). ## Random Numbers Options sysbench provides a number of algorithms to generate random numbers that are distributed according to a given probability distribution. The table below lists options that can be used to control those algorithms. *Option* | *Description* | *Default value* ----------------------|---------------|---------------- `--rand-type` | random numbers distribution {uniform, gaussian, special, pareto, zipfian} to use by default. Benchmark scripts may choose to use either the default distribution, or specify it explictly, i.e. override the default. | special `--rand-seed` | seed for random number generator. When 0, the current time is used as an RNG seed. | 0 `--rand-spec-iter` | number of iterations for the special distribution | 12 `--rand-spec-pct` | percentage of the entire range where 'special' values will fall in the special distribution | 1 `--rand-spec-res` | percentage of 'special' values to use for the special distribution | 75 `--rand-pareto-h` | shape parameter for the Pareto distribution | 0.2 `--rand-zipfian-exp` | shape parameter (theta) for the Zipfian distribution | 0.8 # Versioning For transparency and insight into its release cycle, and for striving to maintain backward compatibility, sysbench will be maintained under the Semantic Versioning guidelines as much as possible. Releases will be numbered with the following format: `..` And constructed with the following guidelines: * Breaking backward compatibility bumps the major (and resets the minor and patch) * New additions without breaking backward compatibility bumps the minor (and resets the patch) * Bug fixes and misc changes bumps the patch For more information on SemVer, please visit [http://semver.org/](http://semver.org/). [coveralls-badge]: https://coveralls.io/repos/github/akopytov/sysbench/badge.svg?branch=master [coveralls-url]: https://coveralls.io/github/akopytov/sysbench?branch=master [action-url]: https://github.com/akopytov/sysbench/actions/workflows/ci.yml [action-badge]: https://github.com/akopytov/sysbench/actions/workflows/ci.yml/badge.svg [license-badge]: https://img.shields.io/badge/license-GPLv2-blue.svg [license-url]: COPYING [release-badge]: https://img.shields.io/github/release/akopytov/sysbench.svg [release-url]: https://github.com/akopytov/sysbench/releases/latest [deb-badge]: https://img.shields.io/badge/Packages-Debian-red.svg?style=flat [deb-url]: https://packagecloud.io/akopytov/sysbench?filter=debs [rpm-badge]: https://img.shields.io/badge/Packages-RPM-blue.svg?style=flat [rpm-url]: https://packagecloud.io/akopytov/sysbench?filter=rpms ================================================ FILE: autogen.sh ================================================ #!/bin/sh autoreconf -vi ================================================ FILE: config/config.rpath ================================================ #! /bin/sh # Output a system dependent set of variables, describing how to set the # run time search path of shared libraries in an executable. # # Copyright 1996-2007 Free Software Foundation, Inc. # Taken from GNU libtool, 2001 # Originally by Gordon Matzigkeit , 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # The first argument passed to this file is the canonical host specification, # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld # should be set by the caller. # # The set of defined variables is at the end of this script. # Known limitations: # - On IRIX 6.5 with CC="cc", the run time search patch must not be longer # than 256 bytes, otherwise the compiler driver will dump core. The only # known workaround is to choose shorter directory names for the build # directory and/or the installation directory. # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a shrext=.so host="$1" host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` # Code taken from libtool.m4's _LT_CC_BASENAME. for cc_temp in $CC""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` # Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC. wl= if test "$GCC" = yes; then wl='-Wl,' else case "$host_os" in aix*) wl='-Wl,' ;; darwin*) case $cc_basename in xlc*) wl='-Wl,' ;; esac ;; mingw* | cygwin* | pw32* | os2*) ;; hpux9* | hpux10* | hpux11*) wl='-Wl,' ;; irix5* | irix6* | nonstopux*) wl='-Wl,' ;; newsos6) ;; linux* | k*bsd*-gnu) case $cc_basename in icc* | ecc*) wl='-Wl,' ;; pgcc | pgf77 | pgf90) wl='-Wl,' ;; ccc*) wl='-Wl,' ;; como) wl='-lopt=' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) wl='-Wl,' ;; esac ;; esac ;; osf3* | osf4* | osf5*) wl='-Wl,' ;; rdos*) ;; solaris*) wl='-Wl,' ;; sunos4*) wl='-Qoption ld ' ;; sysv4 | sysv4.2uw2* | sysv4.3*) wl='-Wl,' ;; sysv4*MP*) ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) wl='-Wl,' ;; unicos*) wl='-Wl,' ;; uts4*) ;; esac fi # Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS. hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no case "$host_os" in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. # Unlike libtool, we use -rpath here, not --rpath, since the documented # option of GNU ld is called -rpath, not --rpath. hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' case "$host_os" in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we cannot use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; cygwin* | mingw* | pw32*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then : else ld_shlibs=no fi ;; interix[3-9]*) hardcode_direct=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; gnu* | linux* | k*bsd*-gnu) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; netbsd*) ;; solaris*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs=no elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' else ld_shlibs=no fi ;; esac ;; sunos4*) hardcode_direct=yes ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then hardcode_libdir_flag_spec= fi else case "$host_os" in aix3*) # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac fi hardcode_direct=yes hardcode_libdir_separator=':' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac fi # Begin _LT_AC_SYS_LIBPATH_AIX. echo 'int main () { return 0; }' > conftest.c ${CC} ${LDFLAGS} conftest.c -o conftest aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` fi if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib" fi rm -f conftest.c conftest # End _LT_AC_SYS_LIBPATH_AIX. if test "$aix_use_runtimelinking" = yes; then hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' else hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" fi fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; bsdi[45]*) ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' libext=lib ;; darwin* | rhapsody*) hardcode_direct=no if test "$GCC" = yes ; then : else case $cc_basename in xlc*) ;; *) ld_shlibs=no ;; esac fi ;; dgux*) hardcode_libdir_flag_spec='-L$libdir' ;; freebsd1*) ld_shlibs=no ;; freebsd2.2*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; freebsd2*) hardcode_direct=yes hardcode_minus_L=yes ;; freebsd* | dragonfly*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; hpux9*) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; hpux10*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no ;; *) hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; netbsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; newsos6) hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then hardcode_libdir_flag_spec='${wl}-rpath,$libdir' else case "$host_os" in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) hardcode_libdir_flag_spec='-R$libdir' ;; *) hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; osf3*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) if test "$GCC" = yes; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else # Both cc and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; solaris*) hardcode_libdir_flag_spec='-R$libdir' ;; sunos4*) hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes ;; sysv4) case $host_vendor in sni) hardcode_direct=yes # is this really true??? ;; siemens) hardcode_direct=no ;; motorola) hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac ;; sysv4.3*) ;; sysv4*MP*) if test -d /usr/nec; then ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) ;; sysv5* | sco3.2v5* | sco5v6*) hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' hardcode_libdir_separator=':' ;; uts4*) hardcode_libdir_flag_spec='-L$libdir' ;; *) ld_shlibs=no ;; esac fi # Check dynamic linker characteristics # Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER. # Unlike libtool.m4, here we don't care about _all_ names of the library, but # only about the one the linker finds when passed -lNAME. This is the last # element of library_names_spec in libtool.m4, or possibly two of them if the # linker has special search rules. library_names_spec= # the last element of library_names_spec in libtool.m4 libname_spec='lib$name' case "$host_os" in aix3*) library_names_spec='$libname.a' ;; aix4* | aix5*) library_names_spec='$libname$shrext' ;; amigaos*) library_names_spec='$libname.a' ;; beos*) library_names_spec='$libname$shrext' ;; bsdi[45]*) library_names_spec='$libname$shrext' ;; cygwin* | mingw* | pw32*) shrext=.dll library_names_spec='$libname.dll.a $libname.lib' ;; darwin* | rhapsody*) shrext=.dylib library_names_spec='$libname$shrext' ;; dgux*) library_names_spec='$libname$shrext' ;; freebsd1*) ;; freebsd* | dragonfly*) case "$host_os" in freebsd[123]*) library_names_spec='$libname$shrext$versuffix' ;; *) library_names_spec='$libname$shrext' ;; esac ;; gnu*) library_names_spec='$libname$shrext' ;; hpux9* | hpux10* | hpux11*) case $host_cpu in ia64*) shrext=.so ;; hppa*64*) shrext=.sl ;; *) shrext=.sl ;; esac library_names_spec='$libname$shrext' ;; interix[3-9]*) library_names_spec='$libname$shrext' ;; irix5* | irix6* | nonstopux*) library_names_spec='$libname$shrext' case "$host_os" in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; *) libsuff= shlibsuff= ;; esac ;; esac ;; linux*oldld* | linux*aout* | linux*coff*) ;; linux* | k*bsd*-gnu) library_names_spec='$libname$shrext' ;; knetbsd*-gnu) library_names_spec='$libname$shrext' ;; netbsd*) library_names_spec='$libname$shrext' ;; newsos6) library_names_spec='$libname$shrext' ;; nto-qnx*) library_names_spec='$libname$shrext' ;; openbsd*) library_names_spec='$libname$shrext$versuffix' ;; os2*) libname_spec='$name' shrext=.dll library_names_spec='$libname.a' ;; osf3* | osf4* | osf5*) library_names_spec='$libname$shrext' ;; rdos*) ;; solaris*) library_names_spec='$libname$shrext' ;; sunos4*) library_names_spec='$libname$shrext$versuffix' ;; sysv4 | sysv4.3*) library_names_spec='$libname$shrext' ;; sysv4*MP*) library_names_spec='$libname$shrext' ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) library_names_spec='$libname$shrext' ;; uts4*) library_names_spec='$libname$shrext' ;; esac sed_quote_subst='s/\(["`$\\]\)/\\\1/g' escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` shlibext=`echo "$shrext" | sed -e 's,^\.,,'` escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' < ] ) # Check if we should enable Linux AIO support AC_ARG_ENABLE(aio, AS_HELP_STRING([--enable-aio],[enable Linux asynchronous I/O support (default is enabled)]), , enable_aio=yes ) AC_CHECK_DECLS(O_SYNC, , AC_DEFINE([O_SYNC], [O_FSYNC], [Define to the appropriate value for O_SYNC on your platform]), [ #include ] ) # Checks for libraries. ACX_PTHREAD AC_CHECK_LIB(m, sqrt) SB_CHECK_MYSQL AS_IF([test x$with_pgsql != xno], [ AC_CHECK_PGSQL([$with_pgsql]) USE_PGSQL=1 AC_DEFINE(USE_PGSQL,1,[Define to 1 if you want to compile with PostgreSQL support]) AC_SUBST([PGSQL_LIBS]) AC_SUBST([PGSQL_CFLAGS]) ]) AM_CONDITIONAL(USE_PGSQL, test x$with_pgsql != xno) AC_SUBST([USE_PGSQL]) # Check for libaio AC_CHECK_AIO AM_CONDITIONAL(USE_AIO, test x$enable_aio = xyes) AC_CHECK_HEADERS([ \ errno.h \ fcntl.h \ math.h \ pthread.h \ sched.h \ signal.h \ stdlib.h \ string.h \ sys/aio.h \ sys/ipc.h \ sys/time.h \ sys/mman.h \ sys/shm.h \ thread.h \ unistd.h \ limits.h \ libgen.h \ ]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_OFF_T AX_TLS([], AC_MSG_ERROR([thread-local storage is not suppored by the target platform!]) ) # Define HAVE_FUNC_ATTRIBUTE_FORMAT if compiler supports the # __attribute__((format...)) function attribute AX_GCC_FUNC_ATTRIBUTE(format) # Define HAVE_FUNC_ATTRIBUTE_UNUSED if compiler supports the # __attribute__((unused)) function attribute AX_GCC_FUNC_ATTRIBUTE(unused) if test "$enable_largefile" = yes; then AC_SYS_LARGEFILE fi AC_CHECK_SIZEOF(size_t) AC_CHECK_SIZEOF(bool,, [ #include ]) # Checks for library functions. AC_FUNC_MMAP AC_FUNC_STRERROR_R AC_SEARCH_LIBS([clock_gettime], [rt]) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_CHECK_FUNCS([ \ alarm \ clock_gettime \ directio \ fdatasync \ gettimeofday \ isatty \ memalign \ memset \ posix_memalign \ pthread_cancel \ pthread_yield \ setvbuf \ sqrt \ strdup \ thr_setconcurrency \ valloc \ ]) AC_CHECK_FUNC(pthread_once, , AC_MSG_ERROR([*** pthread_once() is not available on this platform ***]) ) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_ARG_WITH([debug], [AS_HELP_STRING([--with-debug], [Add debug code/turns off optimizations (yes|no) @<:@default=no@:>@])], [with_debug=$withval], [with_debug=no]) AC_ARG_ENABLE([coverage], [AS_HELP_STRING([--enable-coverage], [Toggle coverage @<:@default=no@:>@])], [ac_coverage="$enableval"], [ac_coverage="no"]) AC_ARG_ENABLE([asan], [AS_HELP_STRING([--enable-asan], [Enable AddressSanitizer @<:@default=no@:>@])], [ac_asan="$enableval"], [ac_asan="no"]) AC_ARG_ENABLE([msan], [AS_HELP_STRING([--enable-msan], [Enable MemorySanitizer @<:@default=no@:>@])], [ac_msan="$enableval"], [ac_msan="no"]) AC_ARG_ENABLE([fail], [AS_HELP_STRING([--disable-fail], [Turn warnings into failures @<:@default=no@:>@])], [ac_warn_fail="$enableval"], [ac_warn_fail="no"]) if test "$with_debug" = "yes" then # Debugging. No optimization. CFLAGS="${DEBUG_CFLAGS} -DDEBUG ${CFLAGS}" elif test "$ac_coverage" = "yes" then # Gcov-enabled build. No optimization. CFLAGS="${GCOV_CFLAGS} ${CFLAGS}" LDFLAGS="${GCOV_LDFLAGS} ${LDFLAGS}" else # Optimized version. No debug CFLAGS="${OPTIMIZE_CFLAGS} ${CFLAGS}" fi if test "$ac_asan" = "yes" then # Add -fsanitize=address to CFLAGS/LDFLAGS if supported by the compiler AX_CHECK_COMPILE_FLAG([-fsanitize=address], [ CFLAGS="${ASAN_CFLAGS} ${CFLAGS}" LDFLAGS="${ASAN_LDFLAGS} ${LDFLAGS}" ]) fi if test "$ac_msan" = "yes" then # Add -fsanitize=memory to CFLAGS/LDFLAGS if supported by the compiler AX_CHECK_COMPILE_FLAG([-fsanitize=memory], [ CFLAGS="${MSAN_CFLAGS} ${CFLAGS}" LDFLAGS="${MSAN_CFLAGS} ${LDFLAGS}" ]) fi if test "$GCC" = "yes" then if test "$ac_warn_fail" = "yes" then W_FAIL="-Werror" fi CC_WARNINGS="-Wall -Wextra -Wpointer-arith -Wbad-function-cast \ -Wstrict-prototypes -Wnested-externs -Wno-format-zero-length \ -Wundef -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations \ -Wredundant-decls -Wcast-align -Wvla ${W_FAIL}" fi if test "$ax_cv_c_compiler_vendor" = "sun" then CC_WARNINGS="-v -errtags=yes -errwarn=%all -erroff=E_INTEGER_OVERFLOW_DETECTED -erroff=E_STATEMENT_NOT_REACHED" fi AM_CFLAGS="${CC_WARNINGS} ${AM_CFLAGS} ${PTHREAD_CFLAGS}" AM_CPPFLAGS="${AM_CPPFLAGS} -I\$(top_srcdir)/src ${LUAJIT_CFLAGS} ${CK_CFLAGS}" AM_LDFLAGS="$PTHREAD_LIBS" AC_SUBST(AM_CFLAGS) AC_SUBST(AM_CPPFLAGS) AC_SUBST(AM_LDFLAGS) # Define SB_GIT_SHA git=$(which git) if test -n "$git" then SB_GIT_SHA=$(git rev-parse --short HEAD 2>/dev/null) if test -n "$SB_GIT_SHA" then SB_GIT_SHA="-$SB_GIT_SHA" fi fi AC_DEFINE_UNQUOTED([SB_GIT_SHA], ["$SB_GIT_SHA"], [Git commit hash, if available.]) AC_SUBST([SB_GIT_SHA]) AC_CONFIG_FILES([ Makefile third_party/luajit/Makefile third_party/concurrency_kit/Makefile src/Makefile src/drivers/Makefile src/drivers/mysql/Makefile src/drivers/pgsql/Makefile src/tests/Makefile src/tests/cpu/Makefile src/tests/fileio/Makefile src/tests/memory/Makefile src/tests/threads/Makefile src/tests/mutex/Makefile src/lua/Makefile src/lua/internal/Makefile tests/Makefile tests/include/config.sh snap/snapcraft.yaml ]) AC_OUTPUT AC_MSG_RESULT([===============================================================================]) AC_MSG_RESULT([sysbench version : ${PACKAGE_VERSION}${SB_GIT_SHA}]) AC_MSG_RESULT([CC : ${CC}]) AC_MSG_RESULT([CFLAGS : ${CFLAGS} ${AM_CFLAGS}]) AC_MSG_RESULT([CPPFLAGS : ${CPPFLAGS} ${AM_CPPFLAGS}]) AC_MSG_RESULT([LDFLAGS : ${LDFLAGS} ${AM_LDFLAGS}]) AC_MSG_RESULT([LIBS : ${LIBS}]) AC_MSG_RESULT([]) AC_MSG_RESULT([prefix : $(eval echo ${prefix})]) AC_MSG_RESULT([bindir : $(eval echo ${bindir})]) AC_MSG_RESULT([libexecdir : $(eval echo ${libexecdir})]) AC_MSG_RESULT([mandir : $(eval echo ${mandir})]) AC_MSG_RESULT([datadir : $(eval echo ${datadir})]) AC_MSG_RESULT([]) AC_MSG_RESULT([MySQL support : ${mysql_support}]) AC_MSG_RESULT([PostgreSQL support : ${pgsql_support}]) AC_MSG_RESULT([]) AC_MSG_RESULT([LuaJIT : ${sb_use_luajit}]) AC_MSG_RESULT([LUAJIT_CFLAGS : ${LUAJIT_CFLAGS}]) AC_MSG_RESULT([LUAJIT_LIBS : ${LUAJIT_LIBS}]) AC_MSG_RESULT([LUAJIT_LDFLAGS : ${LUAJIT_LDFLAGS}]) AC_MSG_RESULT([]) AC_MSG_RESULT([Concurrency Kit : ${sb_use_ck}]) if test "$sb_use_ck" = bundled; then AC_MSG_RESULT([CK_CFLAGS : ${CK_CFLAGS}]) AC_MSG_RESULT([CK_LIBS : ${CK_LIBS}]) AC_MSG_RESULT([configure flags : ${CK_CONFIGURE_FLAGS}]) fi AC_MSG_RESULT([===============================================================================]) ================================================ FILE: debian/changelog ================================================ sysbench (1.0.21-1) unstable; urgency=low * add libzstd-dev to build dependencies -- Alexey Kopytov Sun, 24 Jan 2021 13:16:04 +0300 sysbench (1.0.18-1) unstable; urgency=low * add libssl-dev to build dependencies -- Alexey Kopytov Sun, 08 Dec 2019 14:02:01 +0300 sysbench (1.0.15-2) unstable; urgency=low * add libaio-dev to build dependencies -- Alexey Kopytov Sat, 09 Jul 2018 09:24:42 +0300 sysbench (1.0.12-1) unstable; urgency=low * remove vim-common from build dependencies -- Alexey Kopytov Sat, 06 Jan 2018 10:59:42 +0300 sysbench (1.0.11-1) unstable; urgency=low * add Debian Stretch support by adding optional build dependency on default-libmysqlclient-dev and replacing python-minimal with python (as minimal does not provide the shlex module required by cram) -- Alexey Kopytov Sat, 09 Dec 2017 19:52:23 +0300 sysbench (1.0.6-1) unstable; urgency=low * Add pkg-config, vim-common and python-minimal and libpq-dev to build dependencies. * Fix 'clean' target in rules. * Add ChangeLog and COPYING to docs. * Remove tests/db/*.lua from install. * Pass --without-gcc-arch to configure to not override compiler flags passed by the build system -- Alexey Kopytov Thu, 13 Apr 2017 23:04:34 +0300 sysbench (1.0-1) unstable; urgency=low * Initial release -- Alexey Kopytov Wed, 10 Aug 2016 18:04:53 +0300 ================================================ FILE: debian/compat ================================================ 7 ================================================ FILE: debian/control ================================================ Source: sysbench Section: misc Priority: extra Maintainer: Alexey Kopytov Build-Depends: debhelper, autoconf, automake, libaio-dev, libtool, libmysqlclient-dev | default-libmysqlclient-dev, libpq-dev, pkg-config, python, libssl-dev, libzstd-dev Standards-Version: 3.9.5 Homepage: https://github.com/akopytov/sysbench Package: sysbench Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Scriptable database and system performance benchmark sysbench is a scriptable multi-threaded benchmark tool based on LuaJIT. It is most frequently used for database benchmarks, but can also be used to create arbitrarily complex workloads that do not involve a database server. . sysbench comes with the following bundled benchmarks: . - oltp_*.lua: a collection of OLTP-like database benchmarks - fileio: a filesystem-level benchmark - cpu: a simple CPU benchmark - memory: a memory access benchmark - threads: a thread-based scheduler benchmark - mutex: a POSIX mutex benchmark ================================================ FILE: debian/copyright ================================================ Format-Specification: http://wiki.debian.org/Proposals/CopyrightFormat Upstream-Name: sysbench Upstream-Maintainer: Alexey Kopytov Upstream-Source: https://github.com/akopytov/sysbench Files: * Copyright: 2016 Alexey Kopytov License: GPL-2 This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. . On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL-2'. ================================================ FILE: debian/dirs ================================================ usr/bin ================================================ FILE: debian/docs ================================================ README.md ChangeLog COPYING ================================================ FILE: debian/install ================================================ ================================================ FILE: debian/rules ================================================ #!/usr/bin/make -f %: dh $@ override_dh_auto_configure: dh_testdir autoreconf -vif dh_auto_configure -- --with-mysql --with-pgsql --without-gcc-arch override_dh_compress: dh_compress -X.lua ================================================ FILE: debian/source/format ================================================ 3.0 (quilt) ================================================ FILE: install-sh ================================================ #!/bin/sh # # install - install a program, script, or datafile # # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd=$cpprog shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "$0: no input file specified" >&2 exit 1 else : fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d "$dst" ]; then instcmd=: chmodcmd="" else instcmd=$mkdirprog fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f "$src" ] || [ -d "$src" ] then : else echo "$0: $src does not exist" >&2 exit 1 fi if [ x"$dst" = x ] then echo "$0: no destination specified" >&2 exit 1 else : fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d "$dst" ] then dst=$dst/`basename "$src"` else : fi fi ## this sed command emulates the dirname command dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` IFS=$oIFS pathcomp='' while [ $# -ne 0 ] ; do pathcomp=$pathcomp$1 shift if [ ! -d "$pathcomp" ] ; then $mkdirprog "$pathcomp" else : fi pathcomp=$pathcomp/ done fi if [ x"$dir_arg" != x ] then $doit $instcmd "$dst" && if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename "$dst"` else dstfile=`basename "$dst" $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename "$dst"` else : fi # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up temp files at exit. trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 trap '(exit $?); exit' 1 2 13 15 # Move or copy the file name to the temp name $doit $instcmd "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi && # Now remove or move aside any old file at destination location. We try this # two ways since rm can't unlink itself on some systems and the destination # file might be busy for other reasons. In this case, the final cleanup # might fail but the new file should still install successfully. { if [ -f "$dstdir/$dstfile" ] then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" fi && # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit } ================================================ FILE: m4/ac_check_aio.m4 ================================================ dnl --------------------------------------------------------------------------- dnl Macro: AC_CHECK_AIO dnl Check for Linux AIO availability on the target system dnl Also, check the version of libaio library (at the moment, there are two dnl versions with incompatible interfaces). dnl --------------------------------------------------------------------------- AC_DEFUN([AC_CHECK_AIO],[ if test x$enable_aio = xyes; then AC_CHECK_HEADER([libaio.h], [AC_DEFINE(HAVE_LIBAIO_H,1,[Define to 1 if your system has header file])], [enable_aio=no]) fi if test x$enable_aio = xyes; then AC_CHECK_LIB([aio], [io_queue_init], , [enable_aio=no]) fi if test x$enable_aio = xyes; then AC_MSG_CHECKING(if io_getevents() has an old interface) AC_COMPILE_IFELSE([AC_LANG_PROGRAM( [[ #ifdef HAVE_LIBAIO_H # include #endif struct io_event event; io_context_t ctxt; ]], [[ (void)io_getevents(ctxt, 1, &event, NULL); ]] ) ], [ AC_DEFINE([HAVE_OLD_GETEVENTS], 1, [Define to 1 if libaio has older getevents() interface]) AC_MSG_RESULT(yes) ], [AC_MSG_RESULT(no)] ) fi ]) ================================================ FILE: m4/ac_check_pgsql.m4 ================================================ dnl --------------------------------------------------------------------------- dnl Macro: AC_CHECK_PGSQL dnl First check for custom PostgreSQL paths in --with-pgsql-* options. dnl If some paths are missing, check if pg_config exists. dnl --------------------------------------------------------------------------- AC_DEFUN([AC_CHECK_PGSQL],[ # Check for custom includes path if test [ -z "$ac_cv_pgsql_includes" ] then AC_ARG_WITH([pgsql-includes], AS_HELP_STRING([--with-pgsql-includes], [path to PostgreSQL header files]), [ac_cv_pgsql_includes=$withval]) fi if test [ -n "$ac_cv_pgsql_includes" ] then AC_CACHE_CHECK([PostgreSQL includes], [ac_cv_pgsql_includes], [ac_cv_pgsql_includes=""]) PGSQL_CFLAGS="-I$ac_cv_pgsql_includes" fi # Check for custom library path if test [ -z "$ac_cv_pgsql_libs" ] then AC_ARG_WITH([pgsql-libs], AS_HELP_STRING([--with-pgsql-libs], [path to PostgreSQL libraries]), [ac_cv_pgsql_libs=$withval]) fi if test [ -n "$ac_cv_pgsql_libs" ] then AC_CACHE_CHECK([PostgreSQL libraries], [ac_cv_pgsql_libs], [ac_cv_pgsql_libs=""]) PGSQL_LIBS="-L$ac_cv_pgsql_libs -lpq" fi # If some path is missing, try to autodetermine with pgsql_config if test [ -z "$ac_cv_pgsql_includes" -o -z "$ac_cv_pgsql_libs" ] then if test [ -z "$pgconfig" ] then AC_PATH_PROG(pgconfig,pg_config) fi if test [ -z "$pgconfig" ] then AC_MSG_ERROR([pg_config executable not found ******************************************************************************** ERROR: cannot find PostgreSQL libraries. If you want to compile with PosgregSQL support, you must either specify file locations explicitly using --with-pgsql-includes and --with-pgsql-libs options, or make sure path to pg_config is listed in your PATH environment variable. If you want to disable PostgreSQL support, use --without-pgsql option. ******************************************************************************** ]) else if test [ -z "$ac_cv_pgsql_includes" ] then AC_MSG_CHECKING(PostgreSQL C flags) PGSQL_CFLAGS="-I`${pgconfig} --includedir`" AC_MSG_RESULT($PGSQL_CFLAGS) fi if test [ -z "$ac_cv_pgsql_libs" ] then AC_MSG_CHECKING(PostgreSQL linker flags) PGSQL_LIBS="-L`${pgconfig} --libdir` -lpq" AC_MSG_RESULT($PGSQL_LIBS) fi fi fi ]) ================================================ FILE: m4/acx_pthread.m4 ================================================ ##### http://autoconf-archive.cryp.to/acx_pthread.html # # SYNOPSIS # # ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. # It sets the PTHREAD_LIBS output variable to the threads library and # linker flags, and the PTHREAD_CFLAGS output variable to any special # C compiler flags that are needed. (The user can also force certain # compiler flags/libs to be tested by setting these environment # variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). # (This is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these # flags, but also link it with them as well. e.g. you should link # with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS # $LIBS # # If you are only building threads programs, you may wish to use # these variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute # constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to # that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # ACTION-IF-FOUND is a list of shell commands to run if a threads # library is found, and ACTION-IF-NOT-FOUND is a list of commands to # run it if it is not found. If ACTION-IF-FOUND is not specified, the # default action will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or # if you have any other suggestions or comments. This macro was based # on work by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) # (with help from M. Frigo), as well as ac_pthread and hb_pthread # macros posted by Alejandro Forero Cuervo to the autoconf macro # repository. We are also grateful for the helpful feedback of # numerous users. # # LAST MODIFICATION # # 2006-05-29 # # COPYLEFT # # Copyright (c) 2006 Steven G. Johnson # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # As a special exception, the respective Autoconf Macro's copyright # owner gives unlimited permission to copy, distribute and modify the # configure scripts that are the output of Autoconf when processing # the Macro. You need not follow the terms of the GNU General Public # License when using or distributing such scripts, even though # portions of the text of the Macro appear in them. The GNU General # Public License (GPL) does govern all other use of the material that # constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the # Autoconf Macro released by the Autoconf Macro Archive. When you # make and distribute a modified version of the Autoconf Macro, you # may extend this special exception to the GPL to apply to your # modified version as well. AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ]])],[acx_pthread_ok=yes],[]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int attr=$attr; return attr;]])],[attr_name=$attr; break],[]) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_POP([]) ])dnl ACX_PTHREAD ================================================ FILE: m4/ax_check_compile_flag.m4 ================================================ # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 5 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [ AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS ================================================ FILE: m4/ax_compiler_vendor.m4 ================================================ # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html # =========================================================================== # # SYNOPSIS # # AX_COMPILER_VENDOR # # DESCRIPTION # # Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun, # hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft, # watcom, etc. The vendor is returned in the cache variable # $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2008 Matteo Frigo # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 16 AC_DEFUN([AX_COMPILER_VENDOR], [AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, dnl Please add if possible support to ax_compiler_version.m4 [# note: don't check for gcc first since some other compilers define __GNUC__ vendors="intel: __ICC,__ECC,__INTEL_COMPILER ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__ pathscale: __PATHCC__,__PATHSCALE__ clang: __clang__ cray: _CRAYC fujitsu: __FUJITSU gnu: __GNUC__ sun: __SUNPRO_C,__SUNPRO_CC hp: __HP_cc,__HP_aCC dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland: __BORLANDC__,__CODEGEARC__,__TURBOC__ comeau: __COMO__ kai: __KCC lcc: __LCC__ sgi: __sgi,sgi microsoft: _MSC_VER metrowerks: __MWERKS__ watcom: __WATCOMC__ portland: __PGI tcc: __TINYC__ unknown: UNKNOWN" for ventest in $vendors; do case $ventest in *:) vendor=$ventest; continue ;; *) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;; esac AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ #if !($vencpp) thisisanerror; #endif ])], [break]) done ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1` ]) ]) ================================================ FILE: m4/ax_gcc_archflag.m4 ================================================ # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_gcc_archflag.html # =========================================================================== # # SYNOPSIS # # AX_GCC_ARCHFLAG([PORTABLE?], [ACTION-SUCCESS], [ACTION-FAILURE]) # # DESCRIPTION # # This macro tries to guess the "native" arch corresponding to the target # architecture for use with gcc's -march=arch or -mtune=arch flags. If # found, the cache variable $ax_cv_gcc_archflag is set to this flag and # ACTION-SUCCESS is executed; otherwise $ax_cv_gcc_archflag is set to # "unknown" and ACTION-FAILURE is executed. The default ACTION-SUCCESS is # to add $ax_cv_gcc_archflag to the end of $CFLAGS. # # PORTABLE? should be either [yes] (default) or [no]. In the former case, # the flag is set to -mtune (or equivalent) so that the architecture is # only used for tuning, but the instruction set used is still portable. In # the latter case, the flag is set to -march (or equivalent) so that # architecture-specific instructions are enabled. # # The user can specify --with-gcc-arch= in order to override the # macro's choice of architecture, or --without-gcc-arch to disable this. # # When cross-compiling, or if $CC is not gcc, then ACTION-FAILURE is # called unless the user specified --with-gcc-arch manually. # # Requires macros: AX_CHECK_COMPILE_FLAG, AX_GCC_X86_CPUID # # (The main emphasis here is on recent CPUs, on the principle that doing # high-performance computing on old hardware is uncommon.) # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2008 Matteo Frigo # Copyright (c) 2014 Tsukasa Oi # Copyright (c) 2017-2018 Alexey Kopytov # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 21 AC_DEFUN([AX_GCC_ARCHFLAG], [AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_PROG_SED]) AC_REQUIRE([AX_COMPILER_VENDOR]) AC_ARG_WITH(gcc-arch, [AS_HELP_STRING([--with-gcc-arch=], [use architecture for gcc -march/-mtune, instead of guessing])], ax_gcc_arch=$withval, ax_gcc_arch=yes) AC_MSG_CHECKING([for gcc architecture flag]) AC_MSG_RESULT([]) AC_CACHE_VAL(ax_cv_gcc_archflag, [ ax_cv_gcc_archflag="unknown" if test "$GCC" = yes; then if test "x$ax_gcc_arch" = xyes; then ax_gcc_arch="" if test "$cross_compiling" = no; then case $host_cpu in i[[3456]]86*|x86_64*|amd64*) # use cpuid codes AX_GCC_X86_CPUID(0) AX_GCC_X86_CPUID(1) case $ax_cv_gcc_x86_cpuid_0 in *:756e6547:6c65746e:49656e69) # Intel case $ax_cv_gcc_x86_cpuid_1 in *5[[4578]]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;; *5[[123]]?:*:*:*) ax_gcc_arch=pentium ;; *0?61?:*:*:*|?61?:*:*:*|61?:*:*:*) ax_gcc_arch=pentiumpro ;; *0?6[[356]]?:*:*:*|?6[[356]]?:*:*:*|6[[356]]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; *0?6[[78ab]]?:*:*:*|?6[[78ab]]?:*:*:*|6[[78ab]]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; *0?6[[9d]]?:*:*:*|?6[[9d]]?:*:*:*|6[[9d]]?:*:*:*|*1?65?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;; *0?6e?:*:*:*|?6e?:*:*:*|6e?:*:*:*) ax_gcc_arch="yonah pentium-m pentium3 pentiumpro" ;; *0?6f?:*:*:*|?6f?:*:*:*|6f?:*:*:*|*1?66?:*:*:*) ax_gcc_arch="core2 pentium-m pentium3 pentiumpro" ;; *1?6[[7d]]?:*:*:*) ax_gcc_arch="penryn core2 pentium-m pentium3 pentiumpro" ;; *1?6[[aef]]?:*:*:*|*2?6e?:*:*:*) ax_gcc_arch="nehalem corei7 core2 pentium-m pentium3 pentiumpro" ;; *2?6[[5cf]]?:*:*:*) ax_gcc_arch="westmere corei7 core2 pentium-m pentium3 pentiumpro" ;; *2?6[[ad]]?:*:*:*) ax_gcc_arch="sandybridge corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; *3?6[[ae]]?:*:*:*) ax_gcc_arch="ivybridge core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; *3?6[[cf]]?:*:*:*|*4?6[[56]]?:*:*:*) ax_gcc_arch="haswell core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; *3?6d?:*:*:*|*4?6[[7f]]?:*:*:*|*5?66?:*:*:*) ax_gcc_arch="broadwell core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; *1?6c?:*:*:*|*2?6[[67]]?:*:*:*|*3?6[[56]]?:*:*:*) ax_gcc_arch="bonnell atom core2 pentium-m pentium3 pentiumpro" ;; *3?67?:*:*:*|*[[45]]?6[[ad]]?:*:*:*) ax_gcc_arch="silvermont atom core2 pentium-m pentium3 pentiumpro" ;; *000?f[[012]]?:*:*:*|?f[[012]]?:*:*:*|f[[012]]?:*:*:*) ax_gcc_arch="pentium4 pentiumpro" ;; *000?f[[346]]?:*:*:*|?f[[346]]?:*:*:*|f[[346]]?:*:*:*) ax_gcc_arch="nocona prescott pentium4 pentiumpro" ;; # fallback *5??:*:*:*) ax_gcc_arch=pentium ;; *??6??:*:*:*) ax_gcc_arch="core2 pentiumpro" ;; *6??:*:*:*) ax_gcc_arch=pentiumpro ;; *00??f??:*:*:*|??f??:*:*:*|?f??:*:*:*|f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro" ;; esac ;; *:68747541:444d4163:69746e65) # AMD case $ax_cv_gcc_x86_cpuid_1 in *5[[67]]?:*:*:*) ax_gcc_arch=k6 ;; *5[[8]]?:*:*:*) ax_gcc_arch="k6-2 k6" ;; *5[[9d]]?:*:*:*) ax_gcc_arch="k6-3 k6" ;; *6[[12]]?:*:*:*) ax_gcc_arch="athlon k7" ;; *6[[34]]?:*:*:*) ax_gcc_arch="athlon-tbird k7" ;; *6[[678a]]?:*:*:*) ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;; *000?f[[4578bcef]]?:*:*:*|?f[[4578bcef]]?:*:*:*|f[[4578bcef]]?:*:*:*|*001?f[[4578bcf]]?:*:*:*|1?f[[4578bcf]]?:*:*:*) ax_gcc_arch="athlon64 k8" ;; *002?f[[13457bcf]]?:*:*:*|2?f[[13457bcf]]?:*:*:*|*004?f[[138bcf]]?:*:*:*|4?f[[138bcf]]?:*:*:*|*005?f[[df]]?:*:*:*|5?f[[df]]?:*:*:*|*006?f[[8bcf]]?:*:*:*|6?f[[8bcf]]?:*:*:*|*007?f[[cf]]?:*:*:*|7?f[[cf]]?:*:*:*|*00c?f1?:*:*:*|c?f1?:*:*:*|*020?f3?:*:*:*|20?f3?:*:*:*) ax_gcc_arch="athlon64-sse3 k8-sse3 athlon64 k8" ;; *010?f[[245689a]]?:*:*:*|10?f[[245689a]]?:*:*:*|*030?f1?:*:*:*|30?f1?:*:*:*) ax_gcc_arch="barcelona amdfam10 k8" ;; *050?f[[12]]?:*:*:*|50?f[[12]]?:*:*:*) ax_gcc_arch="btver1 amdfam10 k8" ;; *060?f1?:*:*:*|60?f1?:*:*:*) ax_gcc_arch="bdver1 amdfam10 k8" ;; *060?f2?:*:*:*|60?f2?:*:*:*|*061?f[[03]]?:*:*:*|61?f[[03]]?:*:*:*) ax_gcc_arch="bdver2 bdver1 amdfam10 k8" ;; *063?f0?:*:*:*|63?f0?:*:*:*) ax_gcc_arch="bdver3 bdver2 bdver1 amdfam10 k8" ;; *07[[03]]?f0?:*:*:*|7[[03]]?f0?:*:*:*) ax_gcc_arch="btver2 btver1 amdfam10 k8" ;; # fallback *0[[13]]??f??:*:*:*|[[13]]??f??:*:*:*) ax_gcc_arch="barcelona amdfam10 k8" ;; *020?f??:*:*:*|20?f??:*:*:*) ax_gcc_arch="athlon64-sse3 k8-sse3 athlon64 k8" ;; *05??f??:*:*:*|5??f??:*:*:*) ax_gcc_arch="btver1 amdfam10 k8" ;; *060?f??:*:*:*|60?f??:*:*:*) ax_gcc_arch="bdver1 amdfam10 k8" ;; *061?f??:*:*:*|61?f??:*:*:*) ax_gcc_arch="bdver2 bdver1 amdfam10 k8" ;; *06??f??:*:*:*|6??f??:*:*:*) ax_gcc_arch="bdver3 bdver2 bdver1 amdfam10 k8" ;; *070?f??:*:*:*|70?f??:*:*:*) ax_gcc_arch="btver2 btver1 amdfam10 k8" ;; *???f??:*:*:*) ax_gcc_arch="amdfam10 k8" ;; esac ;; *:746e6543:736c7561:48727561) # IDT / VIA (Centaur) case $ax_cv_gcc_x86_cpuid_1 in *54?:*:*:*) ax_gcc_arch=winchip-c6 ;; *5[[89]]?:*:*:*) ax_gcc_arch=winchip2 ;; *66?:*:*:*) ax_gcc_arch=winchip2 ;; *6[[78]]?:*:*:*) ax_gcc_arch=c3 ;; *6[[9adf]]?:*:*:*) ax_gcc_arch="c3-2 c3" ;; esac ;; esac if test x"$ax_gcc_arch" = x; then # fallback case $host_cpu in i586*) ax_gcc_arch=pentium ;; i686*) ax_gcc_arch=pentiumpro ;; esac fi ;; sparc*) AC_PATH_PROG([PRTDIAG], [prtdiag], [prtdiag], [$PATH:/usr/platform/`uname -i`/sbin/:/usr/platform/`uname -m`/sbin/]) cputype=`(((grep cpu /proc/cpuinfo | cut -d: -f2) ; ($PRTDIAG -v |grep -i sparc) ; grep -i cpu /var/run/dmesg.boot ) | head -n 1) 2> /dev/null` cputype=`echo "$cputype" | tr -d ' -' | $SED 's/SPARCIIi/SPARCII/' |tr $as_cr_LETTERS $as_cr_letters` case $cputype in *ultrasparciv*) ax_gcc_arch="ultrasparc4 ultrasparc3 ultrasparc v9" ;; *ultrasparciii*) ax_gcc_arch="ultrasparc3 ultrasparc v9" ;; *ultrasparc*) ax_gcc_arch="ultrasparc v9" ;; *supersparc*|*tms390z5[[05]]*) ax_gcc_arch="supersparc v8" ;; *hypersparc*|*rt62[[056]]*) ax_gcc_arch="hypersparc v8" ;; *cypress*) ax_gcc_arch=cypress ;; esac ;; alphaev5) ax_gcc_arch=ev5 ;; alphaev56) ax_gcc_arch=ev56 ;; alphapca56) ax_gcc_arch="pca56 ev56" ;; alphapca57) ax_gcc_arch="pca57 pca56 ev56" ;; alphaev6) ax_gcc_arch=ev6 ;; alphaev67) ax_gcc_arch=ev67 ;; alphaev68) ax_gcc_arch="ev68 ev67" ;; alphaev69) ax_gcc_arch="ev69 ev68 ev67" ;; alphaev7) ax_gcc_arch="ev7 ev69 ev68 ev67" ;; alphaev79) ax_gcc_arch="ev79 ev7 ev69 ev68 ev67" ;; powerpc*) cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | $SED 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null` cputype=`echo $cputype | $SED -e 's/ppc//g;s/ *//g'` case $cputype in *750*) ax_gcc_arch="750 G3" ;; *740[[0-9]]*) ax_gcc_arch="$cputype 7400 G4" ;; *74[[4-5]][[0-9]]*) ax_gcc_arch="$cputype 7450 G4" ;; *74[[0-9]][[0-9]]*) ax_gcc_arch="$cputype G4" ;; *970*) ax_gcc_arch="970 G5 power4";; *POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";; *POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";; 603ev|8240) ax_gcc_arch="$cputype 603e 603";; *) ax_gcc_arch=$cputype ;; esac ax_gcc_arch="$ax_gcc_arch powerpc" ;; aarch64) cpuimpl=`grep 'CPU implementer' /proc/cpuinfo 2> /dev/null | cut -d: -f2 | tr -d " " | head -n 1` cpuarch=`grep 'CPU architecture' /proc/cpuinfo 2> /dev/null | cut -d: -f2 | tr -d " " | head -n 1` cpuvar=`grep 'CPU variant' /proc/cpuinfo 2> /dev/null | cut -d: -f2 | tr -d " " | head -n 1` case $cpuimpl in 0x42) case $cpuarch in 8) case $cpuvar in 0x0) ax_gcc_arch="thunderx2t99 vulcan armv8.1-a armv8-a+lse armv8-a native" ;; esac ;; esac ;; 0x43) case $cpuarch in 8) case $cpuvar in 0x0) ax_gcc_arch="thunderx armv8-a native" ;; 0x1) ax_gcc_arch="thunderx+lse armv8.1-a armv8-a+lse armv8-a native" ;; esac ;; esac ;; esac ;; esac fi # not cross-compiling fi # guess arch if test "x$ax_gcc_arch" != x -a "x$ax_gcc_arch" != xno; then if test "x[]m4_default([$1],yes)" = xyes; then # if we require portable code flag_prefixes="-mtune=" if test "x$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor" = xclang; then flag_prefixes="-march="; fi # -mcpu=$arch and m$arch generate nonportable code on every arch except # x86. And some other arches (e.g. Alpha) don't accept -mtune. Grrr. case $host_cpu in i*86|x86_64*|amd64*) flag_prefixes="$flag_prefixes -mcpu= -m";; esac else flag_prefixes="-march= -mcpu= -m" fi for flag_prefix in $flag_prefixes; do for arch in $ax_gcc_arch; do flag="$flag_prefix$arch" AX_CHECK_COMPILE_FLAG($flag, [if test "x$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor" = xclang; then if test "x[]m4_default([$1],yes)" = xyes; then if test "x$flag" = "x-march=$arch"; then flag=-mtune=$arch; fi fi fi; ax_cv_gcc_archflag=$flag; break]) done test "x$ax_cv_gcc_archflag" = xunknown || break done fi fi # $GCC=yes ]) AC_MSG_CHECKING([for gcc architecture flag]) AC_MSG_RESULT($ax_cv_gcc_archflag) if test "x$ax_cv_gcc_archflag" = xunknown; then m4_default([$3],:) else m4_default([$2], [CFLAGS="$CFLAGS $ax_cv_gcc_archflag"]) fi ]) ================================================ FILE: m4/ax_gcc_func_attribute.m4 ================================================ # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_gcc_func_attribute.html # =========================================================================== # # SYNOPSIS # # AX_GCC_FUNC_ATTRIBUTE(ATTRIBUTE) # # DESCRIPTION # # This macro checks if the compiler supports one of GCC's function # attributes; many other compilers also provide function attributes with # the same syntax. Compiler warnings are used to detect supported # attributes as unsupported ones are ignored by default so quieting # warnings when using this macro will yield false positives. # # The ATTRIBUTE parameter holds the name of the attribute to be checked. # # If ATTRIBUTE is supported define HAVE_FUNC_ATTRIBUTE_. # # The macro caches its result in the ax_cv_have_func_attribute_ # variable. # # The macro currently supports the following function attributes: # # alias # aligned # alloc_size # always_inline # artificial # cold # const # constructor # constructor_priority for constructor attribute with priority # deprecated # destructor # dllexport # dllimport # error # externally_visible # fallthrough # flatten # format # format_arg # gnu_inline # hot # ifunc # leaf # malloc # noclone # noinline # nonnull # noreturn # nothrow # optimize # pure # sentinel # sentinel_position # unused # used # visibility # warning # warn_unused_result # weak # weakref # # Unsupported function attributes will be tested with a prototype # returning an int and not accepting any arguments and the result of the # check might be wrong or meaningless so use with care. # # LICENSE # # Copyright (c) 2013 Gabriele Svelto # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 9 AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1]) AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([ m4_case([$1], [alias], [ int foo( void ) { return 0; } int bar( void ) __attribute__(($1("foo"))); ], [aligned], [ int foo( void ) __attribute__(($1(32))); ], [alloc_size], [ void *foo(int a) __attribute__(($1(1))); ], [always_inline], [ inline __attribute__(($1)) int foo( void ) { return 0; } ], [artificial], [ inline __attribute__(($1)) int foo( void ) { return 0; } ], [cold], [ int foo( void ) __attribute__(($1)); ], [const], [ int foo( void ) __attribute__(($1)); ], [constructor_priority], [ int foo( void ) __attribute__((__constructor__(65535/2))); ], [constructor], [ int foo( void ) __attribute__(($1)); ], [deprecated], [ int foo( void ) __attribute__(($1(""))); ], [destructor], [ int foo( void ) __attribute__(($1)); ], [dllexport], [ __attribute__(($1)) int foo( void ) { return 0; } ], [dllimport], [ int foo( void ) __attribute__(($1)); ], [error], [ int foo( void ) __attribute__(($1(""))); ], [externally_visible], [ int foo( void ) __attribute__(($1)); ], [fallthrough], [ int foo( void ) {switch (0) { case 1: __attribute__(($1)); case 2: break ; }}; ], [flatten], [ int foo( void ) __attribute__(($1)); ], [format], [ int foo(const char *p, ...) __attribute__(($1(printf, 1, 2))); ], [format_arg], [ char *foo(const char *p) __attribute__(($1(1))); ], [gnu_inline], [ inline __attribute__(($1)) int foo( void ) { return 0; } ], [hot], [ int foo( void ) __attribute__(($1)); ], [ifunc], [ int my_foo( void ) { return 0; } static int (*resolve_foo(void))(void) { return my_foo; } int foo( void ) __attribute__(($1("resolve_foo"))); ], [leaf], [ __attribute__(($1)) int foo( void ) { return 0; } ], [malloc], [ void *foo( void ) __attribute__(($1)); ], [noclone], [ int foo( void ) __attribute__(($1)); ], [noinline], [ __attribute__(($1)) int foo( void ) { return 0; } ], [nonnull], [ int foo(char *p) __attribute__(($1(1))); ], [noreturn], [ void foo( void ) __attribute__(($1)); ], [nothrow], [ int foo( void ) __attribute__(($1)); ], [optimize], [ __attribute__(($1(3))) int foo( void ) { return 0; } ], [pure], [ int foo( void ) __attribute__(($1)); ], [sentinel], [ int foo(void *p, ...) __attribute__(($1)); ], [sentinel_position], [ int foo(void *p, ...) __attribute__(($1(1))); ], [returns_nonnull], [ void *foo( void ) __attribute__(($1)); ], [unused], [ int foo( void ) __attribute__(($1)); ], [used], [ int foo( void ) __attribute__(($1)); ], [visibility], [ int foo_def( void ) __attribute__(($1("default"))); int foo_hid( void ) __attribute__(($1("hidden"))); int foo_int( void ) __attribute__(($1("internal"))); int foo_pro( void ) __attribute__(($1("protected"))); ], [warning], [ int foo( void ) __attribute__(($1(""))); ], [warn_unused_result], [ int foo( void ) __attribute__(($1)); ], [weak], [ int foo( void ) __attribute__(($1)); ], [weakref], [ static int foo( void ) { return 0; } static int bar( void ) __attribute__(($1("foo"))); ], [ m4_warn([syntax], [Unsupported attribute $1, the test may fail]) int foo( void ) __attribute__(($1)); ] )], []) ], dnl GCC doesn't exit with an error if an unknown attribute is dnl provided but only outputs a warning, so accept the attribute dnl only if no warning were issued. [AS_IF([test -s conftest.err], [AS_VAR_SET([ac_var], [no])], [AS_VAR_SET([ac_var], [yes])])], [AS_VAR_SET([ac_var], [no])]) ]) AS_IF([test yes = AS_VAR_GET([ac_var])], [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_FUNC_ATTRIBUTE_$1), 1, [Define to 1 if the system has the `$1' function attribute])], []) AS_VAR_POPDEF([ac_var]) ]) ================================================ FILE: m4/ax_gcc_x86_cpuid.m4 ================================================ # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_gcc_x86_cpuid.html # =========================================================================== # # SYNOPSIS # # AX_GCC_X86_CPUID(OP) # AX_GCC_X86_CPUID_COUNT(OP, COUNT) # # DESCRIPTION # # On Pentium and later x86 processors, with gcc or a compiler that has a # compatible syntax for inline assembly instructions, run a small program # that executes the cpuid instruction with input OP. This can be used to # detect the CPU type. AX_GCC_X86_CPUID_COUNT takes an additional COUNT # parameter that gets passed into register ECX before calling cpuid. # # On output, the values of the eax, ebx, ecx, and edx registers are stored # as hexadecimal strings as "eax:ebx:ecx:edx" in the cache variable # ax_cv_gcc_x86_cpuid_OP. # # If the cpuid instruction fails (because you are running a # cross-compiler, or because you are not using gcc, or because you are on # a processor that doesn't have this instruction), ax_cv_gcc_x86_cpuid_OP # is set to the string "unknown". # # This macro mainly exists to be used in AX_GCC_ARCHFLAG. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2008 Matteo Frigo # Copyright (c) 2015 Michael Petch # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 10 AC_DEFUN([AX_GCC_X86_CPUID], [AX_GCC_X86_CPUID_COUNT($1, 0) ]) AC_DEFUN([AX_GCC_X86_CPUID_COUNT], [AC_REQUIRE([AC_PROG_CC]) AC_LANG_PUSH([C]) AC_CACHE_CHECK(for x86 cpuid $1 output, ax_cv_gcc_x86_cpuid_$1, [AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ], [ int op = $1, level = $2, eax, ebx, ecx, edx; FILE *f; __asm__ __volatile__ ("xchg %%ebx, %1\n" "cpuid\n" "xchg %%ebx, %1\n" : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx) : "a" (op), "2" (level)); f = fopen("conftest_cpuid", "w"); if (!f) return 1; fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx); fclose(f); return 0; ])], [ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid], [ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid], [ax_cv_gcc_x86_cpuid_$1=unknown])]) AC_LANG_POP([C]) ]) ================================================ FILE: m4/ax_tls.m4 ================================================ # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_tls.html # =========================================================================== # # SYNOPSIS # # AX_TLS([action-if-found], [action-if-not-found]) # # DESCRIPTION # # Provides a test for the compiler support of thread local storage (TLS) # extensions. Defines TLS if it is found. Currently knows about C++11, # GCC/ICC, and MSVC. I think SunPro uses the same as GCC, and Borland # apparently supports either. # # LICENSE # # Copyright (c) 2008 Alan Woodland # Copyright (c) 2010 Diego Elio Petteno` # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 15 AC_DEFUN([AX_TLS], [ AC_MSG_CHECKING([for thread local storage (TLS) class]) AC_CACHE_VAL([ac_cv_tls], [for ax_tls_keyword in thread_local _Thread_local __thread '__declspec(thread)' none; do AS_CASE([$ax_tls_keyword], [none], [ac_cv_tls=none ; break], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM( [#include ], [static $ax_tls_keyword int bar;] )], [ac_cv_tls=$ax_tls_keyword ; break], [ac_cv_tls=none] )] ) done ] ) AC_MSG_RESULT([$ac_cv_tls]) AS_IF([test "$ac_cv_tls" != "none"], [AC_DEFINE_UNQUOTED([TLS],[$ac_cv_tls],[If the compiler supports a TLS storage class, define it to that here]) m4_ifnblank([$1],[$1],[[:]])], [m4_ifnblank([$2],[$2],[[:]])]) ]) ================================================ FILE: m4/extensions.m4 ================================================ dnl Provide AC_USE_SYSTEM_EXTENSIONS for old autoconf machines. AC_DEFUN([ACX_USE_SYSTEM_EXTENSIONS],[ ifdef([AC_USE_SYSTEM_EXTENSIONS],[ AC_USE_SYSTEM_EXTENSIONS ],[ AC_BEFORE([$0], [AC_COMPILE_IFELSE]) AC_BEFORE([$0], [AC_RUN_IFELSE]) AC_REQUIRE([AC_GNU_SOURCE]) AC_REQUIRE([AC_AIX]) AC_REQUIRE([AC_MINIX]) AH_VERBATIM([__EXTENSIONS__], [/* Enable extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif]) AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__], [ac_cv_safe_to_define___extensions__], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([ # define __EXTENSIONS__ 1 AC_INCLUDES_DEFAULT])], [ac_cv_safe_to_define___extensions__=yes], [ac_cv_safe_to_define___extensions__=no])]) test $ac_cv_safe_to_define___extensions__ = yes && AC_DEFINE([__EXTENSIONS__]) AC_DEFINE([_POSIX_PTHREAD_SEMANTICS]) AC_DEFINE([_TANDEM_SOURCE]) ]) ]) ================================================ FILE: m4/host-cpu-c-abi.m4 ================================================ # host-cpu-c-abi.m4 # serial 18 dnl Copyright (C) 2002-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl This file is offered as-is, without any warranty. dnl From Bruno Haible and Sam Steingold. dnl Sets the HOST_CPU variable to the canonical name of the CPU. dnl Sets the HOST_CPU_C_ABI variable to the canonical name of the CPU with its dnl C language ABI (application binary interface). dnl Also defines __${HOST_CPU}__ and __${HOST_CPU_C_ABI}__ as C macros in dnl config.h. dnl dnl This canonical name can be used to select a particular assembly language dnl source file that will interoperate with C code on the given host. dnl dnl For example: dnl * 'i386' and 'sparc' are different canonical names, because code for i386 dnl will not run on SPARC CPUs and vice versa. They have different dnl instruction sets. dnl * 'sparc' and 'sparc64' are different canonical names, because code for dnl 'sparc' and code for 'sparc64' cannot be linked together: 'sparc' code dnl contains 32-bit instructions, whereas 'sparc64' code contains 64-bit dnl instructions. A process on a SPARC CPU can be in 32-bit mode or in 64-bit dnl mode, but not both. dnl * 'mips' and 'mipsn32' are different canonical names, because they use dnl different argument passing and return conventions for C functions, and dnl although the instruction set of 'mips' is a large subset of the dnl instruction set of 'mipsn32'. dnl * 'mipsn32' and 'mips64' are different canonical names, because they use dnl different sizes for the C types like 'int' and 'void *', and although dnl the instruction sets of 'mipsn32' and 'mips64' are the same. dnl * The same canonical name is used for different endiannesses. You can dnl determine the endianness through preprocessor symbols: dnl - 'arm': test __ARMEL__. dnl - 'mips', 'mipsn32', 'mips64': test _MIPSEB vs. _MIPSEL. dnl - 'powerpc64': test __BIG_ENDIAN__ vs. __LITTLE_ENDIAN__. dnl * The same name 'i386' is used for CPUs of type i386, i486, i586 dnl (Pentium), AMD K7, Pentium II, Pentium IV, etc., because dnl - Instructions that do not exist on all of these CPUs (cmpxchg, dnl MMX, SSE, SSE2, 3DNow! etc.) are not frequently used. If your dnl assembly language source files use such instructions, you will dnl need to make the distinction. dnl - Speed of execution of the common instruction set is reasonable across dnl the entire family of CPUs. If you have assembly language source files dnl that are optimized for particular CPU types (like GNU gmp has), you dnl will need to make the distinction. dnl See . AC_DEFUN([gl_HOST_CPU_C_ABI], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([gl_C_ASM]) AC_CACHE_CHECK([host CPU and C ABI], [gl_cv_host_cpu_c_abi], [case "$host_cpu" in changequote(,)dnl i[34567]86 ) changequote([,])dnl gl_cv_host_cpu_c_abi=i386 ;; x86_64 ) # On x86_64 systems, the C compiler may be generating code in one of # these ABIs: # - 64-bit instruction set, 64-bit pointers, 64-bit 'long': x86_64. # - 64-bit instruction set, 64-bit pointers, 32-bit 'long': x86_64 # with native Windows (mingw, MSVC). # - 64-bit instruction set, 32-bit pointers, 32-bit 'long': x86_64-x32. # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': i386. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if (defined __x86_64__ || defined __amd64__ \ || defined _M_X64 || defined _M_AMD64) int ok; #else error fail #endif ]])], [AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __ILP32__ || defined _ILP32 int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=x86_64-x32], [gl_cv_host_cpu_c_abi=x86_64])], [gl_cv_host_cpu_c_abi=i386]) ;; changequote(,)dnl alphaev[4-8] | alphaev56 | alphapca5[67] | alphaev6[78] ) changequote([,])dnl gl_cv_host_cpu_c_abi=alpha ;; arm* | aarch64 ) # Assume arm with EABI. # On arm64 systems, the C compiler may be generating code in one of # these ABIs: # - aarch64 instruction set, 64-bit pointers, 64-bit 'long': arm64. # - aarch64 instruction set, 32-bit pointers, 32-bit 'long': arm64-ilp32. # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': arm or armhf. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#ifdef __aarch64__ int ok; #else error fail #endif ]])], [AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __ILP32__ || defined _ILP32 int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=arm64-ilp32], [gl_cv_host_cpu_c_abi=arm64])], [# Don't distinguish little-endian and big-endian arm, since they # don't require different machine code for simple operations and # since the user can distinguish them through the preprocessor # defines __ARMEL__ vs. __ARMEB__. # But distinguish arm which passes floating-point arguments and # return values in integer registers (r0, r1, ...) - this is # gcc -mfloat-abi=soft or gcc -mfloat-abi=softfp - from arm which # passes them in float registers (s0, s1, ...) and double registers # (d0, d1, ...) - this is gcc -mfloat-abi=hard. GCC 4.6 or newer # sets the preprocessor defines __ARM_PCS (for the first case) and # __ARM_PCS_VFP (for the second case), but older GCC does not. echo 'double ddd; void func (double dd) { ddd = dd; }' > conftest.c # Look for a reference to the register d0 in the .s file. AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $gl_c_asm_opt conftest.c) >/dev/null 2>&1 if LC_ALL=C grep 'd0,' conftest.$gl_asmext >/dev/null; then gl_cv_host_cpu_c_abi=armhf else gl_cv_host_cpu_c_abi=arm fi rm -f conftest* ]) ;; hppa1.0 | hppa1.1 | hppa2.0* | hppa64 ) # On hppa, the C compiler may be generating 32-bit code or 64-bit # code. In the latter case, it defines _LP64 and __LP64__. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#ifdef __LP64__ int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=hppa64], [gl_cv_host_cpu_c_abi=hppa]) ;; ia64* ) # On ia64 on HP-UX, the C compiler may be generating 64-bit code or # 32-bit code. In the latter case, it defines _ILP32. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#ifdef _ILP32 int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=ia64-ilp32], [gl_cv_host_cpu_c_abi=ia64]) ;; mips* ) # We should also check for (_MIPS_SZPTR == 64), but gcc keeps this # at 32. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined _MIPS_SZLONG && (_MIPS_SZLONG == 64) int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=mips64], [# In the n32 ABI, _ABIN32 is defined, _ABIO32 is not defined (but # may later get defined by ), and _MIPS_SIM == _ABIN32. # In the 32 ABI, _ABIO32 is defined, _ABIN32 is not defined (but # may later get defined by ), and _MIPS_SIM == _ABIO32. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if (_MIPS_SIM == _ABIN32) int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=mipsn32], [gl_cv_host_cpu_c_abi=mips])]) ;; powerpc* ) # Different ABIs are in use on AIX vs. Mac OS X vs. Linux,*BSD. # No need to distinguish them here; the caller may distinguish # them based on the OS. # On powerpc64 systems, the C compiler may still be generating # 32-bit code. And on powerpc-ibm-aix systems, the C compiler may # be generating 64-bit code. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __powerpc64__ || defined __LP64__ int ok; #else error fail #endif ]])], [# On powerpc64, there are two ABIs on Linux: The AIX compatible # one and the ELFv2 one. The latter defines _CALL_ELF=2. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined _CALL_ELF && _CALL_ELF == 2 int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=powerpc64-elfv2], [gl_cv_host_cpu_c_abi=powerpc64]) ], [gl_cv_host_cpu_c_abi=powerpc]) ;; rs6000 ) gl_cv_host_cpu_c_abi=powerpc ;; riscv32 | riscv64 ) # There are 2 architectures (with variants): rv32* and rv64*. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if __riscv_xlen == 64 int ok; #else error fail #endif ]])], [cpu=riscv64], [cpu=riscv32]) # There are 6 ABIs: ilp32, ilp32f, ilp32d, lp64, lp64f, lp64d. # Size of 'long' and 'void *': AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __LP64__ int ok; #else error fail #endif ]])], [main_abi=lp64], [main_abi=ilp32]) # Float ABIs: # __riscv_float_abi_double: # 'float' and 'double' are passed in floating-point registers. # __riscv_float_abi_single: # 'float' are passed in floating-point registers. # __riscv_float_abi_soft: # No values are passed in floating-point registers. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __riscv_float_abi_double int ok; #else error fail #endif ]])], [float_abi=d], [AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __riscv_float_abi_single int ok; #else error fail #endif ]])], [float_abi=f], [float_abi='']) ]) gl_cv_host_cpu_c_abi="${cpu}-${main_abi}${float_abi}" ;; s390* ) # On s390x, the C compiler may be generating 64-bit (= s390x) code # or 31-bit (= s390) code. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __LP64__ || defined __s390x__ int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=s390x], [gl_cv_host_cpu_c_abi=s390]) ;; sparc | sparc64 ) # UltraSPARCs running Linux have `uname -m` = "sparc64", but the # C compiler still generates 32-bit code. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __sparcv9 || defined __arch64__ int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=sparc64], [gl_cv_host_cpu_c_abi=sparc]) ;; *) gl_cv_host_cpu_c_abi="$host_cpu" ;; esac ]) dnl In most cases, $HOST_CPU and $HOST_CPU_C_ABI are the same. HOST_CPU=`echo "$gl_cv_host_cpu_c_abi" | sed -e 's/-.*//'` HOST_CPU_C_ABI="$gl_cv_host_cpu_c_abi" AC_SUBST([HOST_CPU]) AC_SUBST([HOST_CPU_C_ABI]) # This was # AC_DEFINE_UNQUOTED([__${HOST_CPU}__]) # AC_DEFINE_UNQUOTED([__${HOST_CPU_C_ABI}__]) # earlier, but KAI C++ 3.2d doesn't like this. sed -e 's/-/_/g' >> confdefs.h <&1 conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by GCC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]* | [A-Za-z]:[\\/]*)] [re_direlt='/[^/][^/]*/\.\./'] # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(acl_cv_path_LD, [if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in *GNU* | *'with BFD'*) test "$with_gnu_ld" != no && break ;; *) test "$with_gnu_ld" != yes && break ;; esac fi done IFS="$ac_save_ifs" else acl_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$acl_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) AC_LIB_PROG_LD_GNU ]) ================================================ FILE: m4/lib-link.m4 ================================================ # lib-link.m4 serial 13 (gettext-0.17) dnl Copyright (C) 2001-2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_PREREQ(2.54) dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and dnl augments the CPPFLAGS variable. dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. AC_DEFUN([AC_LIB_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ AC_LIB_LINKFLAGS_BODY([$1], [$2]) ac_cv_lib[]Name[]_libs="$LIB[]NAME" ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" ac_cv_lib[]Name[]_cppflags="$INC[]NAME" ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX" ]) LIB[]NAME="$ac_cv_lib[]Name[]_libs" LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" INC[]NAME="$ac_cv_lib[]Name[]_cppflags" LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) AC_SUBST([LIB]NAME[_PREFIX]) dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the dnl results of this search when this library appears as a dependency. HAVE_LIB[]NAME=yes undefine([Name]) undefine([NAME]) ]) dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) dnl searches for libname and the libraries corresponding to explicit and dnl implicit dependencies, together with the specified include files and dnl the ability to compile and link the specified testcode. If found, it dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME dnl accordingly. AC_LIB_LINKFLAGS_BODY([$1], [$2]) dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, dnl because if the user has installed lib[]Name and not disabled its use dnl via --without-lib[]Name-prefix, he wants to use it. ac_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ ac_save_LIBS="$LIBS" LIBS="$LIBS $LIB[]NAME" AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) LIBS="$ac_save_LIBS" ]) if test "$ac_cv_lib[]Name" = yes; then HAVE_LIB[]NAME=yes AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) AC_MSG_CHECKING([how to link with lib[]$1]) AC_MSG_RESULT([$LIB[]NAME]) else HAVE_LIB[]NAME=no dnl If $LIB[]NAME didn't lead to a usable library, we don't need dnl $INC[]NAME either. CPPFLAGS="$ac_save_CPPFLAGS" LIB[]NAME= LTLIB[]NAME= LIB[]NAME[]_PREFIX= fi AC_SUBST([HAVE_LIB]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) AC_SUBST([LIB]NAME[_PREFIX]) undefine([Name]) undefine([NAME]) ]) dnl Determine the platform dependent parameters needed to use rpath: dnl acl_libext, dnl acl_shlibext, dnl acl_hardcode_libdir_flag_spec, dnl acl_hardcode_libdir_separator, dnl acl_hardcode_direct, dnl acl_hardcode_minus_L. AC_DEFUN([AC_LIB_RPATH], [ dnl Tell automake >= 1.10 to complain if config.rpath is missing. m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done ]) wl="$acl_cv_wl" acl_libext="$acl_cv_libext" acl_shlibext="$acl_cv_shlibext" acl_libname_spec="$acl_cv_libname_spec" acl_library_names_spec="$acl_cv_library_names_spec" acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" acl_hardcode_direct="$acl_cv_hardcode_direct" acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" dnl Determine whether the user wants rpath handling at all. AC_ARG_ENABLE(rpath, [ --disable-rpath do not hardcode runtime library paths], :, enable_rpath=yes) ]) dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. AC_DEFUN([AC_LIB_LINKFLAGS_BODY], [ AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl Autoconf >= 2.61 supports dots in --with options. define([N_A_M_E],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit([$1],[.],[_])],[$1])]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib]N_A_M_E[-prefix], [ --with-lib]N_A_M_E[-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib --without-lib]N_A_M_E[-prefix don't search for lib$1 in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) dnl Search the library and its dependencies in $additional_libdir and dnl $LDFLAGS. Using breadth-first-seach. LIB[]NAME= LTLIB[]NAME= INC[]NAME= LIB[]NAME[]_PREFIX= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='$1 $2' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" dnl See if it was already located by an earlier AC_LIB_LINKFLAGS dnl or AC_LIB_HAVE_LINKFLAGS call. uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" else dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined dnl that this library doesn't exist. So just drop it. : fi else dnl Search the library lib$name in $additional_libdir and $LDFLAGS dnl and the already constructed $LIBNAME/$LTLIBNAME. found_dir= found_la= found_so= found_a= eval libname=\"$acl_libname_spec\" # typically: libname=lib$name if test -n "$acl_shlibext"; then shrext=".$acl_shlibext" # typically: shrext=.so else shrext= fi if test $use_additional = yes; then dir="$additional_libdir" dnl The same code as in the loop below: dnl First look for a shared library. if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi dnl Then look for a static library. if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext"; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` dnl First look for a shared library. if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi dnl Then look for a static library. if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext"; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then dnl Found the library. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then dnl Linking with a shared library. We attempt to hardcode its dnl directory into the executable's runpath, unless it's the dnl standard /usr/lib. if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then dnl No hardcoding is needed. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl Use an explicit option to hardcode DIR into the resulting dnl binary. dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi dnl The hardcoding into $LIBNAME is system dependent. if test "$acl_hardcode_direct" = yes; then dnl Using DIR/libNAME.so during linking hardcodes DIR into the dnl resulting binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then dnl Use an explicit option to hardcode DIR into the resulting dnl binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else dnl Rely on "-L$found_dir". dnl But don't add it if it's already contained in the LDFLAGS dnl or the already constructed $LIBNAME haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" fi if test "$acl_hardcode_minus_L" != no; then dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH dnl here, because this doesn't fit in flags passed to the dnl compiler. So give up. No hardcoding. This affects only dnl very old systems. dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then dnl Linking with a static library. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" else dnl We shouldn't come here, but anyway it's good to have a dnl fallback. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" fi fi dnl Assume the include files are nearby. additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` LIB[]NAME[]_PREFIX="$basedir" additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then dnl Potentially add $additional_includedir to $INCNAME. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's /usr/local/include and we are using GCC on Linux, dnl 3. if it's already present in $CPPFLAGS or the already dnl constructed $INCNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INC[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $INCNAME. INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" fi fi fi fi fi dnl Look for dependencies. if test -n "$found_la"; then dnl Read the .la file. It defines the variables dnl dlname, library_names, old_library, dependency_libs, current, dnl age, revision, installed, dlopen, dlpreopen, libdir. save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" dnl We use only dependency_libs. for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's /usr/local/lib and we are using GCC on Linux, dnl 3. if it's already present in $LDFLAGS or the already dnl constructed $LIBNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LIBNAME. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LTLIBNAME. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) dnl Handle this in the next round. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) dnl Handle this in the next round. Throw away the .la's dnl directory; it is already contained in a preceding -L dnl option. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) dnl Most likely an immediate library name. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" ;; esac done fi else dnl Didn't find the library; assume it is in the system directories dnl known to the linker and runtime loader. (All the system dnl directories known to the linker should also be known to the dnl runtime loader, otherwise the system is severely misconfigured.) LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$acl_hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user must dnl pass all path elements in one option. We can arrange that for a dnl single library, but not when more than one $LIBNAMEs are used. alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" done dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" else dnl The -rpath options are cumulative. for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then dnl When using libtool, the option that works for both libraries and dnl executables is -R. The -R options are cumulative. for found_dir in $ltrpathdirs; do LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" done fi ]) dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, dnl unless already present in VAR. dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes dnl contains two or three consecutive elements that belong together. AC_DEFUN([AC_LIB_APPENDTOVAR], [ for element in [$2]; do haveit= for x in $[$1]; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then [$1]="${[$1]}${[$1]:+ }$element" fi done ]) dnl For those cases where a variable contains several -L and -l options dnl referring to unknown libraries and directories, this macro determines the dnl necessary additional linker options for the runtime path. dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) dnl sets LDADDVAR to linker options needed together with LIBSVALUE. dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, dnl otherwise linking without libtool is assumed. AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], [ AC_REQUIRE([AC_LIB_RPATH]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) $1= if test "$enable_rpath" != no; then if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then dnl Use an explicit option to hardcode directories into the resulting dnl binary. rpathdirs= next= for opt in $2; do if test -n "$next"; then dir="$next" dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem"; then rpathdirs="$rpathdirs $dir" fi next= else case $opt in -L) next=yes ;; -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem"; then rpathdirs="$rpathdirs $dir" fi next= ;; *) next= ;; esac fi done if test "X$rpathdirs" != "X"; then if test -n ""$3""; then dnl libtool is used for linking. Use -R options. for dir in $rpathdirs; do $1="${$1}${$1:+ }-R$dir" done else dnl The linker is used for linking directly. if test -n "$acl_hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user dnl must pass all path elements in one option. alldirs= for dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="$flag" else dnl The -rpath options are cumulative. for dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$dir" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="${$1}${$1:+ }$flag" done fi fi fi fi fi AC_SUBST([$1]) ]) ================================================ FILE: m4/lib-prefix.m4 ================================================ # lib-prefix.m4 # serial 23 dnl Copyright (C) 2001-2005, 2008-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl This file is offered as-is, without any warranty. dnl From Bruno Haible. dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed dnl to access previously installed libraries. The basic assumption is that dnl a user will want packages to use other packages he previously installed dnl with the same --prefix option. dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate dnl libraries, but is otherwise very convenient. AC_DEFUN([AC_LIB_PREFIX], [ AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_ARG_WITH([lib-prefix], [[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib --without-lib-prefix don't search for libraries in includedir and libdir]], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) if test $use_additional = yes; then dnl Potentially add $additional_includedir to $CPPFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's already present in $CPPFLAGS, dnl 3. if it's /usr/local/include and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= for x in $CPPFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $CPPFLAGS. CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" fi fi fi fi dnl Potentially add $additional_libdir to $LDFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's already present in $LDFLAGS, dnl 3. if it's /usr/local/lib and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= for x in $LDFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LDFLAGS. LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" fi fi fi fi fi ]) dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, dnl acl_final_exec_prefix, containing the values to which $prefix and dnl $exec_prefix will expand at the end of the configure script. AC_DEFUN([AC_LIB_PREPARE_PREFIX], [ dnl Unfortunately, prefix and exec_prefix get only finally determined dnl at the end of configure. if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_saved_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_saved_prefix" ]) dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the dnl variables prefix and exec_prefix bound to the values they will have dnl at the end of the configure script. AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], [ acl_saved_prefix="$prefix" prefix="$acl_final_prefix" acl_saved_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" $1 exec_prefix="$acl_saved_exec_prefix" prefix="$acl_saved_prefix" ]) dnl AC_LIB_PREPARE_MULTILIB creates dnl - a function acl_is_expected_elfclass, that tests whether standard input dn; has a 32-bit or 64-bit ELF header, depending on the host CPU ABI, dnl - 3 variables acl_libdirstem, acl_libdirstem2, acl_libdirstem3, containing dnl the basename of the libdir to try in turn, either "lib" or "lib64" or dnl "lib/64" or "lib32" or "lib/sparcv9" or "lib/amd64" or similar. AC_DEFUN([AC_LIB_PREPARE_MULTILIB], [ dnl There is no formal standard regarding lib, lib32, and lib64. dnl On most glibc systems, the current practice is that on a system supporting dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. However, on dnl Arch Linux based distributions, it's the opposite: 32-bit libraries go dnl under $prefix/lib32 and 64-bit libraries go under $prefix/lib. dnl We determine the compiler's default mode by looking at the compiler's dnl library search path. If at least one of its elements ends in /lib64 or dnl points to a directory whose absolute pathname ends in /lib64, we use that dnl for 64-bit ABIs. Similarly for 32-bit ABIs. Otherwise we use the default, dnl namely "lib". dnl On Solaris systems, the current practice is that on a system supporting dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib. AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([gl_HOST_CPU_C_ABI_32BIT]) AC_CACHE_CHECK([for ELF binary format], [gl_cv_elf], [AC_EGREP_CPP([Extensible Linking Format], [#if defined __ELF__ || (defined __linux__ && (defined __EDG__ || defined __SUNPRO_C)) Extensible Linking Format #endif ], [gl_cv_elf=yes], [gl_cv_elf=no]) ]) if test $gl_cv_elf = yes; then # Extract the ELF class of a file (5th byte) in decimal. # Cf. https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header if od -A x < /dev/null >/dev/null 2>/dev/null; then # Use POSIX od. func_elfclass () { od -A n -t d1 -j 4 -N 1 } else # Use BSD hexdump. func_elfclass () { dd bs=1 count=1 skip=4 2>/dev/null | hexdump -e '1/1 "%3d "' echo } fi # Use 'expr', not 'test', to compare the values of func_elfclass, because on # Solaris 11 OpenIndiana and Solaris 11 OmniOS, the result is 001 or 002, # not 1 or 2. changequote(,)dnl case $HOST_CPU_C_ABI_32BIT in yes) # 32-bit ABI. acl_is_expected_elfclass () { expr "`func_elfclass | sed -e 's/[ ]//g'`" = 1 > /dev/null } ;; no) # 64-bit ABI. acl_is_expected_elfclass () { expr "`func_elfclass | sed -e 's/[ ]//g'`" = 2 > /dev/null } ;; *) # Unknown. acl_is_expected_elfclass () { : } ;; esac changequote([,])dnl else acl_is_expected_elfclass () { : } fi dnl Allow the user to override the result by setting acl_cv_libdirstems. AC_CACHE_CHECK([for the common suffixes of directories in the library search path], [acl_cv_libdirstems], [dnl Try 'lib' first, because that's the default for libdir in GNU, see dnl . acl_libdirstem=lib acl_libdirstem2= acl_libdirstem3= case "$host_os" in solaris*) dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment dnl . dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link." dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the dnl symlink is missing, so we set acl_libdirstem2 too. if test $HOST_CPU_C_ABI_32BIT = no; then acl_libdirstem2=lib/64 case "$host_cpu" in sparc*) acl_libdirstem3=lib/sparcv9 ;; i*86 | x86_64) acl_libdirstem3=lib/amd64 ;; esac fi ;; netbsd*) dnl On NetBSD/sparc64, there is a 'sparc' subdirectory that contains dnl 32-bit libraries. if test $HOST_CPU_C_ABI_32BIT != no; then case "$host_cpu" in sparc*) acl_libdirstem2=lib/sparc ;; esac fi ;; *) dnl If $CC generates code for a 32-bit ABI, the libraries are dnl surely under $prefix/lib or $prefix/lib32, not $prefix/lib64. dnl Similarly, if $CC generates code for a 64-bit ABI, the libraries dnl are surely under $prefix/lib or $prefix/lib64, not $prefix/lib32. dnl Find the compiler's search path. However, non-system compilers dnl sometimes have odd library search paths. But we can't simply invoke dnl '/usr/bin/gcc -print-search-dirs' because that would not take into dnl account the -m32/-m31 or -m64 options from the $CC or $CFLAGS. searchpath=`(LC_ALL=C $CC $CPPFLAGS $CFLAGS -print-search-dirs) 2>/dev/null \ | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test $HOST_CPU_C_ABI_32BIT != no; then # 32-bit or unknown ABI. if test -d /usr/lib32; then acl_libdirstem2=lib32 fi fi if test $HOST_CPU_C_ABI_32BIT != yes; then # 64-bit or unknown ABI. if test -d /usr/lib64; then acl_libdirstem3=lib64 fi fi if test -n "$searchpath"; then acl_saved_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib32/ | */lib32 ) acl_libdirstem2=lib32 ;; */lib64/ | */lib64 ) acl_libdirstem3=lib64 ;; */../ | */.. ) # Better ignore directories of this form. They are misleading. ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib32 ) acl_libdirstem2=lib32 ;; */lib64 ) acl_libdirstem3=lib64 ;; esac ;; esac fi done IFS="$acl_saved_IFS" if test $HOST_CPU_C_ABI_32BIT = yes; then # 32-bit ABI. acl_libdirstem3= fi if test $HOST_CPU_C_ABI_32BIT = no; then # 64-bit ABI. acl_libdirstem2= fi fi ;; esac test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" test -n "$acl_libdirstem3" || acl_libdirstem3="$acl_libdirstem" acl_cv_libdirstems="$acl_libdirstem,$acl_libdirstem2,$acl_libdirstem3" ]) dnl Decompose acl_cv_libdirstems into acl_libdirstem, acl_libdirstem2, and dnl acl_libdirstem3. changequote(,)dnl acl_libdirstem=`echo "$acl_cv_libdirstems" | sed -e 's/,.*//'` acl_libdirstem2=`echo "$acl_cv_libdirstems" | sed -e 's/^[^,]*,//' -e 's/,.*//'` acl_libdirstem3=`echo "$acl_cv_libdirstems" | sed -e 's/^[^,]*,[^,]*,//' -e 's/,.*//'` changequote([,])dnl ]) ================================================ FILE: m4/pkg.m4 ================================================ # pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- # serial 12 (pkg-config-0.29.2) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION], [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. dnl dnl If pkg-config is not found or older than specified, it will result dnl in an empty PKG_CONFIG variable. To avoid widespread issues with dnl scripts not checking it, ACTION-IF-NOT-FOUND defaults to aborting. dnl You can specify [PKG_CONFIG=false] as an action instead, which would dnl result in pkg-config tests failing, but no bogus error messages. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi if test -z "$PKG_CONFIG"; then m4_default([$2], [AC_MSG_ERROR([pkg-config not found])]) fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurrence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------ dnl dnl Prepare a "--with-" configure option using the lowercase dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and dnl PKG_CHECK_MODULES in a single macro. AC_DEFUN([PKG_WITH_MODULES], [ m4_pushdef([with_arg], m4_tolower([$1])) m4_pushdef([description], [m4_default([$5], [build with ]with_arg[ support])]) m4_pushdef([def_arg], [m4_default([$6], [auto])]) m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) m4_case(def_arg, [yes],[m4_pushdef([with_without], [--without-]with_arg)], [m4_pushdef([with_without],[--with-]with_arg)]) AC_ARG_WITH(with_arg, AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, [AS_TR_SH([with_]with_arg)=def_arg]) AS_CASE([$AS_TR_SH([with_]with_arg)], [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], [auto],[PKG_CHECK_MODULES([$1],[$2], [m4_n([def_action_if_found]) $3], [m4_n([def_action_if_not_found]) $4])]) m4_popdef([with_arg]) m4_popdef([description]) m4_popdef([def_arg]) ])dnl PKG_WITH_MODULES dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ----------------------------------------------- dnl dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES dnl check._[VARIABLE-PREFIX] is exported as make variable. AC_DEFUN([PKG_HAVE_WITH_MODULES], [ PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) AM_CONDITIONAL([HAVE_][$1], [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) ])dnl PKG_HAVE_WITH_MODULES dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------------------ dnl dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make dnl and preprocessor variable. AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) ])dnl PKG_HAVE_DEFINE_WITH_MODULES ================================================ FILE: m4/sb_autoconf_compat.m4 ================================================ # --------------------------------------------------------------------------- # Provide various compatibility macros for older Autoconf machines # Definitions were copied from the Autoconf source code. # --------------------------------------------------------------------------- m4_ifdef([AS_VAR_IF],,m4_define([AS_VAR_IF], [AS_LITERAL_WORD_IF([$1], [AS_IF(m4_ifval([$2], [[test "x$$1" = x[]$2]], [[${$1:+false} :]])], [AS_VAR_COPY([as_val], [$1]) AS_IF(m4_ifval([$2], [[test "x$as_val" = x[]$2]], [[${as_val:+false} :]])], [AS_IF(m4_ifval([$2], [[eval test \"x\$"$1"\" = x"_AS_ESCAPE([$2], [`], [\"$])"]], [[eval \${$1:+false} :]])]), [$3], [$4])]))dnl ================================================ FILE: m4/sb_check_mysql.m4 ================================================ dnl --------------------------------------------------------------------------- dnl Macro: SB_CHECK_MYSQL dnl First check if the MySQL root directory is specified with --with-mysql. dnl Otherwise check for custom MySQL paths in --with-mysql-includes and dnl --with-mysql-libs. If some paths are not specified explicitly, try to get dnl them from mysql_config. dnl --------------------------------------------------------------------------- AC_DEFUN([SB_CHECK_MYSQL],[ AS_IF([test "x$with_mysql" != xno], [ # Check for custom MySQL root directory if test [ "x$with_mysql" != xyes -a "x$with_mysql" != xno ] then ac_cv_mysql_root=`echo "$with_mysql" | sed -e 's+/$++'` if test [ -d "$ac_cv_mysql_root/include" -a \ -d "$ac_cv_mysql_root/libmysql_r" ] then ac_cv_mysql_includes="$ac_cv_mysql_root/include" ac_cv_mysql_libs="$ac_cv_mysql_root/libmysql_r" elif test [ -x "$ac_cv_mysql_root/bin/mysql_config" ] then mysqlconfig="$ac_cv_mysql_root/bin/mysql_config" else AC_MSG_ERROR([invalid MySQL root directory: $ac_cv_mysql_root]) fi fi # Check for custom includes path if test [ -z "$ac_cv_mysql_includes" ] then AC_ARG_WITH([mysql-includes], AS_HELP_STRING([--with-mysql-includes], [path to MySQL header files]), [ac_cv_mysql_includes=$withval]) fi if test [ -n "$ac_cv_mysql_includes" ] then AC_CACHE_CHECK([MySQL includes], [ac_cv_mysql_includes], [ac_cv_mysql_includes=""]) MYSQL_CFLAGS="-I$ac_cv_mysql_includes" fi # Check for custom library path if test [ -z "$ac_cv_mysql_libs" ] then AC_ARG_WITH([mysql-libs], AS_HELP_STRING([--with-mysql-libs], [path to MySQL libraries]), [ac_cv_mysql_libs=$withval]) fi if test [ -n "$ac_cv_mysql_libs" ] then # Trim trailing '.libs' if user passed it in --with-mysql-libs option ac_cv_mysql_libs=`echo ${ac_cv_mysql_libs} | sed -e 's/.libs$//' \ -e 's+.libs/$++'` AC_CACHE_CHECK([MySQL libraries], [ac_cv_mysql_libs], [ac_cv_mysql_libs=""]) save_LDFLAGS="$LDFLAGS" save_LIBS="$LIBS" LDFLAGS="-L$ac_cv_mysql_libs" LIBS="" # libmysqlclient_r has been removed in MySQL 5.7 AC_SEARCH_LIBS([mysql_real_connect], [mysqlclient_r mysqlclient], [], AC_MSG_ERROR([cannot find MySQL client libraries in $ac_cv_mysql_libs])) MYSQL_LIBS="$LDFLAGS $LIBS" LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" fi # If some path is missing, try to autodetermine with mysql_config if test [ -z "$ac_cv_mysql_includes" -o -z "$ac_cv_mysql_libs" ] then if test [ -z "$mysqlconfig" ] then AC_PATH_PROG(mysqlconfig,mysql_config) fi if test [ -z "$mysqlconfig" ] then AC_MSG_ERROR([mysql_config executable not found ******************************************************************************** ERROR: cannot find MySQL libraries. If you want to compile with MySQL support, please install the package containing MySQL client libraries and headers. On Debian-based systems the package name is libmysqlclient-dev. On RedHat-based systems, it is mysql-devel. If you have those libraries installed in non-standard locations, you must either specify file locations explicitly using --with-mysql-includes and --with-mysql-libs options, or make sure path to mysql_config is listed in your PATH environment variable. If you want to disable MySQL support, use --without-mysql option. ******************************************************************************** ]) else if test [ -z "$ac_cv_mysql_includes" ] then AC_MSG_CHECKING(MySQL C flags) MYSQL_CFLAGS=`${mysqlconfig} --cflags` AC_MSG_RESULT($MYSQL_CFLAGS) fi if test [ -z "$ac_cv_mysql_libs" ] then AC_MSG_CHECKING(MySQL linker flags) MYSQL_LIBS=`${mysqlconfig} --libs_r` AC_MSG_RESULT($MYSQL_LIBS) fi fi fi AC_DEFINE([USE_MYSQL], 1, [Define to 1 if you want to compile with MySQL support]) USE_MYSQL=1 AC_SUBST([MYSQL_LIBS]) AC_SUBST([MYSQL_CFLAGS]) AC_MSG_CHECKING([if mysql.h defines MYSQL_OPT_SSL_MODE]) SAVE_CFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} ${MYSQL_CFLAGS}" AC_COMPILE_IFELSE([AC_LANG_PROGRAM( [[ #include enum mysql_option opt = MYSQL_OPT_SSL_MODE; ]])], [ AC_DEFINE([HAVE_MYSQL_OPT_SSL_MODE], 1, [Define to 1 if mysql.h defines MYSQL_OPT_SSL_MODE]) AC_MSG_RESULT([yes]) ], [AC_MSG_RESULT([no])]) ]) CFLAGS="${SAVE_CFLAGS}" AM_CONDITIONAL([USE_MYSQL], test "x$with_mysql" != xno) AC_SUBST([USE_MYSQL]) ]) ================================================ FILE: m4/sb_concurrency_kit.m4 ================================================ # Copyright (C) 2016-2017 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # --------------------------------------------------------------------------- # Macro: SB_CONCURRENCY_KIT # --------------------------------------------------------------------------- AC_DEFUN([SB_CONCURRENCY_KIT], [ AC_ARG_WITH([system-ck], AS_HELP_STRING([--with-system-ck], [Use system-provided Concurrency Kit headers and library (requires pkg-config)]), [sb_use_ck="system"], [sb_use_ck="bundled"]) AC_CACHE_CHECK([whether to build with system or bundled Concurrency Kit], [sb_cv_lib_ck], [ AS_IF([test "x$sb_use_ck" = "xsystem"], [ sb_cv_lib_ck=[system] ], [ sb_cv_lib_ck=[bundled] ]) ]) AS_IF([test "x$sb_cv_lib_ck" = "xsystem"], # let PKG_CHECK_MODULES set CK_CFLAGS and CK_LIBS for system libck [PKG_CHECK_MODULES([CK], [ck])], # Set CK_CFLAGS and CK_LIBS manually for bundled libck [ CK_CFLAGS="-I\$(abs_top_builddir)/third_party/concurrency_kit/include" CK_LIBS="\$(abs_top_builddir)/third_party/concurrency_kit/lib/libck.a" case $target_cpu in powerpc*|aarch64) # Assume 128-byte cache line on AArch64 and PowerPC CPPFLAGS="${CPPFLAGS} -DCK_MD_CACHELINE=128" ;; # Force --platform=i*86 for CK, otherwise its configure script # autodetects target based on 'uname -m' which doesn't work for # cross-compiliation i486*|i586*) CK_CONFIGURE_FLAGS="--platform=i586" ;; i686*) CK_CONFIGURE_FLAGS="--platform=i686" ;; mips64*) CK_CONFIGURE_FLAGS="--use-cc-builtins" ;; esac # Add --enable-lse to CK build flags, if LSE instructions are supported by # the target architecture if test "$cross_compiling" = no -a "$host_cpu" = aarch64; then AC_MSG_CHECKING([whether LSE instructions are supported]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM(, [[ unsigned long long d = 1, a = 1; unsigned long long *t = &a; __asm__ __volatile__( "stadd %0, [%1];" : "+&r" (d) : "r" (t) : "memory"); ]])], [ CK_CONFIGURE_FLAGS="--enable-lse" AC_MSG_RESULT([yes]) ], [ CK_CONFIGURE_FLAGS="" AC_MSG_RESULT([no]) ] ) AC_SUBST([CK_CONFIGURE_FLAGS]) fi ] ) AC_DEFINE_UNQUOTED([SB_WITH_CK], ["$sb_use_ck"], [Whether system or bundled Concurrency Kit is used]) AM_CONDITIONAL([USE_BUNDLED_CK], [test "x$sb_use_ck" = xbundled]) ]) ================================================ FILE: m4/sb_luajit.m4 ================================================ # Copyright (C) 2016 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # --------------------------------------------------------------------------- # Macro: SB_LUAJIT # --------------------------------------------------------------------------- AC_DEFUN([SB_LUAJIT], [ AC_ARG_WITH([system-luajit], AS_HELP_STRING([--with-system-luajit], [Use system-provided LuaJIT headers and library (requires pkg-config)]), [sb_use_luajit="system"], [sb_use_luajit="bundled"]) AC_CACHE_CHECK([whether to build with system or bundled LuaJIT], [sb_cv_lib_luajit], [ AS_IF([test "x$sb_use_luajit" = "xsystem"], [ sb_cv_lib_luajit=[system] ], [ sb_cv_lib_luajit=[bundled] ]) ]) AS_IF([test "x$sb_cv_lib_luajit" = "xsystem"], # let PKG_CHECK_MODULES set LUAJIT_CFLAGS and LUAJIT_LIBS for system libluajit [PKG_CHECK_MODULES([LUAJIT], [luajit])], # Set LUAJIT_CFLAGS and LUAJIT_LIBS manually for bundled libluajit [ LUAJIT_CFLAGS="-I\$(abs_top_builddir)/third_party/luajit/inc" LUAJIT_LIBS="\$(abs_top_builddir)/third_party/luajit/lib/libluajit-5.1.a" ] ) AC_DEFINE_UNQUOTED([SB_WITH_LUAJIT], ["$sb_use_luajit"], [Whether system or bundled LuaJIT is used]) AM_CONDITIONAL([USE_BUNDLED_LUAJIT], [test "x$sb_use_luajit" = xbundled]) AS_CASE([$host_os:$host_cpu], # Add extra flags when building a 64-bit application on OS X, # http://luajit.org/install.html [*darwin*:x86_64], [LUAJIT_LDFLAGS="-pagezero_size 10000 -image_base 100000000"], # -ldl and -rdynamic are required on Linux [*linux*:*], [ LUAJIT_LIBS="$LUAJIT_LIBS -ldl" LUAJIT_LDFLAGS="-rdynamic" ], # -rdynamic is required on FreeBSD [*freebsd*:*], [ LUAJIT_LDFLAGS="-rdynamic" ] ) AC_SUBST([LUAJIT_LDFLAGS]) ]) ================================================ FILE: missing ================================================ #! /bin/sh # Common stub for a few missing GNU programs while installing. # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003 Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi case "$1" in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case "$1" in -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch]" ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing 0.4 - GNU automake" ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; aclocal*) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 fi echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 fi echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 fi echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 fi echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 fi echo 1>&2 "\ WARNING: \`$1' is needed, and you do not seem to have it handy on your system. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 fi echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` fi if [ -f "$file" ]; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit 1 fi ;; makeinfo) if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then # We have makeinfo, but it failed. exit 1 fi echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` fi touch $file ;; tar) shift if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 fi # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case "$firstarg" in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case "$firstarg" in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and you do not seem to have it handy on your system. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 ================================================ FILE: mkinstalldirs ================================================ #! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain errstatus=0 dirmode="" usage="\ Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help echo "$usage" 1>&2 exit 0 ;; -m) # -m PERM arg shift test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } dirmode=$1 shift ;; --) # stop option processing shift break ;; -*) # unknown option echo "$usage" 1>&2 exit 1 ;; *) # first non-opt arg break ;; esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac case $dirmode in '') if mkdir -p -- . 2>/dev/null; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" fi ;; *) if mkdir -m "$dirmode" -p -- . 2>/dev/null; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" fi ;; esac for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case $pathcomp in -*) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr else if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" lasterr="" chmod "$dirmode" "$pathcomp" || lasterr=$? if test ! -z "$lasterr"; then errstatus=$lasterr fi fi fi fi pathcomp="$pathcomp/" done done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 2 # End: # mkinstalldirs ends here ================================================ FILE: rpm/sysbench.spec ================================================ Summary: Scriptable database and system performance benchmark Name: sysbench # Version will be replaced by packpack Version: x.y.z Release: 1%{?dist} License: GPLv2+ Group: Applications/System Source0: https://github.com/akopytov/%{name}/archive/%{version}/%{name}-%{version}.tar.gz URL: https://github.com/akopytov/sysbench/ %if 0%{?rhel} < 7 BuildRequires: mysql-devel %else BuildRequires: mariadb-devel %endif BuildRequires: postgresql-devel BuildRequires: make BuildRequires: automake BuildRequires: libtool BuildRequires: pkgconfig BuildRequires: libaio-devel # Use bundled cram for tests %if 0%{?rhel} > 7 BuildRequires: python2 %else BuildRequires: python %endif ExclusiveArch: %{arm} %{ix86} x86_64 %{mips} aarch64 %description sysbench is a scriptable multi-threaded benchmark tool based on LuaJIT. It is most frequently used for database benchmarks, but can also be used to create arbitrarily complex workloads that do not involve a database server. sysbench comes with the following bundled benchmarks: - oltp_*.lua: a collection of OLTP-like database benchmarks - fileio: a filesystem-level benchmark - cpu: a simple CPU benchmark - memory: a memory access benchmark - threads: a thread-based scheduler benchmark - mutex: a POSIX mutex benchmark %prep %setup -q %build export CFLAGS="%{optflags}" autoreconf -vif %configure --with-mysql \ --with-pgsql \ --without-gcc-arch %if 0%{?el6} make -j2 %else %make_build %endif %install %make_install rm -f %{buildroot}%{_docdir}/sysbench/manual.html %check make test %files %doc ChangeLog COPYING README.md %if 0%{?el6} %else %license COPYING %endif %{_bindir}/* %{_datadir}/%{name} %changelog * Fri Mar 15 2019 Alexey Bychko - 1.0.16-1 - Updated build dependencies for RHEL8-Beta. * Sat Jan 6 2018 Alexey Kopytov - 1.0.12-1 - Remove vim-common from build dependencies. * Sun Apr 09 2017 Alexey Kopytov - 1.0.5-1 - Add --without-gcc-arch to configure flags * Sat Apr 08 2017 Alexey Kopytov - 1.0.5-1 - Workarounds for make_build and license macros which are not available on EL 6. * Fri Apr 07 2017 Alexey Kopytov - 1.0.5-1 - Depend on mysql-devel rather than mariadb-devel on EL 6. - Use bundled cram for tests, because it's not available on EL 6. * Thu Apr 06 2017 Alexey Kopytov - 1.0.5-1 - Reuse downstream Fedora spec with modifications (prefer bundled libraries) * Mon Mar 13 2017 Xavier Bachelot 1.0.4-2 - Don't build aarch64 on el7. * Mon Mar 13 2017 Xavier Bachelot 1.0.4-1 - Fix build for i686. - Drop bundled cram. * Wed Mar 08 2017 Xavier Bachelot 1.0.3-1 - Update to 1.0.3 (RHBZ#1424670). - Restrict arches to the same ones as luajit. - Add --with-gcc-arch=native to configure for %%{arm} and aarch64. - Ignore test suite results for aarch64, it segfaults in koji. * Sat Feb 25 2017 Xavier Bachelot 1.0.2-2 - Run test suite. * Sat Feb 25 2017 Xavier Bachelot 1.0.2-1 - Update to 1.0.2 (RHBZ#1424670). * Sun Feb 12 2017 Honza Horak - 1.0.0-1 - Update to the first proper release 1.0.0 * Sat Feb 11 2017 Fedora Release Engineering - 0.4.12-15 - Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild * Fri Feb 05 2016 Fedora Release Engineering - 0.4.12-14 - Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild * Fri Jun 19 2015 Fedora Release Engineering - 0.4.12-13 - Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild * Thu Sep 04 2014 Xavier Bachelot 0.4.12-12 - Modernize specfile. * Mon Aug 18 2014 Fedora Release Engineering - 0.4.12-11 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild * Sun Jun 08 2014 Fedora Release Engineering - 0.4.12-10 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild * Sun Aug 04 2013 Fedora Release Engineering - 0.4.12-9 - Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild * Fri Feb 15 2013 Fedora Release Engineering - 0.4.12-8 - Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild * Sat Jul 21 2012 Fedora Release Engineering - 0.4.12-7 - Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild * Sat Jan 14 2012 Fedora Release Engineering - 0.4.12-6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild * Tue Sep 06 2011 Xavier Bachelot 0.4.12-5 - Add BR: libaio-devel (rhbz#735882). * Wed Mar 23 2011 Dan Horák - 0.4.12-4 - rebuilt for mysql 5.5.10 (soname bump in libmysqlclient) * Wed Feb 09 2011 Fedora Release Engineering - 0.4.12-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild * Fri Dec 24 2010 Xavier Bachelot 0.4.12-2 - Rebuild against new mysql. * Wed Jul 07 2010 Xavier Bachelot 0.4.12-1 - Update to 0.4.12. * Fri Aug 21 2009 Tomas Mraz - 0.4.10-5 - rebuilt with new openssl * Sun Jul 26 2009 Fedora Release Engineering - 0.4.10-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild * Wed Mar 18 2009 Xavier Bachelot 0.4.10-3 - License is GPLv2+, not GPLv2. * Sat Mar 14 2009 Xavier Bachelot 0.4.10-2 - Make postgres support optional, the version in rhel4 is too old. - Drop TODO and manual.html from %%doc, they are empty. * Thu Mar 05 2009 Xavier Bachelot 0.4.10-1 - Adapt original spec file taken from PLD. ================================================ FILE: scripts/buildpack.sh ================================================ #!/usr/bin/env bash # # Copyright (C) 2017-2019 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # Build packages for a specified architecture and upload them to packagecloud.io # Expects the following environment variables to be defined: # # ARCH - architecture. 'aarch64', 'x86_64 and 'i386' are currently supported # values. If not set, the script behaves as if it was sequentially # called with 'x86_64' and 'i386' values # # OS/DIST - distribution specification for packpack. When empty (the default) # use all disitributions available for ARCH # # PACKAGECLOUD_TOKEN - packagecloud.io API token # # PACKAGECLOUD_USER - packagecloud.io user name, defaults to 'akopytov' # # PACKAGECLOUD_REPO - packagecloud.io repository. The default is 'sysbench' # for releases (i.e. if git HEAD corresponds to a tag), # and 'sysbench-prereleases' otherwise. # # PACKAGECLOUD_EXTRA_ARGS - extra arguments to pass to the package_cloud # utility. Empty by default. Can be used to pass the # --skip-errors flag to ignore deploy errors. # # PACKPACK_REPO - packpack repository to use. Defaults to akopytov/packpack. set -eu PACKAGECLOUD_USER=${PACKAGECLOUD_USER:-"akopytov"} PACKAGECLOUD_EXTRA_ARGS=${PACKAGECLOUD_EXTRA_ARGS:-} PACKPACK_REPO=${PACKPACK_REPO:-akopytov/packpack} distros_x86_64=( "el 7 x86_64" "el 8 x86_64" "fedora 32 x86_64" "fedora 33 x86_64" "ubuntu xenial x86_64" "ubuntu bionic x86_64" "ubuntu focal x86_64" "ubuntu groovy x86_64" "debian stretch x86_64" "debian buster x86_64" ) distros_i386=( "ubuntu xenial i386" "ubuntu bionic i386" "debian stretch i386" "debian buster i386" ) distros_aarch64=( "el 7 aarch64" "fedora 32 aarch64" "fedora 33 aarch64" "ubuntu bionic aarch64" "ubuntu focal aarch64" "ubuntu groovy aarch64" "ubuntu xenial aarch64" "debian stretch aarch64" "debian buster aarch64" ) main() { if [ ! -r configure.ac ]; then echo "This script should be executed from the source root directory." exit 1 fi if [ -z "${PACKAGECLOUD_TOKEN+x}" ]; then echo "This script expects PACKAGECLOUD_TOKEN to be defined." exit 1 fi if ! which package_cloud >/dev/null 2>&1 ; then echo "This script requires package_cloud. You can install it by running:" echo " gem install package_cloud" exit 1 fi if [ ! -d packpack ]; then git clone https://github.com/${PACKPACK_REPO} packpack fi if [ -z "${PACKAGECLOUD_REPO+x}" ]; then # Upload builds corresponding to release tags to the 'sysbench' # repository, push other ones to 'sysbench-prereleases' if ! git describe --long --always >/dev/null 2>&1 ; then echo "Either run this script from a git repository, or specify " echo "the packagecloud repository explicitly with PACKAGECLOUD_REPO" exit 1 fi local commits=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\2/p') if [ ${commits:-0} = 0 ]; then export PACKAGECLOUD_REPO=sysbench # Use short version numbers for release builds export VERSION=$(git describe) else export PACKAGECLOUD_REPO=sysbench-prereleases fi fi declare -a distros OS=${OS:-} DIST=${DIST:-} if [ -n "${OS}" -a -n "${DIST}" ]; then distros=( "${OS} ${DIST} ${ARCH:-x86_64}" ) elif [ -z "${ARCH+x}" ]; then distros=("${distros_x86_64[@]}" "${distros_i386[@]}") else case "$ARCH" in x86_64) distros=( "${distros_x86_64[@]}" ) ;; i386) distros=( "${distros_i386[@]}" ) ;; aarch64) distros=( "${distros_aarch64[@]}" ) ;; *) echo "Invalid ARCH value: $ARCH" exit 1 ;; esac fi export PRODUCT=sysbench export CHANGELOG_NAME=sysbench export CHANGELOG_EMAIL=akopytov@gmail.com for d in "${distros[@]}"; do echo "*** Building package for $d ***" local t=( $d ) export OS=${t[0]} export DIST=${t[1]} export ARCH=${t[2]} # Replace "el" with "centos" for packpack, as there is no "el-*" docker # images for some architectures local PPOS=${OS/#el/centos} OS="$PPOS" packpack/packpack # To avoid name conflicts, deploy source packages only for # "default", i.e. x86_64 architecture if [ "${ARCH}" = "x86_64" ]; then files="$(ls build/*.{rpm,deb,dsc} 2>/dev/null || :)" else files="$(ls build/*{[^c].rpm,.deb} 2>/dev/null || :)" fi if [ -z "$files" ]; then echo "No package files to push" exit 1 fi echo "Pushing packages to ${PACKAGECLOUD_USER}/${PACKAGECLOUD_REPO}" for f in $files ; do echo $f package_cloud push ${PACKAGECLOUD_EXTRA_ARGS} \ ${PACKAGECLOUD_USER}/${PACKAGECLOUD_REPO}/${OS}/${DIST} \ $f done OS=${PPOS} packpack/packpack clean done } main ================================================ FILE: snap/snapcraft.yaml.in ================================================ name: sysbench version: @PACKAGE_VERSION@ summary: Scriptable database and system performance benchmark description: | sysbench is a scriptable multi-threaded benchmark tool based on LuaJIT. It is most frequently used for database benchmarks, but can also be used to create arbitrarily complex workloads that do not involve a database server. sysbench comes with the following bundled benchmarks: - oltp_*.lua: a collection of OLTP-like database benchmarks - fileio: a filesystem-level benchmark - cpu: a simple CPU benchmark - memory: a memory access benchmark - threads: a thread-based scheduler benchmark - mutex: a POSIX mutex benchmark grade: stable confinement: classic apps: sysbench: command: sysbench plugs: - network parts: sysbench: source: . plugin: autotools build-packages: - libmysqlclient-dev stage-packages: - libmysqlclient20 - libaio1 ================================================ FILE: src/Makefile.am ================================================ # Copyright (C) 2004 MySQL AB # Copyright (C) 2004-2017 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA SUBDIRS = drivers tests lua . AM_CPPFLAGS += -DDATADIR=\"$(pkgdatadir)\" -DLIBDIR=\"$(pkglibdir)\" bin_PROGRAMS = sysbench # The following check will be extended as new database drivers will be added if USE_MYSQL mysql_ldadd = drivers/mysql/libsbmysql.a $(MYSQL_LIBS) endif if USE_PGSQL pgsql_ldadd = drivers/pgsql/libsbpgsql.a $(PGSQL_LIBS) endif sysbench_SOURCES = sysbench.c sysbench.h sb_timer.c sb_timer.h \ sb_options.c sb_options.h sb_logger.c sb_logger.h sb_list.h db_driver.h \ db_driver.c sb_histogram.c sb_histogram.h sb_rand.c sb_rand.h \ sb_thread.c sb_thread.h sb_barrier.c sb_barrier.h sb_lua.c \ sb_ck_pr.h \ sb_lua.h sb_util.h sb_util.c sb_counter.h sb_counter.c \ lua/internal/sysbench.lua.h lua/internal/sysbench.sql.lua.h \ lua/internal/sysbench.rand.lua.h lua/internal/sysbench.cmdline.lua.h \ lua/internal/sysbench.histogram.lua.h \ xoroshiro128plus.h sysbench_LDADD = tests/fileio/libsbfileio.a tests/threads/libsbthreads.a \ tests/memory/libsbmemory.a tests/cpu/libsbcpu.a \ tests/mutex/libsbmutex.a \ $(mysql_ldadd) $(pgsql_ldadd) \ $(LUAJIT_LIBS) $(CK_LIBS) sysbench_LDFLAGS = $(mysql_ldflags) \ $(pgsql_ldflags) $(LUAJIT_LDFLAGS) ================================================ FILE: src/db_driver.c ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef STDC_HEADERS # include # include # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include #include "db_driver.h" #include "sb_list.h" #include "sb_histogram.h" #include "sb_ck_pr.h" /* Query length limit for bulk insert queries */ #define BULK_PACKET_SIZE (512*1024) /* How many rows to insert before COMMITs (used in bulk insert) */ #define ROWS_BEFORE_COMMIT 1000 /* Global variables */ db_globals_t db_globals CK_CC_CACHELINE; static sb_list_t drivers; /* list of available DB drivers */ static uint8_t stats_enabled; static bool db_global_initialized; static pthread_once_t db_global_once = PTHREAD_ONCE_INIT; /* Timers used in debug mode */ static sb_timer_t *exec_timers; static sb_timer_t *fetch_timers; /* Static functions */ static int db_parse_arguments(void); #if 0 static void db_free_row(db_row_t *); #endif static int db_bulk_do_insert(db_conn_t *, int); static void db_reset_stats(void); static int db_free_results_int(db_conn_t *con); /* DB layer arguments */ static sb_arg_t db_args[] = { SB_OPT("db-driver", "specifies database driver to use " "('help' to get list of available drivers)", #ifdef USE_MYSQL "mysql", #else NULL, #endif STRING), SB_OPT("db-ps-mode", "prepared statements usage mode {auto, disable}", "auto", STRING), SB_OPT("db-debug", "print database-specific debug information", "off", BOOL), SB_OPT_END }; /* Register available database drivers and command line arguments */ int db_register(void) { sb_list_item_t *pos; db_driver_t *drv; /* Register database drivers */ SB_LIST_INIT(&drivers); #ifdef USE_MYSQL register_driver_mysql(&drivers); #endif #ifdef USE_PGSQL register_driver_pgsql(&drivers); #endif /* Register command line options for each driver */ SB_LIST_FOR_EACH(pos, &drivers) { drv = SB_LIST_ENTRY(pos, db_driver_t, listitem); if (drv->args != NULL) sb_register_arg_set(drv->args); drv->initialized = false; pthread_mutex_init(&drv->mutex, NULL); } /* Register general command line arguments for DB API */ sb_register_arg_set(db_args); return 0; } /* Print list of available drivers and their options */ void db_print_help(void) { sb_list_item_t *pos; db_driver_t *drv; log_text(LOG_NOTICE, "General database options:\n"); sb_print_options(db_args); log_text(LOG_NOTICE, ""); log_text(LOG_NOTICE, "Compiled-in database drivers:"); SB_LIST_FOR_EACH(pos, &drivers) { drv = SB_LIST_ENTRY(pos, db_driver_t, listitem); log_text(LOG_NOTICE, " %s - %s", drv->sname, drv->lname); } log_text(LOG_NOTICE, ""); SB_LIST_FOR_EACH(pos, &drivers) { drv = SB_LIST_ENTRY(pos, db_driver_t, listitem); log_text(LOG_NOTICE, "%s options:", drv->sname); sb_print_options(drv->args); } } static void enable_print_stats(void) { ck_pr_fence_store(); ck_pr_store_8(&stats_enabled, 1); } static void disable_print_stats(void) { ck_pr_store_8(&stats_enabled, 0); ck_pr_fence_store(); } static bool check_print_stats(void) { bool rc = ck_pr_load_8(&stats_enabled) == 1; ck_pr_fence_load(); return rc; } static void db_init(void) { if (SB_LIST_IS_EMPTY(&drivers)) { log_text(LOG_FATAL, "No DB drivers available"); return; } if (db_parse_arguments()) return; /* Initialize timers if in debug mode */ if (db_globals.debug) { exec_timers = sb_alloc_per_thread_array(sizeof(sb_timer_t)); fetch_timers = sb_alloc_per_thread_array(sizeof(sb_timer_t)); } db_reset_stats(); enable_print_stats(); db_global_initialized = true; } /* Initialize a driver specified by 'name' and return a handle to it If NULL is passed as a name, then use the driver passed in --db-driver command line option */ db_driver_t *db_create(const char *name) { db_driver_t *drv = NULL; db_driver_t *tmp; sb_list_item_t *pos; pthread_once(&db_global_once, db_init); if (!db_global_initialized) goto err; if (name == NULL && db_globals.driver == NULL) { drv = SB_LIST_ENTRY(SB_LIST_ITEM_NEXT(&drivers), db_driver_t, listitem); /* Is it the only driver available? */ if (SB_LIST_ITEM_NEXT(&(drv->listitem)) == SB_LIST_ITEM_PREV(&(drv->listitem))) log_text(LOG_INFO, "No DB drivers specified, using %s", drv->sname); else { log_text(LOG_FATAL, "Multiple DB drivers are available. " "Use --db-driver=name to specify which one to use"); goto err; } } else { if (name == NULL) name = db_globals.driver; SB_LIST_FOR_EACH(pos, &drivers) { tmp = SB_LIST_ENTRY(pos, db_driver_t, listitem); if (!strcmp(tmp->sname, name)) { drv = tmp; break; } } } if (drv == NULL) { log_text(LOG_FATAL, "invalid database driver name: '%s'", name); goto err; } /* Initialize database driver only once */ pthread_mutex_lock(&drv->mutex); if (!drv->initialized) { if (drv->ops.init()) { pthread_mutex_unlock(&drv->mutex); goto err; } drv->initialized = true; } pthread_mutex_unlock(&drv->mutex); if (drv->ops.thread_init != NULL && drv->ops.thread_init(sb_tls_thread_id)) { log_text(LOG_FATAL, "thread-local driver initialization failed."); return NULL; } return drv; err: return NULL; } /* Deinitialize a driver object */ int db_destroy(db_driver_t *drv) { if (drv->ops.thread_done != NULL) return drv->ops.thread_done(sb_tls_thread_id); return 0; } /* Describe database capabilities */ int db_describe(db_driver_t *drv, drv_caps_t *caps) { if (drv->ops.describe == NULL) return 1; return drv->ops.describe(caps); } /* Connect to database */ db_conn_t *db_connection_create(db_driver_t *drv) { db_conn_t *con; SB_COMPILE_TIME_ASSERT(sizeof(db_conn_t) % CK_MD_CACHELINE == 0); con = (db_conn_t *)calloc(1, sizeof(db_conn_t)); if (con == NULL) return NULL; con->driver = drv; con->state = DB_CONN_READY; con->thread_id = sb_tls_thread_id; if (drv->ops.connect(con)) { free(con); return NULL; } return con; } /* Disconnect from database */ int db_connection_close(db_conn_t *con) { int rc; db_driver_t *drv = con->driver; if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to close an already closed connection"); return 0; } else if (con->state == DB_CONN_RESULT_SET) { db_free_results_int(con); } rc = drv->ops.disconnect(con); con->state = DB_CONN_INVALID; return rc; } /* Reconnect with the same connection parameters */ int db_connection_reconnect(db_conn_t *con) { int rc; db_driver_t *drv = con->driver; if (drv->ops.reconnect == NULL) { log_text(LOG_ALERT, "reconnect is not supported by the current driver"); return 0; } if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to close an already closed connection"); return 0; } else if (con->state == DB_CONN_RESULT_SET) { db_free_results_int(con); } rc = drv->ops.reconnect(con); if (rc == DB_ERROR_FATAL) { con->state = DB_CONN_INVALID; sb_counter_inc(con->thread_id, SB_CNT_ERROR); } else { con->state = DB_CONN_READY; sb_counter_inc(con->thread_id, SB_CNT_RECONNECT); /* Clear DB_ERROR_IGNORABLE */ rc = DB_ERROR_NONE; } return rc; } /* Disconnect and release memory allocated by a connection object */ void db_connection_free(db_conn_t *con) { if (con->state != DB_CONN_INVALID) db_connection_close(con); free(con); } /* Prepare statement */ db_stmt_t *db_prepare(db_conn_t *con, const char *query, size_t len) { db_stmt_t *stmt; if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return NULL; } stmt = (db_stmt_t *)calloc(1, sizeof(db_stmt_t)); if (stmt == NULL) return NULL; stmt->connection = con; if (con->driver->ops.prepare(stmt, query, len)) { con->error = DB_ERROR_FATAL; free(stmt); return NULL; } return stmt; } /* Bind parameters for prepared statement */ int db_bind_param(db_stmt_t *stmt, db_bind_t *params, size_t len) { db_conn_t *con = stmt->connection; if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return 1; } return con->driver->ops.bind_param(stmt, params, len); } /* Bind results for prepared statement */ int db_bind_result(db_stmt_t *stmt, db_bind_t *results, size_t len) { db_conn_t *con = stmt->connection; if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return 1; } return con->driver->ops.bind_result(stmt, results, len); } /* Execute prepared statement */ db_result_t *db_execute(db_stmt_t *stmt) { db_conn_t *con = stmt->connection; db_result_t *rs = &con->rs; int rc; if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return NULL; } else if (con->state == DB_CONN_RESULT_SET && (rc = db_free_results_int(con)) != 0) { return NULL; } rs->statement = stmt; con->error = con->driver->ops.execute(stmt, rs); sb_counter_inc(con->thread_id, rs->counter); if (SB_LIKELY(con->error == DB_ERROR_NONE)) { if (rs->counter == SB_CNT_READ) { con->state = DB_CONN_RESULT_SET; return rs; } con->state = DB_CONN_READY; return NULL; } return NULL; } /* Retrieve the next result of a prepared statement */ db_result_t *db_stmt_next_result(db_stmt_t *stmt) { db_conn_t *con = stmt->connection; db_result_t *rs = &con->rs; int rc; if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return NULL; } else if (con->state == DB_CONN_RESULT_SET && (rc = db_free_results_int(con)) != 0) { return NULL; } rs->statement = stmt; if (con->driver->ops.stmt_next_result == NULL) { con->error = DB_ERROR_NONE; return NULL; } con->error = con->driver->ops.stmt_next_result(stmt, rs); sb_counter_inc(con->thread_id, rs->counter); if (SB_LIKELY(con->error == DB_ERROR_NONE)) { if (rs->counter == SB_CNT_READ) { con->state = DB_CONN_RESULT_SET; return rs; } con->state = DB_CONN_READY; return NULL; } return NULL; } /* Fetch row from result set of a query */ db_row_t *db_fetch_row(db_result_t *rs) { db_conn_t *con = SB_CONTAINER_OF(rs, db_conn_t, rs); if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return NULL; } else if (con->state != DB_CONN_RESULT_SET) { log_text(LOG_ALERT, "attempt to fetch row from an invalid result set"); return NULL; } if (con->driver->ops.fetch_row == NULL) { log_text(LOG_ALERT, "fetching rows is not supported by the driver"); } if (rs->nrows == 0 || rs->nfields == 0) { log_text(LOG_ALERT, "attempt to fetch row from an empty result set"); return NULL; } if (rs->row.values == NULL) { rs->row.values = malloc(rs->nfields * sizeof(db_value_t)); } if (con->driver->ops.fetch_row(rs, &rs->row)) { return NULL; } return &rs->row; } /* Execute non-prepared statement */ db_result_t *db_query(db_conn_t *con, const char *query, size_t len) { db_result_t *rs = &con->rs; int rc; if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); con->error = DB_ERROR_FATAL; return NULL; } else if (con->state == DB_CONN_RESULT_SET && (rc = db_free_results_int(con)) != 0) { con->error = DB_ERROR_FATAL; return NULL; } con->error = con->driver->ops.query(con, query, len, rs); sb_counter_inc(con->thread_id, rs->counter); if (SB_LIKELY(con->error == DB_ERROR_NONE)) { if (rs->counter == SB_CNT_READ) { con->state = DB_CONN_RESULT_SET; return rs; } con->state = DB_CONN_READY; return NULL; } return NULL; } /* Check if more result sets are available */ bool db_more_results(db_conn_t *con) { if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return false; } if (con->state != DB_CONN_RESULT_SET || con->driver->ops.more_results == NULL || con->driver->ops.more_results(con) == false) return false; return true; } /* Retrieve the next result set */ db_result_t *db_next_result(db_conn_t *con) { db_result_t *rs = &con->rs; int rc; if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); con->error = DB_ERROR_FATAL; return NULL; } else if (con->state == DB_CONN_RESULT_SET && (rc = db_free_results_int(con)) != 0) { con->error = DB_ERROR_FATAL; return NULL; } if (con->driver->ops.next_result == NULL) { con->error = DB_ERROR_NONE; return NULL; } con->error = con->driver->ops.next_result(con, rs); sb_counter_inc(con->thread_id, rs->counter); if (SB_LIKELY(con->error == DB_ERROR_NONE)) { if (rs->counter == SB_CNT_READ) { con->state = DB_CONN_RESULT_SET; return rs; } con->state = DB_CONN_READY; } return NULL; } /* Free result set */ static int db_free_results_int(db_conn_t *con) { int rc; rc = con->driver->ops.free_results(&con->rs); if (con->rs.row.values != NULL) { free(con->rs.row.values); con->rs.row.values = NULL; } con->rs.nrows = 0; con->rs.nfields = 0; con->rs.statement = NULL; con->state = DB_CONN_READY; return rc; } int db_free_results(db_result_t *rs) { db_conn_t * const con = SB_CONTAINER_OF(rs, db_conn_t, rs); if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return 1; } else if (con->state != DB_CONN_RESULT_SET) { log_text(LOG_ALERT, "attempt to free an invalid result set"); return 1; } return db_free_results_int(con); } /* Close prepared statement */ int db_close(db_stmt_t *stmt) { int rc; db_conn_t *con = stmt->connection; if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return 0; } else if (con->state == DB_CONN_RESULT_SET && (rc = db_free_results_int(con)) != 0) { return DB_ERROR_FATAL; } if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return 0; } else if (con->state == DB_CONN_RESULT_SET && con->rs.statement == stmt && (rc = db_free_results_int(con)) != 0) { return 0; } rc = con->driver->ops.close(stmt); if (stmt->query != NULL) { free(stmt->query); stmt->query = NULL; } if (stmt->bound_param != NULL) { free(stmt->bound_param); stmt->bound_param = NULL; } free(stmt); return rc; } /* Uninitialize DB API */ void db_done(void) { sb_list_item_t *pos; db_driver_t *drv; if (!db_global_initialized) return; disable_print_stats(); if (db_globals.debug) { free(exec_timers); free(fetch_timers); exec_timers = fetch_timers = NULL; } SB_LIST_FOR_EACH(pos, &drivers) { drv = SB_LIST_ENTRY(pos, db_driver_t, listitem); if (drv->initialized) { drv->ops.done(); pthread_mutex_destroy(&drv->mutex); } } return; } /* Parse command line arguments */ int db_parse_arguments(void) { char *s; s = sb_get_value_string("db-ps-mode"); if (!strcmp(s, "auto")) db_globals.ps_mode = DB_PS_MODE_AUTO; else if (!strcmp(s, "disable")) db_globals.ps_mode = DB_PS_MODE_DISABLE; else { log_text(LOG_FATAL, "Invalid value for db-ps-mode: %s", s); return 1; } db_globals.driver = sb_get_value_string("db-driver"); db_globals.debug = sb_get_value_flag("db-debug"); return 0; } /* Produce character representation of a 'bind' variable */ int db_print_value(db_bind_t *var, char *buf, int buflen) { int n; db_time_t *tm; if (var->is_null != NULL && *var->is_null) { n = snprintf(buf, buflen, "NULL"); return (n < buflen) ? n : -1; } switch (var->type) { case DB_TYPE_TINYINT: n = snprintf(buf, buflen, "%hhd", *(char *)var->buffer); break; case DB_TYPE_SMALLINT: n = snprintf(buf, buflen, "%hd", *(short *)var->buffer); break; case DB_TYPE_INT: n = snprintf(buf, buflen, "%d", *(int *)var->buffer); break; case DB_TYPE_BIGINT: n = snprintf(buf, buflen, "%lld", *(long long *)var->buffer); break; case DB_TYPE_FLOAT: n = snprintf(buf, buflen, "%f", *(float *)var->buffer); break; case DB_TYPE_DOUBLE: n = snprintf(buf, buflen, "%f", *(double *)var->buffer); break; case DB_TYPE_CHAR: case DB_TYPE_VARCHAR: n = snprintf(buf, buflen, "'%s'", (char *)var->buffer); break; case DB_TYPE_DATE: tm = (db_time_t *)var->buffer; n = snprintf(buf, buflen, "'%d-%d-%d'", tm->year, tm->month, tm->day); break; case DB_TYPE_TIME: tm = (db_time_t *)var->buffer; n = snprintf(buf, buflen, "'%d:%d:%d'", tm->hour, tm->minute, tm->second); break; case DB_TYPE_DATETIME: case DB_TYPE_TIMESTAMP: tm = (db_time_t *)var->buffer; n = snprintf(buf, buflen, "'%d-%d-%d %d:%d:%d'", tm->year, tm->month, tm->day, tm->hour, tm->minute, tm->second); break; default: n = 0; break; } return (n < buflen) ? n : -1; } #if 0 /* Free row fetched by db_fetch_row() */ void db_free_row(db_row_t *row) { free(row); } #endif /* Initialize multi-row insert operation */ int db_bulk_insert_init(db_conn_t *con, const char *query, size_t query_len) { drv_caps_t driver_caps; int rc; if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return 0; } else if (con->state == DB_CONN_RESULT_SET && (rc = db_free_results_int(con)) != 0) { return 0; } /* Get database capabilites */ if (db_describe(con->driver, &driver_caps)) { log_text(LOG_FATAL, "failed to get database capabilities!"); return 1; } /* Allocate query buffer */ if (query_len + 1 > BULK_PACKET_SIZE) { log_text(LOG_FATAL, "Query length exceeds the maximum value (%u), aborting", BULK_PACKET_SIZE); return 1; } con->bulk_buflen = BULK_PACKET_SIZE; con->bulk_buffer = (char *)malloc(con->bulk_buflen); if (con->bulk_buffer == NULL) return 1; con->bulk_commit_max = driver_caps.needs_commit ? ROWS_BEFORE_COMMIT : 0; con->bulk_commit_cnt = 0; strcpy(con->bulk_buffer, query); con->bulk_ptr = query_len; con->bulk_values = query_len; con->bulk_cnt = 0; return 0; } /* Add row to multi-row insert operation */ int db_bulk_insert_next(db_conn_t *con, const char *query, size_t query_len) { int rc; if (con->state == DB_CONN_INVALID) { log_text(LOG_ALERT, "attempt to use an already closed connection"); return 0; } else if (con->state == DB_CONN_RESULT_SET && (rc = db_free_results_int(con)) != 0) { return 0; } if (con->bulk_buffer == NULL) { log_text(LOG_ALERT, "attempt to call bulk_insert_next() before bulk_insert_init()"); return 1; } /* Reserve space for '\0' and ',' (if not the first chunk in a bulk insert */ if (con->bulk_ptr + query_len + 1 + (con->bulk_cnt>0) > con->bulk_buflen) { /* Is this a first row? */ if (!con->bulk_cnt) { log_text(LOG_FATAL, "Query length exceeds the maximum value (%u), aborting", con->bulk_buflen); return 1; } if (db_bulk_do_insert(con, 0)) return 1; } if (con->bulk_cnt > 0) { con->bulk_buffer[con->bulk_ptr] = ','; strcpy(con->bulk_buffer + con->bulk_ptr + 1, query); } else strcpy(con->bulk_buffer + con->bulk_ptr, query); con->bulk_ptr += query_len + (con->bulk_cnt > 0); con->bulk_cnt++; return 0; } /* Do the actual INSERT (and COMMIT, if necessary) */ static int db_bulk_do_insert(db_conn_t *con, int is_last) { if (!con->bulk_cnt) return 0; if (db_query(con, con->bulk_buffer, con->bulk_ptr) == NULL && con->error != DB_ERROR_NONE) return 1; if (con->bulk_commit_max != 0) { con->bulk_commit_cnt += con->bulk_cnt; if (is_last || con->bulk_commit_cnt >= con->bulk_commit_max) { if (db_query(con, "COMMIT", 6) == NULL && con->error != DB_ERROR_NONE) return 1; con->bulk_commit_cnt = 0; } } con->bulk_ptr = con->bulk_values; con->bulk_cnt = 0; return 0; } /* Finish multi-row insert operation */ int db_bulk_insert_done(db_conn_t *con) { /* Flush remaining data in buffer, if any */ if (db_bulk_do_insert(con, 1)) return 1; if (con->bulk_buffer != NULL) { free(con->bulk_buffer); con->bulk_buffer = NULL; } return 0; } void db_report_intermediate(sb_stat_t *stat) { /* Use default stats handler if no drivers are used */ if (!check_print_stats()) { sb_report_intermediate(stat); return; } const double seconds = stat->time_interval; log_timestamp(LOG_NOTICE, stat->time_total, "thds: %u tps: %4.2f " "qps: %4.2f (r/w/o: %4.2f/%4.2f/%4.2f) " "lat (ms,%u%%): %4.2f err/s: %4.2f " "reconn/s: %4.2f", stat->threads_running, stat->events / seconds, (stat->reads + stat->writes + stat->other) / seconds, stat->reads / seconds, stat->writes / seconds, stat->other / seconds, sb_globals.percentile, SEC2MS(stat->latency_pct), stat->errors / seconds, stat->reconnects / seconds); if (sb_globals.tx_rate > 0) { log_timestamp(LOG_NOTICE, stat->time_total, "queue length: %" PRIu64", concurrency: %" PRIu64, stat->queue_length, stat->concurrency); } } void db_report_cumulative(sb_stat_t *stat) { sb_timer_t exec_timer; sb_timer_t fetch_timer; /* Use default stats handler if no drivers are used */ if (!check_print_stats()) { sb_report_cumulative(stat); return; } const double seconds = stat->time_interval; const uint64_t queries = stat->reads + stat->writes + stat->other; log_text(LOG_NOTICE, "SQL statistics:"); log_text(LOG_NOTICE, " queries performed:"); log_text(LOG_NOTICE, " read: %" PRIu64, stat->reads); log_text(LOG_NOTICE, " write: %" PRIu64, stat->writes); log_text(LOG_NOTICE, " other: %" PRIu64, stat->other); log_text(LOG_NOTICE, " total: %" PRIu64, queries); log_text(LOG_NOTICE, " transactions: %-6" PRIu64 " (%.2f per sec.)", stat->events, stat->events / seconds); log_text(LOG_NOTICE, " queries: %-6" PRIu64 " (%.2f per sec.)", queries, queries / seconds); log_text(LOG_NOTICE, " ignored errors: %-6" PRIu64 " (%.2f per sec.)", stat->errors, stat->errors / seconds); log_text(LOG_NOTICE, " reconnects: %-6" PRIu64 " (%.2f per sec.)", stat->reconnects, stat->reconnects / seconds); if (db_globals.debug) { sb_timer_init(&exec_timer); sb_timer_init(&fetch_timer); for (unsigned i = 0; i < sb_globals.threads; i++) { exec_timer = sb_timer_merge(&exec_timer, exec_timers + i); fetch_timer = sb_timer_merge(&fetch_timer, fetch_timers + i); } log_text(LOG_DEBUG, ""); log_text(LOG_DEBUG, "Query execution statistics:"); log_text(LOG_DEBUG, " min: %.4fs", NS2SEC(sb_timer_min(&exec_timer))); log_text(LOG_DEBUG, " avg: %.4fs", NS2SEC(sb_timer_avg(&exec_timer))); log_text(LOG_DEBUG, " max: %.4fs", NS2SEC(sb_timer_max(&exec_timer))); log_text(LOG_DEBUG, " total: %.4fs", NS2SEC(sb_timer_sum(&exec_timer))); log_text(LOG_DEBUG, "Results fetching statistics:"); log_text(LOG_DEBUG, " min: %.4fs", NS2SEC(sb_timer_min(&fetch_timer))); log_text(LOG_DEBUG, " avg: %.4fs", NS2SEC(sb_timer_avg(&fetch_timer))); log_text(LOG_DEBUG, " max: %.4fs", NS2SEC(sb_timer_max(&fetch_timer))); log_text(LOG_DEBUG, " total: %.4fs", NS2SEC(sb_timer_sum(&fetch_timer))); } /* Report sysbench general stats */ sb_report_cumulative(stat); } static void db_reset_stats(void) { unsigned int i; /* So that intermediate stats are calculated from the current moment rather than from the previous intermediate report */ sb_timer_current(&sb_intermediate_timer); if (db_globals.debug) { for (i = 0; i < sb_globals.threads; i++) { sb_timer_init(exec_timers + i); sb_timer_init(fetch_timers + i); } } } ================================================ FILE: src/db_driver.h ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2017 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef DB_DRIVER_H #define DB_DRIVER_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "sysbench.h" #include "sb_list.h" #include "sb_histogram.h" #include "sb_counter.h" /* Prepared statements usage modes */ typedef enum { DB_PS_MODE_AUTO, DB_PS_MODE_DISABLE, } db_ps_mode_t; /* Global DB API options */ typedef struct { db_ps_mode_t ps_mode; /* Requested prepared statements usage mode */ char *driver; /* Requested database driver */ unsigned char debug; /* debug flag */ } db_globals_t; /* Driver capabilities definition */ typedef struct { char multi_rows_insert; /* 1 if database supports multi-row inserts */ char prepared_statements; /* 1 if database supports prepared statements */ char auto_increment; /* 1 if database supports AUTO_INCREMENT clause */ char needs_commit; /* 1 if database needs explicit commit after INSERTs */ char serial; /* 1 if database supports SERIAL clause */ char unsigned_int; /* 1 if database supports UNSIGNED INTEGER types */ } drv_caps_t; /* Database errors definition */ typedef enum { DB_ERROR_NONE, /* no error(s) */ DB_ERROR_IGNORABLE, /* error should be ignored as defined by command line arguments or a custom error handler */ DB_ERROR_FATAL /* non-ignorable error */ } db_error_t; /* Available buffer types (for parameters binding) */ typedef enum { DB_TYPE_NONE, DB_TYPE_TINYINT, DB_TYPE_SMALLINT, DB_TYPE_INT, DB_TYPE_BIGINT, DB_TYPE_FLOAT, DB_TYPE_DOUBLE, DB_TYPE_TIME, DB_TYPE_DATE, DB_TYPE_DATETIME, DB_TYPE_TIMESTAMP, DB_TYPE_CHAR, DB_TYPE_VARCHAR } db_bind_type_t; /* Structure used to represent DATE, TIME, DATETIME and TIMESTAMP values */ typedef struct { unsigned int year; unsigned int month; unsigned int day; unsigned int hour; unsigned int minute; unsigned int second; } db_time_t; /* Structure used to bind data for prepared statements */ typedef struct { db_bind_type_t type; void *buffer; unsigned long *data_len; unsigned long max_len; char *is_null; } db_bind_t; /* Forward declarations */ struct db_conn; struct db_stmt; struct db_result; struct db_row; /* Driver operations definition */ typedef int drv_op_init(void); typedef int drv_op_thread_init(int); typedef int drv_op_describe(drv_caps_t *); typedef int drv_op_connect(struct db_conn *); typedef int drv_op_reconnect(struct db_conn *); typedef int drv_op_disconnect(struct db_conn *); typedef int drv_op_prepare(struct db_stmt *, const char *, size_t); typedef int drv_op_bind_param(struct db_stmt *, db_bind_t *, size_t); typedef int drv_op_bind_result(struct db_stmt *, db_bind_t *, size_t); typedef db_error_t drv_op_execute(struct db_stmt *, struct db_result *); typedef db_error_t drv_op_stmt_next_result(struct db_stmt *, struct db_result *); typedef int drv_op_fetch(struct db_result *); typedef int drv_op_fetch_row(struct db_result *, struct db_row *); typedef db_error_t drv_op_query(struct db_conn *, const char *, size_t, struct db_result *); typedef bool drv_op_more_results(struct db_conn *); typedef db_error_t drv_op_next_result(struct db_conn *, struct db_result *); typedef int drv_op_free_results(struct db_result *); typedef int drv_op_close(struct db_stmt *); typedef int drv_op_thread_done(int); typedef int drv_op_done(void); typedef struct { drv_op_init *init; /* initializate driver */ drv_op_thread_init *thread_init; /* thread-local driver initialization */ drv_op_describe *describe; /* describe database capabilities */ drv_op_connect *connect; /* connect to database */ drv_op_disconnect *disconnect; /* disconnect from database */ drv_op_reconnect *reconnect; /* reconnect with the same parameters */ drv_op_prepare *prepare; /* prepare statement */ drv_op_bind_param *bind_param; /* bind params for prepared statement */ drv_op_bind_result *bind_result; /* bind results for prepared statement */ drv_op_execute *execute; /* execute prepared statement */ /* retrieve the next result of a prepared statement */ drv_op_stmt_next_result *stmt_next_result; drv_op_fetch *fetch; /* fetch row for prepared statement */ drv_op_fetch_row *fetch_row; /* fetch row for queries */ drv_op_free_results *free_results; /* free result set */ drv_op_more_results *more_results; /* check if more result sets are available */ drv_op_next_result *next_result; /* retrieve the next result set */ drv_op_close *close; /* close prepared statement */ drv_op_query *query; /* execute non-prepared statement */ drv_op_thread_done *thread_done; /* thread-local driver deinitialization */ drv_op_done *done; /* uninitialize driver */ } drv_ops_t; /* Database driver definition */ typedef struct { const char *sname; /* short name */ const char *lname; /* long name */ sb_arg_t *args; /* driver command line arguments */ drv_ops_t ops; /* driver operations */ sb_list_item_t listitem; /* can be linked in a list */ bool initialized; pthread_mutex_t mutex; } db_driver_t; /* Row value definition */ typedef struct { uint32_t len; /* Value length */ const char *ptr; /* Value string */ } db_value_t; /* Result set row definition */ typedef struct db_row { void *ptr; /* Driver-specific row data */ db_value_t *values; /* Array of column values */ } db_row_t; /* Result set definition */ typedef struct db_result { sb_counter_type_t counter; /* Statistical counter type */ uint32_t nrows; /* Number of affected rows */ uint32_t nfields; /* Number of fields */ struct db_stmt *statement; /* Pointer to prepared statement (if used) */ void *ptr; /* Pointer to driver-specific data */ db_row_t row; /* Last fetched row */ } db_result_t; typedef enum { DB_CONN_READY, DB_CONN_RESULT_SET, DB_CONN_INVALID } db_conn_state_t; /* Database connection structure */ typedef struct db_conn { db_error_t error; /* Database-independent error code */ int sql_errno; /* Database-specific error code */ const char *sql_state; /* Database-specific SQL state */ const char *sql_errmsg; /* Database-specific error message */ db_driver_t *driver; /* DB driver for this connection */ void *ptr; /* Driver-specific data */ db_result_t rs; /* Result set */ db_conn_state_t state; /* Connection state */ int thread_id; /* Thread this connection belongs to */ unsigned int bulk_cnt; /* Current number of rows in bulk insert buffer */ unsigned int bulk_buflen; /* Current length of bulk_buffer */ char *bulk_buffer; /* Bulk insert query buffer */ unsigned int bulk_ptr; /* Current position in bulk_buffer */ unsigned int bulk_values; /* Save value of bulk_ptr */ unsigned int bulk_commit_cnt; /* Current value of uncommitted rows */ unsigned int bulk_commit_max; /* Maximum value of uncommitted rows */ char pad[SB_CACHELINE_PAD(sizeof(db_error_t) + sizeof(int) + sizeof(void *) + sizeof(void *) + sizeof(void *) + sizeof(void *) + sizeof(db_result_t) + sizeof(db_conn_state_t) + sizeof(int) + sizeof(int) * 2 + sizeof(void *) + sizeof(int) * 4 )]; } db_conn_t; /* Prepared statement definition */ typedef struct db_stmt { db_conn_t *connection; /* Connection which this statement belongs to */ char *query; /* Query string for emulated PS */ db_bind_t *bound_param; /* Array of bound parameters for emulated PS */ unsigned int bound_param_len; /* Length of the bound_param array */ db_bind_t *bound_res; /* Array of bound results for emulated PS */ db_bind_t *bound_res_len; /* Length of the bound_res array */ char emulated; /* Should this statement be emulated? */ void *ptr; /* Pointer to driver-specific data structure */ } db_stmt_t; extern db_globals_t db_globals; /* Database abstraction layer calls */ int db_register(void); void db_print_help(void); db_driver_t *db_create(const char *); int db_destroy(db_driver_t *); int db_describe(db_driver_t *, drv_caps_t *); db_conn_t *db_connection_create(db_driver_t *); int db_connection_close(db_conn_t *); int db_connection_reconnect(db_conn_t *con); void db_connection_free(db_conn_t *con); db_stmt_t *db_prepare(db_conn_t *, const char *, size_t); int db_bind_param(db_stmt_t *, db_bind_t *, size_t); int db_bind_result(db_stmt_t *, db_bind_t *, size_t); db_result_t *db_execute(db_stmt_t *); db_result_t *db_stmt_next_result(db_stmt_t *); db_row_t *db_fetch_row(db_result_t *); db_result_t *db_query(db_conn_t *, const char *, size_t len); int db_free_results(db_result_t *); bool db_more_results(db_conn_t *); db_result_t *db_next_result(db_conn_t *); int db_store_results(db_result_t *); int db_close(db_stmt_t *); void db_done(void); int db_print_value(db_bind_t *, char *, int); /* Initialize multi-row insert operation */ int db_bulk_insert_init(db_conn_t *, const char *, size_t); /* Add row to multi-row insert operation */ int db_bulk_insert_next(db_conn_t *, const char *, size_t); /* Finish multi-row insert operation */ int db_bulk_insert_done(db_conn_t *); /* Print database-specific test stats */ void db_report_intermediate(sb_stat_t *); void db_report_cumulative(sb_stat_t *); /* DB drivers registrars */ #ifdef USE_MYSQL int register_driver_mysql(sb_list_t *); #endif #ifdef USE_PGSQL int register_driver_pgsql(sb_list_t *); #endif #endif /* DB_DRIVER_H */ ================================================ FILE: src/drivers/Makefile.am ================================================ # Copyright (C) 2004 MySQL AB # Copyright (C) 2004-2018 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA if USE_MYSQL MYSQL_DIR = mysql endif if USE_PGSQL PGSQL_DIR = pgsql endif SUBDIRS = $(MYSQL_DIR) $(PGSQL_DIR) ================================================ FILE: src/drivers/mysql/Makefile.am ================================================ # Copyright (C) 2004 MySQL AB # Copyright (C) 2004-2008 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA noinst_LIBRARIES = libsbmysql.a libsbmysql_a_SOURCES = drv_mysql.c libsbmysql_a_CPPFLAGS = $(MYSQL_CFLAGS) $(AM_CPPFLAGS) ================================================ FILE: src/drivers/mysql/drv_mysql.c ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef STDC_HEADERS # include #endif #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include #include #include #include #include "sb_options.h" #include "db_driver.h" #define DEBUG(format, ...) \ do { \ if (SB_UNLIKELY(args.debug != 0)) \ log_text(LOG_DEBUG, format, __VA_ARGS__); \ } while (0) static inline const char *SAFESTR(const char *s) { return s ? s : "(null)"; } #if !defined(MARIADB_BASE_VERSION) && !defined(MARIADB_VERSION_ID) && \ MYSQL_VERSION_ID >= 80001 && MYSQL_VERSION_ID != 80002 /* see https://bugs.mysql.com/?id=87337 */ typedef bool my_bool; #endif /* MySQL driver arguments */ static sb_arg_t mysql_drv_args[] = { SB_OPT("mysql-host", "MySQL server host", "localhost", LIST), SB_OPT("mysql-port", "MySQL server port", "3306", LIST), SB_OPT("mysql-socket", "MySQL socket", NULL, LIST), SB_OPT("mysql-user", "MySQL user", "sbtest", STRING), SB_OPT("mysql-password", "MySQL password", "", STRING), SB_OPT("mysql-db", "MySQL database name", "sbtest", STRING), #ifdef HAVE_MYSQL_OPT_SSL_MODE SB_OPT("mysql-ssl", "SSL mode. This accepts the same values as the " "--ssl-mode option in the MySQL client utilities. Disabled by default", "disabled", STRING), #else SB_OPT("mysql-ssl", "use SSL connections, if available in the client " "library", "off", BOOL), #endif SB_OPT("mysql-ssl-key", "path name of the client private key file", NULL, STRING), SB_OPT("mysql-ssl-ca", "path name of the CA file", NULL, STRING), SB_OPT("mysql-ssl-cert", "path name of the client public key certificate file", NULL, STRING), SB_OPT("mysql-ssl-cipher", "use specific cipher for SSL connections", "", STRING), SB_OPT("mysql-compression", "use compression, if available in the " "client library", "off", BOOL), SB_OPT("mysql-compression-algorithms", "compression algorithms to use", "zlib", STRING), SB_OPT("mysql-debug", "trace all client library calls", "off", BOOL), SB_OPT("mysql-ignore-errors", "list of errors to ignore, or \"all\"", "1213,1020,1205", LIST), SB_OPT("mysql-dry-run", "Dry run, pretend that all MySQL client API " "calls are successful without executing them", "off", BOOL), SB_OPT_END }; typedef struct { sb_list_t *hosts; sb_list_t *ports; sb_list_t *sockets; const char *user; const char *password; const char *db; #ifdef HAVE_MYSQL_OPT_SSL_MODE unsigned int ssl_mode; #endif bool use_ssl; const char *ssl_key; const char *ssl_cert; const char *ssl_ca; const char *ssl_cipher; unsigned char use_compression; #ifdef MYSQL_OPT_COMPRESSION_ALGORITHMS const char *compression_alg; #endif unsigned char debug; sb_list_t *ignored_errors; unsigned int dry_run; } mysql_drv_args_t; typedef struct { MYSQL *mysql; const char *host; const char *user; const char *password; const char *db; unsigned int port; char *socket; } db_mysql_conn_t; #ifdef HAVE_MYSQL_OPT_SSL_MODE typedef struct { const char *name; enum mysql_ssl_mode mode; } ssl_mode_map_t; #endif /* Structure used for DB-to-MySQL bind types map */ typedef struct { db_bind_type_t db_type; int my_type; } db_mysql_bind_map_t; /* DB-to-MySQL bind types map */ db_mysql_bind_map_t db_mysql_bind_map[] = { {DB_TYPE_TINYINT, MYSQL_TYPE_TINY}, {DB_TYPE_SMALLINT, MYSQL_TYPE_SHORT}, {DB_TYPE_INT, MYSQL_TYPE_LONG}, {DB_TYPE_BIGINT, MYSQL_TYPE_LONGLONG}, {DB_TYPE_FLOAT, MYSQL_TYPE_FLOAT}, {DB_TYPE_DOUBLE, MYSQL_TYPE_DOUBLE}, {DB_TYPE_DATETIME, MYSQL_TYPE_DATETIME}, {DB_TYPE_TIMESTAMP, MYSQL_TYPE_TIMESTAMP}, {DB_TYPE_CHAR, MYSQL_TYPE_STRING}, {DB_TYPE_VARCHAR, MYSQL_TYPE_VAR_STRING}, {DB_TYPE_NONE, 0} }; /* MySQL driver capabilities */ static drv_caps_t mysql_drv_caps = { 1, 0, 1, 0, 0, 1 }; static mysql_drv_args_t args; /* driver args */ static char use_ps; /* whether server-side prepared statemens should be used */ /* Positions in the list of hosts/ports/sockets. Protected by pos_mutex */ static sb_list_item_t *hosts_pos; static sb_list_item_t *ports_pos; static sb_list_item_t *sockets_pos; static pthread_mutex_t pos_mutex; #ifdef HAVE_MYSQL_OPT_SSL_MODE #if MYSQL_VERSION_ID < 50711 /* In MySQL 5.6 the only valid SSL mode is SSL_MODE_REQUIRED. Define SSL_MODE_DISABLED to enable the 'disabled' default value for --mysql-ssl */ #define SSL_MODE_DISABLED 1 #endif static ssl_mode_map_t ssl_mode_names[] = { {"DISABLED", SSL_MODE_DISABLED}, #if MYSQL_VERSION_ID >= 50711 {"PREFERRED", SSL_MODE_PREFERRED}, #endif {"REQUIRED", SSL_MODE_REQUIRED}, #if MYSQL_VERSION_ID >= 50711 {"VERIFY_CA", SSL_MODE_VERIFY_CA}, {"VERIFY_IDENTITY", SSL_MODE_VERIFY_IDENTITY}, #endif {NULL, 0} }; #endif /* MySQL driver operations */ static int mysql_drv_init(void); static int mysql_drv_thread_init(int); static int mysql_drv_describe(drv_caps_t *); static int mysql_drv_connect(db_conn_t *); static int mysql_drv_reconnect(db_conn_t *); static int mysql_drv_disconnect(db_conn_t *); static int mysql_drv_prepare(db_stmt_t *, const char *, size_t); static int mysql_drv_bind_param(db_stmt_t *, db_bind_t *, size_t); static int mysql_drv_bind_result(db_stmt_t *, db_bind_t *, size_t); static db_error_t mysql_drv_execute(db_stmt_t *, db_result_t *); static db_error_t mysql_drv_stmt_next_result(db_stmt_t *, db_result_t *); static int mysql_drv_fetch(db_result_t *); static int mysql_drv_fetch_row(db_result_t *, db_row_t *); static db_error_t mysql_drv_query(db_conn_t *, const char *, size_t, db_result_t *); static bool mysql_drv_more_results(db_conn_t *); static db_error_t mysql_drv_next_result(db_conn_t *, db_result_t *); static int mysql_drv_free_results(db_result_t *); static int mysql_drv_close(db_stmt_t *); static int mysql_drv_thread_done(int); static int mysql_drv_done(void); /* MySQL driver definition */ static db_driver_t mysql_driver = { .sname = "mysql", .lname = "MySQL driver", .args = mysql_drv_args, .ops = { .init = mysql_drv_init, .thread_init = mysql_drv_thread_init, .describe = mysql_drv_describe, .connect = mysql_drv_connect, .disconnect = mysql_drv_disconnect, .reconnect = mysql_drv_reconnect, .prepare = mysql_drv_prepare, .bind_param = mysql_drv_bind_param, .bind_result = mysql_drv_bind_result, .execute = mysql_drv_execute, .stmt_next_result = mysql_drv_stmt_next_result, .fetch = mysql_drv_fetch, .fetch_row = mysql_drv_fetch_row, .more_results = mysql_drv_more_results, .next_result = mysql_drv_next_result, .free_results = mysql_drv_free_results, .close = mysql_drv_close, .query = mysql_drv_query, .thread_done = mysql_drv_thread_done, .done = mysql_drv_done } }; /* Local functions */ static int get_mysql_bind_type(db_bind_type_t); /* Register MySQL driver */ int register_driver_mysql(sb_list_t *drivers) { SB_LIST_ADD_TAIL(&mysql_driver.listitem, drivers); return 0; } /* MySQL driver initialization */ int mysql_drv_init(void) { pthread_mutex_init(&pos_mutex, NULL); args.hosts = sb_get_value_list("mysql-host"); if (SB_LIST_IS_EMPTY(args.hosts)) { log_text(LOG_FATAL, "No MySQL hosts specified, aborting"); return 1; } hosts_pos = SB_LIST_ITEM_NEXT(args.hosts); args.ports = sb_get_value_list("mysql-port"); if (SB_LIST_IS_EMPTY(args.ports)) { log_text(LOG_FATAL, "No MySQL ports specified, aborting"); return 1; } ports_pos = SB_LIST_ITEM_NEXT(args.ports); args.sockets = sb_get_value_list("mysql-socket"); sockets_pos = args.sockets; args.user = sb_get_value_string("mysql-user"); args.password = sb_get_value_string("mysql-password"); args.db = sb_get_value_string("mysql-db"); args.ssl_cipher = sb_get_value_string("mysql-ssl-cipher"); args.ssl_key = sb_get_value_string("mysql-ssl-key"); args.ssl_cert = sb_get_value_string("mysql-ssl-cert"); args.ssl_ca = sb_get_value_string("mysql-ssl-ca"); #ifdef HAVE_MYSQL_OPT_SSL_MODE const char * const ssl_mode_string = sb_get_value_string("mysql-ssl"); args.ssl_mode = 0; for (int i = 0; ssl_mode_names[i].name != NULL; i++) { if (!strcasecmp(ssl_mode_string, ssl_mode_names[i].name)) { args.ssl_mode = ssl_mode_names[i].mode; break; } } if (args.ssl_mode == 0) { log_text(LOG_FATAL, "Invalid value for --mysql-ssl: '%s'", ssl_mode_string); return 1; } args.use_ssl = (args.ssl_mode != SSL_MODE_DISABLED); #else args.use_ssl = sb_get_value_flag("mysql-ssl"); #endif args.use_compression = sb_get_value_flag("mysql-compression"); #ifdef MYSQL_OPT_COMPRESSION_ALGORITHMS args.compression_alg = sb_get_value_string("mysql-compression-algorithms"); #endif args.debug = sb_get_value_flag("mysql-debug"); if (args.debug) sb_globals.verbosity = LOG_DEBUG; args.ignored_errors = sb_get_value_list("mysql-ignore-errors"); args.dry_run = sb_get_value_flag("mysql-dry-run"); use_ps = 0; mysql_drv_caps.prepared_statements = 1; if (db_globals.ps_mode != DB_PS_MODE_DISABLE) use_ps = 1; DEBUG("mysql_library_init(%d, %p, %p)", 0, NULL, NULL); mysql_library_init(0, NULL, NULL); return 0; } /* Thread-local driver initialization */ int mysql_drv_thread_init(int thread_id) { (void) thread_id; /* unused */ const my_bool rc = mysql_thread_init(); DEBUG("mysql_thread_init() = %d", (int) rc); return rc != 0; } /* Thread-local driver deinitialization */ int mysql_drv_thread_done(int thread_id) { (void) thread_id; /* unused */ DEBUG("mysql_thread_end(%s)", ""); mysql_thread_end(); return 0; } /* Describe database capabilities */ int mysql_drv_describe(drv_caps_t *caps) { *caps = mysql_drv_caps; return 0; } static int mysql_drv_real_connect(db_mysql_conn_t *db_mysql_con) { MYSQL *con = db_mysql_con->mysql; #ifdef HAVE_MYSQL_OPT_SSL_MODE DEBUG("mysql_options(%p,%s,%d)", con, "MYSQL_OPT_SSL_MODE", args.ssl_mode); mysql_options(con, MYSQL_OPT_SSL_MODE, &args.ssl_mode); #endif if (args.use_ssl) { DEBUG("mysql_ssl_set(%p, \"%s\", \"%s\", \"%s\", NULL, \"%s\")", con, SAFESTR(args.ssl_key), SAFESTR(args.ssl_cert), SAFESTR(args.ssl_ca), SAFESTR(args.ssl_cipher)); mysql_ssl_set(con, args.ssl_key, args.ssl_cert, args.ssl_ca, NULL, args.ssl_cipher); } if (args.use_compression) { DEBUG("mysql_options(%p, %s, %s)",con, "MYSQL_OPT_COMPRESS", "NULL"); mysql_options(con, MYSQL_OPT_COMPRESS, NULL); #ifdef MYSQL_OPT_COMPRESSION_ALGORITHMS DEBUG("mysql_options(%p, %s, %s)",con, "MYSQL_OPT_COMPRESSION_ALGORITHMS", args.compression_alg); mysql_options(con, MYSQL_OPT_COMPRESSION_ALGORITHMS, args.compression_alg); #endif } DEBUG("mysql_real_connect(%p, \"%s\", \"%s\", \"%s\", \"%s\", %u, \"%s\", %s)", con, SAFESTR(db_mysql_con->host), SAFESTR(db_mysql_con->user), SAFESTR(db_mysql_con->password), SAFESTR(db_mysql_con->db), db_mysql_con->port, SAFESTR(db_mysql_con->socket), (MYSQL_VERSION_ID >= 50000) ? "CLIENT_MULTI_STATEMENTS" : "0" ); return mysql_real_connect(con, db_mysql_con->host, db_mysql_con->user, db_mysql_con->password, db_mysql_con->db, db_mysql_con->port, db_mysql_con->socket, #if MYSQL_VERSION_ID >= 50000 CLIENT_MULTI_STATEMENTS #else 0 #endif ) == NULL; } /* Connect to MySQL database */ int mysql_drv_connect(db_conn_t *sb_conn) { MYSQL *con; db_mysql_conn_t *db_mysql_con; if (args.dry_run) return 0; db_mysql_con = (db_mysql_conn_t *) calloc(1, sizeof(db_mysql_conn_t)); if (db_mysql_con == NULL) return 1; con = (MYSQL *) malloc(sizeof(MYSQL)); if (con == NULL) return 1; db_mysql_con->mysql = con; DEBUG("mysql_init(%p)", con); mysql_init(con); pthread_mutex_lock(&pos_mutex); if (SB_LIST_IS_EMPTY(args.sockets)) { db_mysql_con->socket = NULL; db_mysql_con->host = SB_LIST_ENTRY(hosts_pos, value_t, listitem)->data; db_mysql_con->port = atoi(SB_LIST_ENTRY(ports_pos, value_t, listitem)->data); /* Pick the next port in args.ports. If there are no more ports in the list, move to the next available host and get the first port again. */ ports_pos = SB_LIST_ITEM_NEXT(ports_pos); if (ports_pos == args.ports) { hosts_pos = SB_LIST_ITEM_NEXT(hosts_pos); if (hosts_pos == args.hosts) hosts_pos = SB_LIST_ITEM_NEXT(hosts_pos); ports_pos = SB_LIST_ITEM_NEXT(ports_pos); } } else { db_mysql_con->host = "localhost"; /* The sockets list may be empty. So unlike hosts/ports the loop invariant here is that sockets_pos points to the previous one and should be advanced before using it, not after. */ sockets_pos = SB_LIST_ITEM_NEXT(sockets_pos); if (sockets_pos == args.sockets) sockets_pos = SB_LIST_ITEM_NEXT(sockets_pos); db_mysql_con->socket = SB_LIST_ENTRY(sockets_pos, value_t, listitem)->data; } pthread_mutex_unlock(&pos_mutex); db_mysql_con->user = args.user; db_mysql_con->password = args.password; db_mysql_con->db = args.db; if (mysql_drv_real_connect(db_mysql_con)) { if (!SB_LIST_IS_EMPTY(args.sockets)) log_text(LOG_FATAL, "unable to connect to MySQL server on socket '%s', " "aborting...", db_mysql_con->socket); else log_text(LOG_FATAL, "unable to connect to MySQL server on host '%s', " "port %u, aborting...", db_mysql_con->host, db_mysql_con->port); log_text(LOG_FATAL, "error %d: %s", mysql_errno(con), mysql_error(con)); free(db_mysql_con); free(con); return 1; } if (args.use_ssl) { DEBUG("mysql_get_ssl_cipher(con): \"%s\"", SAFESTR(mysql_get_ssl_cipher(con))); } sb_conn->ptr = db_mysql_con; return 0; } /* Disconnect from MySQL database */ int mysql_drv_disconnect(db_conn_t *sb_conn) { db_mysql_conn_t *db_mysql_con = sb_conn->ptr; if (args.dry_run) return 0; if (db_mysql_con != NULL && db_mysql_con->mysql != NULL) { DEBUG("mysql_close(%p)", db_mysql_con->mysql); mysql_close(db_mysql_con->mysql); free(db_mysql_con->mysql); free(db_mysql_con); } return 0; } /* Prepare statement */ int mysql_drv_prepare(db_stmt_t *stmt, const char *query, size_t len) { MYSQL_STMT *mystmt; unsigned int rc; if (args.dry_run) return 0; db_mysql_conn_t *db_mysql_con = (db_mysql_conn_t *) stmt->connection->ptr; MYSQL *con = db_mysql_con->mysql; if (con == NULL) return 1; if (use_ps) { mystmt = mysql_stmt_init(con); DEBUG("mysql_stmt_init(%p) = %p", con, mystmt); if (mystmt == NULL) { log_text(LOG_FATAL, "mysql_stmt_init() failed"); return 1; } stmt->ptr = (void *)mystmt; DEBUG("mysql_stmt_prepare(%p, \"%s\", %u) = %p", mystmt, query, (unsigned int) len, stmt->ptr); if (mysql_stmt_prepare(mystmt, query, len)) { /* Check if this statement in not supported */ rc = mysql_errno(con); DEBUG("mysql_errno(%p) = %u", con, rc); if (rc == ER_UNSUPPORTED_PS) { log_text(LOG_INFO, "Failed to prepare query \"%s\" (%d: %s), using emulation", query, rc, mysql_error(con)); goto emulate; } else { log_text(LOG_FATAL, "mysql_stmt_prepare() failed"); log_text(LOG_FATAL, "MySQL error: %d \"%s\"", rc, mysql_error(con)); DEBUG("mysql_stmt_close(%p)", mystmt); mysql_stmt_close(mystmt); return 1; } } stmt->query = strdup(query); return 0; } emulate: /* Use client-side PS */ stmt->emulated = 1; stmt->query = strdup(query); return 0; } static void convert_to_mysql_bind(MYSQL_BIND *mybind, db_bind_t *bind) { mybind->buffer_type = get_mysql_bind_type(bind->type); mybind->buffer = bind->buffer; mybind->buffer_length = bind->max_len; mybind->length = bind->data_len; /* Reuse the buffer passed by the caller to avoid conversions. This is only valid if sizeof(char) == sizeof(mybind->is_null[0]). Depending on the version of the MySQL client library, the type of MYSQL_BIND::is_null[0] can be either my_bool or bool, but sizeof(bool) is not defined by the C standard. We assume it to be 1 on most platforms to simplify code and Lua API. */ #if SIZEOF_BOOL > 1 # error This code assumes sizeof(bool) == 1! #endif mybind->is_null = (my_bool *) bind->is_null; } /* Bind parameters for prepared statement */ int mysql_drv_bind_param(db_stmt_t *stmt, db_bind_t *params, size_t len) { MYSQL_BIND *bind; unsigned int i; my_bool rc; unsigned long param_count; if (args.dry_run) return 0; db_mysql_conn_t *db_mysql_con = (db_mysql_conn_t *) stmt->connection->ptr; MYSQL *con = db_mysql_con->mysql; if (con == NULL) return 1; if (!stmt->emulated) { if (stmt->ptr == NULL) return 1; /* Validate parameters count */ param_count = mysql_stmt_param_count(stmt->ptr); DEBUG("mysql_stmt_param_count(%p) = %lu", stmt->ptr, param_count); if (param_count != len) { log_text(LOG_FATAL, "Wrong number of parameters to mysql_stmt_bind_param"); return 1; } /* Convert sysbench bind structures to MySQL ones */ bind = (MYSQL_BIND *)calloc(len, sizeof(MYSQL_BIND)); if (bind == NULL) return 1; for (i = 0; i < len; i++) convert_to_mysql_bind(&bind[i], ¶ms[i]); rc = mysql_stmt_bind_param(stmt->ptr, bind); DEBUG("mysql_stmt_bind_param(%p, %p) = %d", stmt->ptr, bind, rc); if (rc) { log_text(LOG_FATAL, "mysql_stmt_bind_param() failed"); log_text(LOG_FATAL, "MySQL error: %d \"%s\"", mysql_errno(con), mysql_error(con)); free(bind); return 1; } free(bind); return 0; } /* Use emulation */ if (stmt->bound_param != NULL) free(stmt->bound_param); stmt->bound_param = (db_bind_t *)malloc(len * sizeof(db_bind_t)); if (stmt->bound_param == NULL) return 1; memcpy(stmt->bound_param, params, len * sizeof(db_bind_t)); stmt->bound_param_len = len; return 0; } /* Bind results for prepared statement */ int mysql_drv_bind_result(db_stmt_t *stmt, db_bind_t *params, size_t len) { MYSQL_BIND *bind; unsigned int i; my_bool rc; if (args.dry_run) return 0; db_mysql_conn_t *db_mysql_con =(db_mysql_conn_t *) stmt->connection->ptr; MYSQL *con = db_mysql_con->mysql; if (con == NULL || stmt->ptr == NULL) return 1; /* Convert sysbench bind structures to MySQL ones */ bind = (MYSQL_BIND *)calloc(len, sizeof(MYSQL_BIND)); if (bind == NULL) return 1; for (i = 0; i < len; i++) convert_to_mysql_bind(&bind[i], ¶ms[i]); rc = mysql_stmt_bind_result(stmt->ptr, bind); DEBUG("mysql_stmt_bind_result(%p, %p) = %d", stmt->ptr, bind, rc); if (rc) { free(bind); return 1; } free(bind); return 0; } /* Reset connection to the server by reconnecting with the same parameters. */ static int mysql_drv_reconnect(db_conn_t *sb_con) { db_mysql_conn_t *db_mysql_con = (db_mysql_conn_t *) sb_con->ptr; MYSQL *con = db_mysql_con->mysql; log_text(LOG_DEBUG, "Reconnecting"); DEBUG("mysql_close(%p)", con); mysql_close(con); while (mysql_drv_real_connect(db_mysql_con)) { if (sb_globals.error) return DB_ERROR_FATAL; usleep(1000); } log_text(LOG_DEBUG, "Reconnected"); return DB_ERROR_IGNORABLE; } /* Check if the error in a given connection should be fatal or ignored according to the list of errors in --mysql-ignore-errors. */ static db_error_t check_error(db_conn_t *sb_con, const char *func, const char *query, sb_counter_type_t *counter) { sb_list_item_t *pos; unsigned int tmp; db_mysql_conn_t *db_mysql_con = (db_mysql_conn_t *) sb_con->ptr; MYSQL *con = db_mysql_con->mysql; const unsigned int error = mysql_errno(con); DEBUG("mysql_errno(%p) = %u", con, sb_con->sql_errno); sb_con->sql_errno = (int) error; sb_con->sql_state = mysql_sqlstate(con); DEBUG("mysql_state(%p) = %s", con, SAFESTR(sb_con->sql_state)); sb_con->sql_errmsg = mysql_error(con); DEBUG("mysql_error(%p) = %s", con, SAFESTR(sb_con->sql_errmsg)); /* Check if the error code is specified in --mysql-ignore-errors, and return DB_ERROR_IGNORABLE if so, or DB_ERROR_FATAL otherwise */ SB_LIST_FOR_EACH(pos, args.ignored_errors) { const char *val = SB_LIST_ENTRY(pos, value_t, listitem)->data; tmp = (unsigned int) atoi(val); if (error == tmp || !strcmp(val, "all")) { log_text(LOG_DEBUG, "Ignoring error %u %s, ", error, sb_con->sql_errmsg); /* Check if we should reconnect */ switch (error) { case CR_SERVER_LOST: case CR_SERVER_GONE_ERROR: case CR_TCP_CONNECTION: case CR_SERVER_LOST_EXTENDED: *counter = SB_CNT_RECONNECT; return mysql_drv_reconnect(sb_con); default: break; } *counter = SB_CNT_ERROR; return DB_ERROR_IGNORABLE; } } if (query) log_text(LOG_FATAL, "%s returned error %u (%s) for query '%s'", func, error, sb_con->sql_errmsg, query); else log_text(LOG_FATAL, "%s returned error %u (%s)", func, error, sb_con->sql_errmsg); *counter = SB_CNT_ERROR; return DB_ERROR_FATAL; } /* Execute prepared statement */ db_error_t mysql_drv_execute(db_stmt_t *stmt, db_result_t *rs) { db_conn_t *con = stmt->connection; char *buf = NULL; unsigned int buflen = 0; unsigned int i, j, vcnt; char need_realloc; int n; if (args.dry_run) return DB_ERROR_NONE; con->sql_errno = 0; con->sql_state = NULL; con->sql_errmsg = NULL; if (!stmt->emulated) { if (stmt->ptr == NULL) { log_text(LOG_DEBUG, "ERROR: exiting mysql_drv_execute(), uninitialized statement"); return DB_ERROR_FATAL; } int err = mysql_stmt_execute(stmt->ptr); DEBUG("mysql_stmt_execute(%p) = %d", stmt->ptr, err); if (err) return check_error(con, "mysql_stmt_execute()", stmt->query, &rs->counter); err = mysql_stmt_store_result(stmt->ptr); DEBUG("mysql_stmt_store_result(%p) = %d", stmt->ptr, err); if (err) return check_error(con, "mysql_stmt_store_result()", NULL, &rs->counter); if (mysql_stmt_errno(stmt->ptr) == 0 && mysql_stmt_field_count(stmt->ptr) == 0) { rs->nrows = (uint32_t) mysql_stmt_affected_rows(stmt->ptr); DEBUG("mysql_stmt_affected_rows(%p) = %u", stmt->ptr, (unsigned) rs->nrows); rs->counter = (rs->nrows > 0) ? SB_CNT_WRITE : SB_CNT_OTHER; return DB_ERROR_NONE; } rs->counter = SB_CNT_READ; rs->nrows = (uint32_t) mysql_stmt_num_rows(stmt->ptr); DEBUG("mysql_stmt_num_rows(%p) = %u", rs->statement->ptr, (unsigned) (rs->nrows)); rs->nfields = (uint32_t) mysql_stmt_field_count(stmt->ptr); DEBUG("mysql_stmt_field_count(%p) = %u", rs->statement->ptr, (unsigned) (rs->nfields)); return DB_ERROR_NONE; } /* Use emulation */ /* Build the actual query string from parameters list */ need_realloc = 1; vcnt = 0; for (i = 0, j = 0; stmt->query[i] != '\0'; i++) { again: if (j+1 >= buflen || need_realloc) { buflen = (buflen > 0) ? buflen * 2 : 256; buf = realloc(buf, buflen); if (buf == NULL) { log_text(LOG_DEBUG, "ERROR: exiting mysql_drv_execute(), memory allocation failure"); return DB_ERROR_FATAL; } need_realloc = 0; } if (stmt->query[i] != '?') { buf[j++] = stmt->query[i]; continue; } n = db_print_value(stmt->bound_param + vcnt, buf + j, (int)(buflen - j)); if (n < 0) { need_realloc = 1; goto again; } j += (unsigned int)n; vcnt++; } buf[j] = '\0'; db_error_t rc = mysql_drv_query(con, buf, j, rs); free(buf); return rc; } /* Retrieve the next result of a prepared statement */ db_error_t mysql_drv_stmt_next_result(db_stmt_t *stmt, db_result_t *rs) { db_conn_t *con = stmt->connection; if (args.dry_run) return DB_ERROR_NONE; con->sql_errno = 0; con->sql_state = NULL; con->sql_errmsg = NULL; if (stmt->emulated) return mysql_drv_next_result(con, rs); if (stmt->ptr == NULL) { log_text(LOG_DEBUG, "ERROR: exiting mysql_drv_stmt_next_result(), " "uninitialized statement"); return DB_ERROR_FATAL; } int err = mysql_stmt_next_result(stmt->ptr); DEBUG("mysql_stmt_next_result(%p) = %d", stmt->ptr, err); if (SB_UNLIKELY(err > 0)) return check_error(con, "mysql_drv_stmt_next_result()", stmt->query, &rs->counter); if (err == -1) { rs->counter = SB_CNT_OTHER; return DB_ERROR_NONE; } err = mysql_stmt_store_result(stmt->ptr); DEBUG("mysql_stmt_store_result(%p) = %d", stmt->ptr, err); if (err) return check_error(con, "mysql_stmt_store_result()", NULL, &rs->counter); if (mysql_stmt_errno(stmt->ptr) == 0 && mysql_stmt_field_count(stmt->ptr) == 0) { rs->nrows = (uint32_t) mysql_stmt_affected_rows(stmt->ptr); DEBUG("mysql_stmt_affected_rows(%p) = %u", stmt->ptr, (unsigned) rs->nrows); rs->counter = (rs->nrows > 0) ? SB_CNT_WRITE : SB_CNT_OTHER; return DB_ERROR_NONE; } rs->counter = SB_CNT_READ; rs->nrows = (uint32_t) mysql_stmt_num_rows(stmt->ptr); DEBUG("mysql_stmt_num_rows(%p) = %u", rs->statement->ptr, (unsigned) (rs->nrows)); rs->nfields = (uint32_t) mysql_stmt_field_count(stmt->ptr); DEBUG("mysql_stmt_field_count(%p) = %u", rs->statement->ptr, (unsigned) (rs->nfields)); return DB_ERROR_NONE; } /* Execute SQL query */ db_error_t mysql_drv_query(db_conn_t *sb_conn, const char *query, size_t len, db_result_t *rs) { db_mysql_conn_t *db_mysql_con; MYSQL *con; if (args.dry_run) return DB_ERROR_NONE; sb_conn->sql_errno = 0; sb_conn->sql_state = NULL; sb_conn->sql_errmsg = NULL; db_mysql_con = (db_mysql_conn_t *)sb_conn->ptr; con = db_mysql_con->mysql; int err = mysql_real_query(con, query, len); DEBUG("mysql_real_query(%p, \"%s\", %zd) = %d", con, query, len, err); if (SB_UNLIKELY(err != 0)) return check_error(sb_conn, "mysql_drv_query()", query, &rs->counter); /* Store results and get query type */ MYSQL_RES *res = mysql_store_result(con); DEBUG("mysql_store_result(%p) = %p", con, res); if (res == NULL) { if (mysql_errno(con) == 0 && mysql_field_count(con) == 0) { /* Not a select. Check if it was a DML */ uint32_t nrows = (uint32_t) mysql_affected_rows(con); if (nrows > 0) { rs->counter = SB_CNT_WRITE; rs->nrows = nrows; } else rs->counter = SB_CNT_OTHER; return DB_ERROR_NONE; } return check_error(sb_conn, "mysql_store_result()", NULL, &rs->counter); } rs->counter = SB_CNT_READ; rs->ptr = (void *)res; rs->nrows = mysql_num_rows(res); DEBUG("mysql_num_rows(%p) = %u", res, (unsigned int) rs->nrows); rs->nfields = mysql_num_fields(res); DEBUG("mysql_num_fields(%p) = %u", res, (unsigned int) rs->nfields); return DB_ERROR_NONE; } /* Fetch row from result set of a prepared statement */ int mysql_drv_fetch(db_result_t *rs) { /* NYI */ (void)rs; /* unused */ if (args.dry_run) return DB_ERROR_NONE; return 1; } /* Fetch row from result set of a query */ int mysql_drv_fetch_row(db_result_t *rs, db_row_t *row) { MYSQL_ROW my_row; if (args.dry_run) return DB_ERROR_NONE; my_row = mysql_fetch_row(rs->ptr); DEBUG("mysql_fetch_row(%p) = %p", rs->ptr, my_row); unsigned long *lengths = mysql_fetch_lengths(rs->ptr); DEBUG("mysql_fetch_lengths(%p) = %p", rs->ptr, lengths); if (lengths == NULL) return DB_ERROR_IGNORABLE; for (size_t i = 0; i < rs->nfields; i++) { row->values[i].len = lengths[i]; row->values[i].ptr = my_row[i]; } return DB_ERROR_NONE; } /* Check if more result sets are available */ bool mysql_drv_more_results(db_conn_t *sb_conn) { db_mysql_conn_t *db_mysql_con; MYSQL *con; if (args.dry_run) return false; db_mysql_con = (db_mysql_conn_t *)sb_conn->ptr; con = db_mysql_con->mysql; bool res = mysql_more_results(con); DEBUG("mysql_more_results(%p) = %d", con, res); return res; } /* Retrieve the next result set */ db_error_t mysql_drv_next_result(db_conn_t *sb_conn, db_result_t *rs) { db_mysql_conn_t *db_mysql_con; MYSQL *con; if (args.dry_run) return DB_ERROR_NONE; sb_conn->sql_errno = 0; sb_conn->sql_state = NULL; sb_conn->sql_errmsg = NULL; db_mysql_con = (db_mysql_conn_t *)sb_conn->ptr; con = db_mysql_con->mysql; int err = mysql_next_result(con); DEBUG("mysql_next_result(%p) = %d", con, err); if (SB_UNLIKELY(err > 0)) return check_error(sb_conn, "mysql_drv_next_result()", NULL, &rs->counter); if (err == -1) { rs->counter = SB_CNT_OTHER; return DB_ERROR_NONE; } /* Store results and get query type */ MYSQL_RES *res = mysql_store_result(con); DEBUG("mysql_store_result(%p) = %p", con, res); if (res == NULL) { if (mysql_errno(con) == 0 && mysql_field_count(con) == 0) { /* Not a select. Check if it was a DML */ uint32_t nrows = (uint32_t) mysql_affected_rows(con); if (nrows > 0) { rs->counter = SB_CNT_WRITE; rs->nrows = nrows; } else rs->counter = SB_CNT_OTHER; return DB_ERROR_NONE; } return check_error(sb_conn, "mysql_store_result()", NULL, &rs->counter); } rs->counter = SB_CNT_READ; rs->ptr = (void *)res; rs->nrows = mysql_num_rows(res); DEBUG("mysql_num_rows(%p) = %u", res, (unsigned int) rs->nrows); rs->nfields = mysql_num_fields(res); DEBUG("mysql_num_fields(%p) = %u", res, (unsigned int) rs->nfields); return DB_ERROR_NONE; } /* Free result set */ int mysql_drv_free_results(db_result_t *rs) { if (args.dry_run) return 0; /* Is this a result set of a prepared statement? */ if (rs->statement != NULL && rs->statement->emulated == 0) { DEBUG("mysql_stmt_free_result(%p)", rs->statement->ptr); mysql_stmt_free_result(rs->statement->ptr); rs->ptr = NULL; } if (rs->ptr != NULL) { DEBUG("mysql_free_result(%p)", rs->ptr); mysql_free_result((MYSQL_RES *)rs->ptr); rs->ptr = NULL; } return 0; } /* Close prepared statement */ int mysql_drv_close(db_stmt_t *stmt) { if (args.dry_run) return 0; if (stmt->query) { free(stmt->query); stmt->query = NULL; } if (stmt->ptr == NULL) return 1; int rc = mysql_stmt_close(stmt->ptr); DEBUG("mysql_stmt_close(%p) = %d", stmt->ptr, rc); stmt->ptr = NULL; return rc; } /* Uninitialize driver */ int mysql_drv_done(void) { if (args.dry_run) return 0; mysql_library_end(); return 0; } /* Map SQL data type to bind_type value in MYSQL_BIND */ int get_mysql_bind_type(db_bind_type_t type) { unsigned int i; for (i = 0; db_mysql_bind_map[i].db_type != DB_TYPE_NONE; i++) if (db_mysql_bind_map[i].db_type == type) return db_mysql_bind_map[i].my_type; return -1; } ================================================ FILE: src/drivers/pgsql/Makefile.am ================================================ # Copyright (C) 2005 MySQL AB # Copyright (C) 2005-2015 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA noinst_LIBRARIES = libsbpgsql.a libsbpgsql_a_SOURCES = drv_pgsql.c libsbpgsql_a_CPPFLAGS = -g $(PGSQL_CFLAGS) $(AM_CPPFLAGS) ================================================ FILE: src/drivers/pgsql/drv_pgsql.c ================================================ /* Copyright (C) 2005 MySQL AB Copyright (C) 2005-2017 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include #include "sb_options.h" #include "db_driver.h" #include "sb_rand.h" #define xfree(ptr) ({ if (ptr) free((void *)ptr); ptr = NULL; }) /* Maximum length of text representation of bind parameters */ #define MAX_PARAM_LENGTH 256UL /* PostgreSQL driver arguments */ static sb_arg_t pgsql_drv_args[] = { SB_OPT("pgsql-host", "PostgreSQL server host", "localhost", STRING), SB_OPT("pgsql-port", "PostgreSQL server port", "5432", INT), SB_OPT("pgsql-user", "PostgreSQL user", "sbtest", STRING), SB_OPT("pgsql-password", "PostgreSQL password", "", STRING), SB_OPT("pgsql-db", "PostgreSQL database name", "sbtest", STRING), SB_OPT("pgsql-sslmode", "PostgreSQL SSL mode (disable, allow, prefer, require, verify-ca, verify-full)", "prefer", STRING), SB_OPT_END }; typedef struct { char *host; char *port; char *user; char *password; char *db; } pgsql_drv_args_t; /* Structure used for DB-to-PgSQL bind types map */ typedef struct { db_bind_type_t db_type; int pg_type; } db_pgsql_bind_map_t; /* DB-to-PgSQL bind types map */ db_pgsql_bind_map_t db_pgsql_bind_map[] = { {DB_TYPE_TINYINT, 0}, {DB_TYPE_SMALLINT, 21}, {DB_TYPE_INT, 23}, {DB_TYPE_BIGINT, 20}, {DB_TYPE_FLOAT, 700}, {DB_TYPE_DOUBLE, 701}, {DB_TYPE_DATETIME, 0}, {DB_TYPE_TIMESTAMP, 1114}, {DB_TYPE_CHAR, 18}, {DB_TYPE_VARCHAR, 1043}, {DB_TYPE_NONE, 0} }; /* PgSQL driver capabilities */ static drv_caps_t pgsql_drv_caps = { 1, /* multi_rows_insert */ 1, /* prepared_statements */ 0, /* auto_increment */ 0, /* needs_commit */ 1, /* serial */ 0, /* unsigned int */ }; /* Describes the PostgreSQL prepared statement */ typedef struct pg_stmt { char *name; int prepared; int nparams; Oid *ptypes; char **pvalues; } pg_stmt_t; static pgsql_drv_args_t args; /* driver args */ static char use_ps; /* whether server-side prepared statemens should be used */ /* PgSQL driver operations */ static int pgsql_drv_init(void); static int pgsql_drv_describe(drv_caps_t *); static int pgsql_drv_connect(db_conn_t *); static int pgsql_drv_disconnect(db_conn_t *); static int pgsql_drv_reconnect(db_conn_t *); static int pgsql_drv_prepare(db_stmt_t *, const char *, size_t); static int pgsql_drv_bind_param(db_stmt_t *, db_bind_t *, size_t); static int pgsql_drv_bind_result(db_stmt_t *, db_bind_t *, size_t); static db_error_t pgsql_drv_execute(db_stmt_t *, db_result_t *); static int pgsql_drv_fetch(db_result_t *); static int pgsql_drv_fetch_row(db_result_t *, db_row_t *); static db_error_t pgsql_drv_query(db_conn_t *, const char *, size_t, db_result_t *); static int pgsql_drv_free_results(db_result_t *); static int pgsql_drv_close(db_stmt_t *); static int pgsql_drv_done(void); /* PgSQL driver definition */ static db_driver_t pgsql_driver = { .sname = "pgsql", .lname = "PostgreSQL driver", .args = pgsql_drv_args, .ops = { .init = pgsql_drv_init, .describe = pgsql_drv_describe, .connect = pgsql_drv_connect, .disconnect = pgsql_drv_disconnect, .reconnect = pgsql_drv_reconnect, .prepare = pgsql_drv_prepare, .bind_param = pgsql_drv_bind_param, .bind_result = pgsql_drv_bind_result, .execute = pgsql_drv_execute, .fetch = pgsql_drv_fetch, .fetch_row = pgsql_drv_fetch_row, .free_results = pgsql_drv_free_results, .close = pgsql_drv_close, .query = pgsql_drv_query, .done = pgsql_drv_done } }; /* Local functions */ static int get_pgsql_bind_type(db_bind_type_t); static int get_unique_stmt_name(char *, int); /* Register PgSQL driver */ int register_driver_pgsql(sb_list_t *drivers) { SB_LIST_ADD_TAIL(&pgsql_driver.listitem, drivers); return 0; } /* PgSQL driver initialization */ int pgsql_drv_init(void) { args.host = sb_get_value_string("pgsql-host"); args.port = sb_get_value_string("pgsql-port"); args.user = sb_get_value_string("pgsql-user"); args.password = sb_get_value_string("pgsql-password"); char * dbname = sb_get_value_string("pgsql-db"); char * sslmode = sb_get_value_string("pgsql-sslmode"); args.db = malloc(strlen("dbname= sslmode=") + strlen(dbname) + strlen(sslmode) + 1); sprintf(args.db, "dbname=%s sslmode=%s", dbname, sslmode); use_ps = 0; pgsql_drv_caps.prepared_statements = 1; if (db_globals.ps_mode != DB_PS_MODE_DISABLE) use_ps = 1; return 0; } /* Describe database capabilities */ int pgsql_drv_describe(drv_caps_t *caps) { PGconn *con; *caps = pgsql_drv_caps; /* Determine the server version */ con = PQsetdbLogin(args.host, args.port, NULL, NULL, args.db, args.user, args.password); if (PQstatus(con) != CONNECTION_OK) { log_text(LOG_FATAL, "Connection to database failed: %s", PQerrorMessage(con)); PQfinish(con); return 1; } /* Support for multi-row INSERTs is not available before 8.2 */ if (PQserverVersion(con) < 80200) caps->multi_rows_insert = 0; PQfinish(con); return 0; } static void empty_notice_processor(void *arg, const char *msg) { (void) arg; /* unused */ (void) msg; /* unused */ } /* Connect to database */ int pgsql_drv_connect(db_conn_t *sb_conn) { PGconn *con; con = PQsetdbLogin(args.host, args.port, NULL, NULL, args.db, args.user, args.password); if (PQstatus(con) != CONNECTION_OK) { log_text(LOG_FATAL, "Connection to database failed: %s", PQerrorMessage(con)); PQfinish(con); return 1; } /* Silence the default notice receiver spitting NOTICE message to stderr */ PQsetNoticeProcessor(con, empty_notice_processor, NULL); sb_conn->ptr = con; return 0; } /* Disconnect from database */ int pgsql_drv_disconnect(db_conn_t *sb_conn) { PGconn *con = (PGconn *)sb_conn->ptr; /* These might be allocated in pgsql_check_status() */ xfree(sb_conn->sql_state); xfree(sb_conn->sql_errmsg); if (con != NULL) PQfinish(con); return 0; } /* Disconnect from database */ int pgsql_drv_reconnect(db_conn_t *sb_conn) { if (pgsql_drv_disconnect(sb_conn)) return DB_ERROR_FATAL; while (pgsql_drv_connect(sb_conn)) { if (sb_globals.error) return DB_ERROR_FATAL; } return DB_ERROR_IGNORABLE; } /* Prepare statement */ int pgsql_drv_prepare(db_stmt_t *stmt, const char *query, size_t len) { PGconn *con = (PGconn *)stmt->connection->ptr; PGresult *pgres; pg_stmt_t *pgstmt; char *buf = NULL; unsigned int vcnt; unsigned int need_realloc; unsigned int i,j; unsigned int buflen; int n; char name[32]; (void) len; /* unused */ if (con == NULL) return 1; if (!use_ps) { /* Use client-side PS */ stmt->emulated = 1; stmt->query = strdup(query); return 0; } /* Convert query to PgSQL-style named placeholders */ need_realloc = 1; vcnt = 1; buflen = 0; for (i = 0, j = 0; query[i] != '\0'; i++) { again: if (j+1 >= buflen || need_realloc) { buflen = (buflen > 0) ? buflen * 2 : 256; buf = realloc(buf, buflen); if (buf == NULL) goto error; need_realloc = 0; } if (query[i] != '?') { buf[j++] = query[i]; continue; } n = snprintf(buf + j, buflen - j, "$%d", vcnt); if (n < 0 || n >= (int)(buflen - j)) { need_realloc = 1; goto again; } j += n; vcnt++; } buf[j] = '\0'; /* Store the query to be prepared later on the first bind_param call */ stmt->query = strdup(buf); free(buf); pgstmt = (pg_stmt_t *)calloc(1, sizeof(pg_stmt_t)); if (pgstmt == NULL) goto error; /* Generate random statement name */ get_unique_stmt_name(name, sizeof(name)); pgstmt->name = strdup(name); pgstmt->nparams = vcnt - 1; /* Special keys for statements without parameters, since we don't need to know the types of arguments, and no calls to bind_param() will be made */ if (pgstmt->nparams == 0) { /* Do prepare */ pgres = PQprepare(con, pgstmt->name, stmt->query, pgstmt->nparams, NULL); if (PQresultStatus(pgres) != PGRES_COMMAND_OK) { log_text(LOG_FATAL, "PQprepare() failed: %s", PQerrorMessage(con)); PQclear(pgres); free(stmt->query); free(pgstmt->name); free(pgstmt); return 1; } PQclear(pgres); pgstmt->prepared = 1; } stmt->ptr = pgstmt; return 0; error: return 1; } /* Bind parameters for prepared statement */ int pgsql_drv_bind_param(db_stmt_t *stmt, db_bind_t *params, size_t len) { PGconn *con = (PGconn *)stmt->connection->ptr; PGresult *pgres; pg_stmt_t *pgstmt; unsigned int i; if (con == NULL) return 1; if (stmt->bound_param != NULL) free(stmt->bound_param); stmt->bound_param = (db_bind_t *)malloc(len * sizeof(db_bind_t)); if (stmt->bound_param == NULL) return 1; memcpy(stmt->bound_param, params, len * sizeof(db_bind_t)); stmt->bound_param_len = len; if (stmt->emulated) return 0; pgstmt = stmt->ptr; if (pgstmt->prepared) return 0; /* Prepare statement here, since we need to know types of parameters */ /* Validate parameters count */ if ((unsigned)pgstmt->nparams != len) { log_text(LOG_ALERT, "wrong number of parameters in prepared statement"); log_text(LOG_DEBUG, "counted: %d, passed to bind_param(): %zd", pgstmt->nparams, len); return 1; } pgstmt->ptypes = (Oid *)malloc(len * sizeof(int)); if (pgstmt->ptypes == NULL) return 1; /* Convert sysbench data types to PgSQL ones */ for (i = 0; i < len; i++) pgstmt->ptypes[i] = get_pgsql_bind_type(params[i].type); /* Do prepare */ pgres = PQprepare(con, pgstmt->name, stmt->query, pgstmt->nparams, pgstmt->ptypes); if (PQresultStatus(pgres) != PGRES_COMMAND_OK) { log_text(LOG_FATAL, "PQprepare() failed: %s", PQerrorMessage(con)); return 1; } PQclear(pgres); pgstmt->pvalues = (char **)calloc(len, sizeof(char *)); if (pgstmt->pvalues == NULL) return 1; /* Allocate buffers for bind parameters */ for (i = 0; i < len; i++) { if (pgstmt->pvalues[i] != NULL) { free(pgstmt->pvalues[i]); } pgstmt->pvalues[i] = (char *)malloc(MAX_PARAM_LENGTH); if (pgstmt->pvalues[i] == NULL) return 1; } pgstmt->prepared = 1; return 0; } /* Bind results for prepared statement */ int pgsql_drv_bind_result(db_stmt_t *stmt, db_bind_t *params, size_t len) { /* unused */ (void)stmt; (void)params; (void)len; return 0; } /* Check query execution status */ static db_error_t pgsql_check_status(db_conn_t *con, PGresult *pgres, const char *funcname, const char *query, db_result_t *rs) { ExecStatusType status; db_error_t rc; PGconn * const pgcon = con->ptr; status = PQresultStatus(pgres); switch(status) { case PGRES_TUPLES_OK: rs->nrows = PQntuples(pgres); rs->nfields = PQnfields(pgres); rs->counter = SB_CNT_READ; rc = DB_ERROR_NONE; break; case PGRES_COMMAND_OK: rs->nrows = strtoul(PQcmdTuples(pgres), NULL, 10);; rs->counter = (rs->nrows > 0) ? SB_CNT_WRITE : SB_CNT_OTHER; rc = DB_ERROR_NONE; /* Since we are not returning a result set, the SQL layer will never call pgsql_drv_free_results(). So we must call PQclear() here. */ PQclear(pgres); break; case PGRES_FATAL_ERROR: rs->nrows = 0; rs->counter = SB_CNT_ERROR; /* Duplicate strings here, because PostgreSQL will deallocate them on PQclear() call below. They will be deallocated either on subsequent calls to pgsql_check_status() or in pgsql_drv_disconnect(). */ xfree(con->sql_state); xfree(con->sql_errmsg); con->sql_state = strdup(PQresultErrorField(pgres, PG_DIAG_SQLSTATE)); con->sql_errmsg = strdup(PQresultErrorField(pgres, PG_DIAG_MESSAGE_PRIMARY)); if (!strcmp(con->sql_state, "40P01") /* deadlock_detected */ || !strcmp(con->sql_state, "23505") /* unique violation */ || !strcmp(con->sql_state, "40001"))/* serialization_failure */ { PGresult *tmp; tmp = PQexec(pgcon, "ROLLBACK"); PQclear(tmp); rc = DB_ERROR_IGNORABLE; } else { log_text(LOG_FATAL, "%s() failed: %d %s", funcname, status, con->sql_errmsg); if (query != NULL) log_text(LOG_FATAL, "failed query was: %s", query); rc = DB_ERROR_FATAL; } PQclear(pgres); break; default: rs->nrows = 0; rs->counter = SB_CNT_ERROR; rc = DB_ERROR_FATAL; } return rc; } /* Execute prepared statement */ db_error_t pgsql_drv_execute(db_stmt_t *stmt, db_result_t *rs) { db_conn_t *con = stmt->connection; PGconn *pgcon = (PGconn *)con->ptr; PGresult *pgres; pg_stmt_t *pgstmt; char *buf = NULL; unsigned int buflen = 0; unsigned int i, j, vcnt; char need_realloc; int n; db_error_t rc; unsigned long len; con->sql_errno = 0; xfree(con->sql_state); xfree(con->sql_errmsg); if (!stmt->emulated) { pgstmt = stmt->ptr; if (pgstmt == NULL) { log_text(LOG_DEBUG, "ERROR: exiting mysql_drv_execute(), uninitialized statement"); return DB_ERROR_FATAL; } /* Convert sysbench bind structures to PgSQL data */ for (i = 0; i < (unsigned)pgstmt->nparams; i++) { if (stmt->bound_param[i].is_null && *(stmt->bound_param[i].is_null)) continue; switch (stmt->bound_param[i].type) { case DB_TYPE_CHAR: case DB_TYPE_VARCHAR: len = stmt->bound_param[i].data_len[0]; memcpy(pgstmt->pvalues[i], stmt->bound_param[i].buffer, SB_MIN(MAX_PARAM_LENGTH, len)); /* PostgreSQL requires a zero-terminated string */ pgstmt->pvalues[i][len] = '\0'; break; default: db_print_value(stmt->bound_param + i, pgstmt->pvalues[i], MAX_PARAM_LENGTH); } } pgres = PQexecPrepared(pgcon, pgstmt->name, pgstmt->nparams, (const char **)pgstmt->pvalues, NULL, NULL, 1); rc = pgsql_check_status(con, pgres, "PQexecPrepared", NULL, rs); rs->ptr = (rs->counter == SB_CNT_READ) ? (void *) pgres : NULL; return rc; } /* Use emulation */ /* Build the actual query string from parameters list */ need_realloc = 1; vcnt = 0; for (i = 0, j = 0; stmt->query[i] != '\0'; i++) { again: if (j+1 >= buflen || need_realloc) { buflen = (buflen > 0) ? buflen * 2 : 256; buf = realloc(buf, buflen); if (buf == NULL) return DB_ERROR_FATAL; need_realloc = 0; } if (stmt->query[i] != '?') { buf[j++] = stmt->query[i]; continue; } n = db_print_value(stmt->bound_param + vcnt, buf + j, buflen - j); if (n < 0) { need_realloc = 1; goto again; } j += n; vcnt++; } buf[j] = '\0'; rc = pgsql_drv_query(con, buf, j, rs); free(buf); return rc; } /* Execute SQL query */ db_error_t pgsql_drv_query(db_conn_t *sb_conn, const char *query, size_t len, db_result_t *rs) { PGconn *pgcon = sb_conn->ptr; PGresult *pgres; db_error_t rc; (void)len; /* unused */ sb_conn->sql_errno = 0; xfree(sb_conn->sql_state); xfree(sb_conn->sql_errmsg); pgres = PQexec(pgcon, query); rc = pgsql_check_status(sb_conn, pgres, "PQexec", query, rs); rs->ptr = (rs->counter == SB_CNT_READ) ? (void *) pgres : NULL; return rc; } /* Fetch row from result set of a prepared statement */ int pgsql_drv_fetch(db_result_t *rs) { /* NYI */ (void)rs; return 1; } /* Fetch row from result set of a query */ int pgsql_drv_fetch_row(db_result_t *rs, db_row_t *row) { intptr_t rownum; int i; /* Use row->ptr as a row number, rather than a pointer to avoid dynamic memory management. */ rownum = (intptr_t) row->ptr; if (rownum >= (int) rs->nrows) return DB_ERROR_IGNORABLE; for (i = 0; i < (int) rs->nfields; i++) { /* PQgetvalue() returns an empty string, not a NULL value for a NULL field. Callers of this function expect a NULL pointer in this case. */ if (PQgetisnull(rs->ptr, rownum, i)) row->values[i].ptr = NULL; else { row->values[i].len = PQgetlength(rs->ptr, rownum, i); row->values[i].ptr = PQgetvalue(rs->ptr, rownum, i); } } row->ptr = (void *) (rownum + 1); return DB_ERROR_NONE; } /* Free result set */ int pgsql_drv_free_results(db_result_t *rs) { if (rs->ptr != NULL) { PQclear((PGresult *)rs->ptr); rs->ptr = NULL; rs->row.ptr = 0; return 0; } return 1; } /* Close prepared statement */ int pgsql_drv_close(db_stmt_t *stmt) { pg_stmt_t *pgstmt = stmt->ptr; int i; if (pgstmt == NULL) return 1; if (pgstmt->name != NULL) free(pgstmt->name); if (pgstmt->ptypes != NULL) free(pgstmt->ptypes); if (pgstmt->pvalues != NULL) { for (i = 0; i < pgstmt->nparams; i++) if (pgstmt->pvalues[i] != NULL) free(pgstmt->pvalues[i]); free(pgstmt->pvalues); } xfree(stmt->ptr); return 0; } /* Uninitialize driver */ int pgsql_drv_done(void) { return 0; } /* Map SQL data type to bind_type value in MYSQL_BIND */ int get_pgsql_bind_type(db_bind_type_t type) { unsigned int i; for (i = 0; db_pgsql_bind_map[i].db_type != DB_TYPE_NONE; i++) if (db_pgsql_bind_map[i].db_type == type) return db_pgsql_bind_map[i].pg_type; return -1; } int get_unique_stmt_name(char *name, int len) { return snprintf(name, len, "sbstmt%d%d", (int) sb_rand_uniform_uint64(), (int) sb_rand_uniform_uint64()); } ================================================ FILE: src/lua/Makefile.am ================================================ # Copyright (C) 2016 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA SUBDIRS = internal dist_pkgdata_SCRIPTS = bulk_insert.lua \ oltp_delete.lua \ oltp_insert.lua \ oltp_read_only.lua \ oltp_read_write.lua \ oltp_point_select.lua \ oltp_update_index.lua \ oltp_update_non_index.lua \ oltp_write_only.lua\ select_random_points.lua \ select_random_ranges.lua dist_pkgdata_DATA = oltp_common.lua ================================================ FILE: src/lua/bulk_insert.lua ================================================ #!/usr/bin/env sysbench -- -------------------------------------------------------------------------- -- -- Bulk insert benchmark: do multi-row INSERTs concurrently in --threads -- threads with each thread inserting into its own table. The number of INSERTs -- executed by each thread is controlled by either --time or --events. -- -------------------------------------------------------------------------- -- cursize=0 function thread_init() drv = sysbench.sql.driver() con = drv:connect() end function prepare() local i local drv = sysbench.sql.driver() local con = drv:connect() for i = 1, sysbench.opt.threads do print("Creating table 'sbtest" .. i .. "'...") con:query(string.format([[ CREATE TABLE IF NOT EXISTS sbtest%d ( id INTEGER NOT NULL, k INTEGER DEFAULT '0' NOT NULL, PRIMARY KEY (id))]], i)) end end function event() if (cursize == 0) then con:bulk_insert_init("INSERT INTO sbtest" .. sysbench.tid+1 .. " VALUES") end cursize = cursize + 1 con:bulk_insert_next("(" .. cursize .. "," .. cursize .. ")") end function thread_done() con:bulk_insert_done() con:disconnect() end function cleanup() local i local drv = sysbench.sql.driver() local con = drv:connect() for i = 1, sysbench.opt.threads do print("Dropping table 'sbtest" .. i .. "'...") con:query("DROP TABLE IF EXISTS sbtest" .. i ) end end ================================================ FILE: src/lua/empty-test.lua ================================================ #!/usr/bin/env sysbench -- you can run this script like this: -- $ ./empty-test.lua --cpu-max-prime=20000 --threads=8 --histogram --report-interval=1 run sysbench.cmdline.options = { -- the default values for built-in options are currently ignored, see -- https://github.com/akopytov/sysbench/issues/151 ["cpu-max-prime"] = {"CPU maximum prime", 10000}, ["threads"] = {"Number of threads", 1}, ["histogram"] = {"Show histogram", "off"}, ["report-interval"] = {"Report interval", 1} } function event() end function sysbench.hooks.report_cumulative(stat) local seconds = stat.time_interval print(string.format([[ { "errors": %4.0f, "events": %4.0f, "latency_avg": %4.10f, "latency_max": %4.10f, "latency_min": %4.10f, "latency_pct": %4.10f, "latency_sum": %4.10f, "other": %4.0f, "reads": %4.0f, "reconnects": %4.0f, "threads_running": %4.0f, "time_interval": %4.10f, "time_total": %4.10f, "writes": %4.0f } ]], stat.errors, stat.events, stat.latency_avg, stat.latency_max, stat.latency_min, stat.latency_pct, stat.latency_sum, stat.other, stat.reads, stat.reconnects, stat.threads_running, stat.time_interval, stat.time_total, stat.writes)) end ================================================ FILE: src/lua/internal/Makefile.am ================================================ # Copyright (C) 2016-2018 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA BUILT_SOURCES = sysbench.lua.h sysbench.rand.lua.h sysbench.sql.lua.h \ sysbench.cmdline.lua.h \ sysbench.histogram.lua.h CLEANFILES = $(BUILT_SOURCES) EXTRA_DIST = $(BUILT_SOURCES:.h=) SUFFIXES = .lua .lua.h .lua.lua.h: @echo "Creating $@ from $<" @var=$$(echo $< | sed 's/\./_/g') && \ ( echo "unsigned char $${var}[] =" && \ sed -e 's/\\/\\\\/g' \ -e 's/"/\\"/g' \ -e 's/^/ "/g' \ -e 's/$$/\\n"/g' $< && \ echo ";" && \ echo "size_t $${var}_len = sizeof($${var}) - 1;" ) > $@ ================================================ FILE: src/lua/internal/sysbench.cmdline.lua ================================================ -- Copyright (C) 2017-2018 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ---------------------------------------------------------------------- -- Command line option handling -- ---------------------------------------------------------------------- ffi = require("ffi") ffi.cdef[[ /* The following has been copied from sb_option.h */ typedef enum { SB_ARG_TYPE_NULL, SB_ARG_TYPE_BOOL, SB_ARG_TYPE_INT, SB_ARG_TYPE_SIZE, SB_ARG_TYPE_DOUBLE, SB_ARG_TYPE_STRING, SB_ARG_TYPE_LIST, SB_ARG_TYPE_FILE, SB_ARG_TYPE_MAX } sb_arg_type_t; /* Option validation function */ typedef bool sb_opt_validate_t(const char *, const char *); /* Test option definition */ typedef struct { const char *name; const char *desc; const char *value; sb_arg_type_t type; sb_opt_validate_t *validate; } sb_arg_t; int sb_lua_set_test_args(sb_arg_t *args, size_t len); ]] sysbench.cmdline.ARG_NULL = ffi.C.SB_ARG_TYPE_NULL sysbench.cmdline.ARG_BOOL = ffi.C.SB_ARG_TYPE_BOOL sysbench.cmdline.ARG_INT = ffi.C.SB_ARG_TYPE_INT sysbench.cmdline.ARG_SIZE = ffi.C.SB_ARG_TYPE_SIZE sysbench.cmdline.ARG_DOUBLE = ffi.C.SB_ARG_TYPE_DOUBLE sysbench.cmdline.ARG_STRING = ffi.C.SB_ARG_TYPE_STRING sysbench.cmdline.ARG_LIST = ffi.C.SB_ARG_TYPE_LIST sysbench.cmdline.ARG_FILE = ffi.C.SB_ARG_TYPE_FILE sysbench.cmdline.ARG_MAX = ffi.C.SB_ARG_TYPE_MAX -- Attribute indicating that a custom command can be executed in parallel sysbench.cmdline.PARALLEL_COMMAND = true local arg_types = { boolean = sysbench.cmdline.ARG_BOOL, string = sysbench.cmdline.ARG_STRING, number = sysbench.cmdline.ARG_DOUBLE, table = sysbench.cmdline.ARG_LIST } local function __genOrderedIndex( t ) local orderedIndex = {} for key in pairs(t) do table.insert( orderedIndex, key ) end table.sort( orderedIndex ) return orderedIndex end local function orderedNext(t, state) local key = nil if state == nil then t.__orderedIndex = __genOrderedIndex( t ) key = t.__orderedIndex[1] else for i = 1,table.getn(t.__orderedIndex) do if t.__orderedIndex[i] == state then key = t.__orderedIndex[i+1] end end end if key then return key, t[key] end t.__orderedIndex = nil return end local function orderedPairs(t) return orderedNext, t, nil end -- Parse command line options definitions, if present in the script as a -- 'sysbench.cmdline.options' table. If no such table exists, or if there a -- parsing error, return false. Return true on success. After parsing the -- command line arguments, option values are available as the sysbench.opt -- table. function sysbench.cmdline.read_cmdline_options() if sysbench.cmdline.options == nil then return true end local t = type(sysbench.cmdline.options) assert(t == "table", "wrong type for sysbench.cmdline.options: " .. t) local i = 0 for name, def in pairs(sysbench.cmdline.options) do i = i+1 end local args = ffi.new('sb_arg_t[?]', i) i = 0 for name, def in orderedPairs(sysbench.cmdline.options) do -- name assert(type(name) == "string" and type(def) == "table", "wrong table structure in sysbench.cmdline.options") args[i].name = name -- description assert(def[1] ~= nil, "nil description for option " .. name) args[i].desc = def[1] if type(def[2]) == "table" then assert(type(def[3]) == "nil" or type(def[3]) == sysbench.cmdline.ARG_LIST, "wrong type for list option " .. name) args[i].value = table.concat(def[2], ',') else if type(def[2]) == "boolean" then args[i].value = def[2] and 'on' or 'off' elseif type(def[2]) == "number" then args[i].value = tostring(def[2]) else args[i].value = def[2] end end -- type local t = def[3] if t == nil then if def[2] ~= nil then -- Try to determine the type by the default value t = arg_types[type(def[2])] else t = sysbench.cmdline.ARG_STRING end end assert(t ~= nil, "cannot determine type for option " .. name) args[i].type = t -- validation function args[i].validate = def[4] i = i + 1 end return ffi.C.sb_lua_set_test_args(args, i) == 0 end function sysbench.cmdline.command_defined(name) return type(sysbench.cmdline.commands) == "table" and sysbench.cmdline.commands[name] ~= nil and sysbench.cmdline.commands[name][1] ~= nil end function sysbench.cmdline.command_parallel(name) return sysbench.cmdline.command_defined(name) and sysbench.cmdline.commands[name][2] == sysbench.cmdline.PARALLEL_COMMAND end function sysbench.cmdline.call_command(name) if not sysbench.cmdline.command_defined(name) then return false end local rc = sysbench.cmdline.commands[name][1]() if rc == nil then -- handle the case when the command does not return and value as success return true else -- otherwise return success for any returned value other than false return rc and true or false end end ffi.cdef[[ void sb_print_test_options(void); ]] -- ---------------------------------------------------------------------- -- Print descriptions of command line options, if defined by -- sysbench.cmdline.options -- ---------------------------------------------------------------------- function sysbench.cmdline.print_test_options() ffi.C.sb_print_test_options() end ================================================ FILE: src/lua/internal/sysbench.histogram.lua ================================================ -- Copyright (C) 2017 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ---------------------------------------------------------------------- -- Bounded histograms API -- ---------------------------------------------------------------------- ffi = require("ffi") sysbench.histogram = {} ffi.cdef[[ typedef struct histogram sb_histogram_t; /* Allocate a new histogram and initialize it with sb_histogram_init(). */ sb_histogram_t *sb_histogram_new(size_t size, double range_min, double range_max); /* Deallocate a histogram allocated with sb_histogram_new(). */ void sb_histogram_delete(sb_histogram_t *h); /* Update histogram with a given value. */ void sb_histogram_update(sb_histogram_t *h, double value); /* Print a given histogram to stdout */ void sb_histogram_print(sb_histogram_t *h); ]] local histogram = {} function histogram:update(value) ffi.C.sb_histogram_update(self, value) end function histogram:print() ffi.C.sb_histogram_print(self) end local histogram_mt = { __index = histogram, __tostring = '' } ffi.metatype('sb_histogram_t', histogram_mt) function sysbench.histogram.new(size, range_min, range_max) local h = ffi.C.sb_histogram_new(size, range_min, range_max) return ffi.gc(h, ffi.C.sb_histogram_delete) end ================================================ FILE: src/lua/internal/sysbench.lua ================================================ -- Copyright (C) 2016-2018 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ffi = require("ffi") ffi.cdef[[ void sb_event_start(int thread_id); void sb_event_stop(int thread_id); bool sb_more_events(int thread_id); ]] -- ---------------------------------------------------------------------- -- Main event loop. This is a Lua version of sysbench.c:thread_run() -- ---------------------------------------------------------------------- function thread_run(thread_id) while ffi.C.sb_more_events(thread_id) do ffi.C.sb_event_start(thread_id) local success, ret repeat success, ret = pcall(event, thread_id) if not success then if type(ret) == "table" and ret.errcode == sysbench.error.RESTART_EVENT then if sysbench.hooks.before_restart_event then sysbench.hooks.before_restart_event(ret) end else error(ret, 2) -- propagate unknown errors end end until success -- Stop the benchmark if event() returns a value other than nil or false if ret then break end ffi.C.sb_event_stop(thread_id) end end -- ---------------------------------------------------------------------- -- Hooks -- ---------------------------------------------------------------------- sysbench.hooks = { -- sql_error_ignorable = , -- report_intermediate = , -- report_cumulative = } -- Report statistics in the CSV format. Add the following to your -- script to replace the default human-readable reports -- -- sysbench.hooks.report_intermediate = sysbench.report_csv function sysbench.report_csv(stat) local seconds = stat.time_interval print(string.format("%.0f,%u,%4.2f," .. "%4.2f,%4.2f,%4.2f,%4.2f," .. "%4.2f,%4.2f," .. "%4.2f", stat.time_total, stat.threads_running, stat.events / seconds, (stat.reads + stat.writes + stat.other) / seconds, stat.reads / seconds, stat.writes / seconds, stat.other / seconds, stat.latency_pct * 1000, stat.errors / seconds, stat.reconnects / seconds )) end -- Report statistics in the JSON format. Add the following to your -- script to replace the default human-readable reports -- -- sysbench.hooks.report_intermediate = sysbench.report_json function sysbench.report_json(stat) if not gobj then io.write('[\n') -- hack to print the closing bracket when the Lua state of the reporting -- thread is closed gobj = newproxy(true) getmetatable(gobj).__gc = function () io.write('\n]\n') end else io.write(',\n') end local seconds = stat.time_interval io.write(([[ { "time": %4.0f, "threads": %u, "tps": %4.2f, "qps": { "total": %4.2f, "reads": %4.2f, "writes": %4.2f, "other": %4.2f }, "latency": %4.2f, "errors": %4.2f, "reconnects": %4.2f }]]):format( stat.time_total, stat.threads_running, stat.events / seconds, (stat.reads + stat.writes + stat.other) / seconds, stat.reads / seconds, stat.writes / seconds, stat.other / seconds, stat.latency_pct * 1000, stat.errors / seconds, stat.reconnects / seconds )) end -- Report statistics in the default human-readable format. You can use it if you -- want to augment default reports with your own statistics. Call it from your -- own report hook, e.g.: -- -- function sysbench.hooks.report_intermediate(stat) -- print("my stat: ", val) -- sysbench.report_default(stat) -- end function sysbench.report_default(stat) local seconds = stat.time_interval print(string.format("[ %.0fs ] thds: %u tps: %4.2f qps: %4.2f " .. "(r/w/o: %4.2f/%4.2f/%4.2f) lat (ms,%u%%): %4.2f " .. "err/s %4.2f reconn/s: %4.2f", stat.time_total, stat.threads_running, stat.events / seconds, (stat.reads + stat.writes + stat.other) / seconds, stat.reads / seconds, stat.writes / seconds, stat.other / seconds, sysbench.opt.percentile, stat.latency_pct * 1000, stat.errors / seconds, stat.reconnects / seconds )) end ================================================ FILE: src/lua/internal/sysbench.rand.lua ================================================ -- Copyright (C) 2016-2017 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ffi = require("ffi") -- ---------------------------------------------------------------------- -- Pseudo-random number generation API -- ---------------------------------------------------------------------- sysbench.rand = {} ffi.cdef[[ uint64_t sb_rand_uniform_uint64(void); uint32_t sb_rand_default(uint32_t, uint32_t); uint32_t sb_rand_uniform(uint32_t, uint32_t); uint32_t sb_rand_gaussian(uint32_t, uint32_t); uint32_t sb_rand_pareto(uint32_t, uint32_t); uint32_t sb_rand_zipfian(uint32_t, uint32_t); uint32_t sb_rand_unique(void); void sb_rand_str(const char *, char *); uint32_t sb_rand_varstr(char *, uint32_t, uint32_t); double sb_rand_uniform_double(void); ]] function sysbench.rand.uniform_uint64() return ffi.C.sb_rand_uniform_uint64() end function sysbench.rand.default(a, b) return ffi.C.sb_rand_default(a, b) end function sysbench.rand.uniform(a, b) return ffi.C.sb_rand_uniform(a, b) end function sysbench.rand.gaussian(a, b) return ffi.C.sb_rand_gaussian(a, b) end function sysbench.rand.pareto(a, b) return ffi.C.sb_rand_pareto(a, b) end function sysbench.rand.zipfian(a, b) return ffi.C.sb_rand_zipfian(a, b) end function sysbench.rand.unique() return ffi.C.sb_rand_unique() end function sysbench.rand.string(fmt) local buflen = #fmt local buf = ffi.new("uint8_t[?]", buflen) ffi.C.sb_rand_str(fmt, buf) return ffi.string(buf, buflen) end function sysbench.rand.varstring(min_len, max_len) assert(min_len <= max_len) assert(max_len > 0) local buflen = max_len local buf = ffi.new("uint8_t[?]", buflen) local nchars = ffi.C.sb_rand_varstr(buf, min_len, max_len) return ffi.string(buf, nchars) end function sysbench.rand.uniform_double() return ffi.C.sb_rand_uniform_double() end ================================================ FILE: src/lua/internal/sysbench.sql.lua ================================================ -- Copyright (C) 2017 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ---------------------------------------------------------------------- -- SQL API -- ---------------------------------------------------------------------- ffi = require("ffi") sysbench.sql = {} ffi.cdef[[ /* The following definitions have been copied with modifications from db_driver.h */ typedef enum { DB_ERROR_NONE, /* no error(s) */ DB_ERROR_IGNORABLE, /* error should be ignored as defined by command line arguments or a custom error handler */ DB_ERROR_FATAL /* non-ignorable error */ } sql_error_t; typedef struct { const char *sname; /* short name */ const char *lname; /* long name */ const char opaque[?]; } sql_driver; typedef struct { uint32_t len; /* Value length */ const char *ptr; /* Value string */ } sql_value; /* Result set row definition */ typedef struct { void *ptr; /* Driver-specific row data */ sql_value *values; /* Array of column values */ } sql_row; /* Statistic counter types */ typedef enum { SB_CNT_OTHER, SB_CNT_READ, SB_CNT_WRITE, SB_CNT_TRX, SB_CNT_ERROR, SB_CNT_RECONNECT, SB_CNT_BYTES_READ, SB_CNT_BYTES_WRITTEN, SB_CNT_MAX } sb_counter_type; typedef struct { sql_error_t error; /* Driver-independent error code */ int sql_errno; /* Driver-specific error code */ const char *sql_state; /* Database-specific SQL state */ const char *sql_errmsg; /* Database-specific error message */ sql_driver *driver; /* DB driver for this connection */ const char opaque[?]; } sql_connection; typedef struct { sql_connection *connection; const char opaque[?]; } sql_statement; /* Result set definition */ typedef struct { sb_counter_type counter; /* Statistical counter type */ uint32_t nrows; /* Number of affected rows */ uint32_t nfields; /* Number of fields */ sql_statement *statement; /* Pointer to prepared statement (if used) */ void *ptr; /* Pointer to driver-specific data */ sql_row row; /* Last fetched row */ } sql_result; typedef enum { SQL_TYPE_NONE, SQL_TYPE_TINYINT, SQL_TYPE_SMALLINT, SQL_TYPE_INT, SQL_TYPE_BIGINT, SQL_TYPE_FLOAT, SQL_TYPE_DOUBLE, SQL_TYPE_TIME, SQL_TYPE_DATE, SQL_TYPE_DATETIME, SQL_TYPE_TIMESTAMP, SQL_TYPE_CHAR, SQL_TYPE_VARCHAR } sql_bind_type_t; typedef struct { sql_bind_type_t type; void *buffer; unsigned long *data_len; unsigned long max_len; char *is_null; } sql_bind; sql_driver *db_create(const char *); int db_destroy(sql_driver *drv); sql_connection *db_connection_create(sql_driver * drv); int db_connection_close(sql_connection *con); int db_connection_reconnect(sql_connection *con); void db_connection_free(sql_connection *con); int db_bulk_insert_init(sql_connection *, const char *, size_t); int db_bulk_insert_next(sql_connection *, const char *, size_t); int db_bulk_insert_done(sql_connection *); sql_result *db_query(sql_connection *con, const char *query, size_t len); sql_row *db_fetch_row(sql_result *rs); sql_statement *db_prepare(sql_connection *con, const char *query, size_t len); int db_bind_param(sql_statement *stmt, sql_bind *params, size_t len); int db_bind_result(sql_statement *stmt, sql_bind *results, size_t len); sql_result *db_execute(sql_statement *stmt); sql_result *db_stmt_next_result(sql_statement *stmt); int db_close(sql_statement *stmt); bool db_more_results(sql_connection *con); sql_result *db_next_result(sql_connection *con); int db_free_results(sql_result *); ]] local sql_driver = ffi.typeof('sql_driver *') local sql_connection = ffi.typeof('sql_connection *') local sql_statement = ffi.typeof('sql_statement *') local sql_bind = ffi.typeof('sql_bind'); local sql_result = ffi.typeof('sql_result'); local sql_value = ffi.typeof('sql_value'); local sql_row = ffi.typeof('sql_row'); sysbench.sql.type = { NONE = ffi.C.SQL_TYPE_NONE, TINYINT = ffi.C.SQL_TYPE_TINYINT, SMALLINT = ffi.C.SQL_TYPE_SMALLINT, INT = ffi.C.SQL_TYPE_INT, BIGINT = ffi.C.SQL_TYPE_BIGINT, FLOAT = ffi.C.SQL_TYPE_FLOAT, DOUBLE = ffi.C.SQL_TYPE_DOUBLE, TIME = ffi.C.SQL_TYPE_TIME, DATE = ffi.C.SQL_TYPE_DATE, DATETIME = ffi.C.SQL_TYPE_DATETIME, TIMESTAMP = ffi.C.SQL_TYPE_TIMESTAMP, CHAR = ffi.C.SQL_TYPE_CHAR, VARCHAR = ffi.C.SQL_TYPE_VARCHAR } -- Initialize a given SQL driver and return a handle to it to create -- connections. A nil driver name (i.e. no function argument) initializes the -- default driver, i.e. the one specified with --db-driver on the command line. function sysbench.sql.driver(driver_name) local drv = ffi.C.db_create(driver_name) if (drv == nil) then error("failed to initialize the DB driver", 2) end return ffi.gc(drv, ffi.C.db_destroy) end -- sql_driver methods local driver_methods = {} function driver_methods.connect(self) local con = ffi.C.db_connection_create(self) if con == nil then error("connection creation failed", 2) end return ffi.gc(con, ffi.C.db_connection_free) end function driver_methods.name(self) return ffi.string(self.sname) end -- sql_driver metatable local driver_mt = { __index = driver_methods, __gc = ffi.C.db_destroy, __tostring = function() return '' end, } ffi.metatype("sql_driver", driver_mt) -- sql_connection methods local connection_methods = {} function connection_methods.disconnect(self) return assert(ffi.C.db_connection_close(self) == 0) end function connection_methods.reconnect(self) return assert(ffi.C.db_connection_reconnect(self) == 0) end function connection_methods.check_error(self, rs, query) if rs ~= nil or self.error == sysbench.sql.error.NONE then return rs end if self.sql_state == nil or self.sql_errmsg == nil then -- It must be an API error, don't bother trying to downgrade it an -- ignorable error error("SQL API error", 3) end local sql_state = ffi.string(self.sql_state) local sql_errmsg = ffi.string(self.sql_errmsg) -- Create an error descriptor containing connection, failed query, SQL error -- number, state and error message provided by the SQL driver errdesc = { connection = self, query = query, sql_errno = self.sql_errno, sql_state = sql_state, sql_errmsg = sql_errmsg } -- Check if the error has already been marked as ignorable by the driver, or -- there is an error hook that allows downgrading it to IGNORABLE if (self.error == sysbench.sql.error.FATAL and type(sysbench.hooks.sql_error_ignorable) == "function" and sysbench.hooks.sql_error_ignorable(errdesc)) or self.error == sysbench.sql.error.IGNORABLE then -- Throw a 'restart event' exception that can be caught by the user script -- to do some extra steps to restart a transaction (e.g. reprepare -- statements after a reconnect). Otherwise it will be caught by -- thread_run() in sysbench.lua, in which case the entire current event -- will be restarted without extra processing. errdesc.errcode = sysbench.error.RESTART_EVENT error(errdesc, 3) end -- Just throw a regular error message on a fatal error error(string.format("SQL error, errno = %d, state = '%s': %s", self.sql_errno, sql_state, sql_errmsg), 2) end function connection_methods.query(self, query) local rs = ffi.C.db_query(self, query, #query) return self:check_error(rs, query) end function connection_methods.more_results(self) return ffi.C.db_more_results(self) end function connection_methods.next_result(self) local rs = ffi.C.db_next_result(self) return self:check_error(rs, ""); end function connection_methods.bulk_insert_init(self, query) return assert(ffi.C.db_bulk_insert_init(self, query, #query) == 0, "db_bulk_insert_init() failed") end function connection_methods.bulk_insert_next(self, val) return assert(ffi.C.db_bulk_insert_next(self, val, #val) == 0, "db_bulk_insert_next() failed") end function connection_methods.bulk_insert_done(self) return assert(ffi.C.db_bulk_insert_done(self) == 0, "db_bulk_insert_done() failed") end function connection_methods.prepare(self, query) local stmt = ffi.C.db_prepare(self, query, #query) if stmt == nil then self:check_error(nil, query) end return stmt end -- A convenience wrapper around sql_connection:query() and -- sql_result:fetch_row(). Executes the specified query and returns the first -- row from the result set, if available, or nil otherwise function connection_methods.query_row(self, query) local rs = self:query(query) if rs == nil or rs.nrows == 0 then return nil end return unpack(rs:fetch_row(), 1, rs.nfields) end -- sql_connection metatable local connection_mt = { __index = connection_methods, __tostring = function() return '' end, __gc = ffi.C.db_connection_free, } ffi.metatype("sql_connection", connection_mt) -- sql_param local sql_param = {} function sql_param.set(self, value) local sql_type = sysbench.sql.type local btype = self.type if (value == nil) then self.is_null[0] = true return end self.is_null[0] = false if btype == sql_type.TINYINT or btype == sql_type.SMALLINT or btype == sql_type.INT or btype == sql_type.BIGINT or btype == sql_type.FLOAT or btype == sql_type.DOUBLE then self.buffer[0] = value elseif btype == sql_type.CHAR or btype == sql_type.VARCHAR then local len = #value len = self.max_len < len and self.max_len or len ffi.copy(self.buffer, value, len) self.data_len[0] = len else error("Unsupported argument type: " .. btype, 2) end end function sql_param.set_rand_str(self, fmt) local sql_type = sysbench.sql.type local btype = self.type self.is_null[0] = false if btype == sql_type.CHAR or btype == sql_type.VARCHAR then local len = #fmt len = self.max_len < len and self.max_len or len ffi.C.sb_rand_str(fmt, self.buffer) self.data_len[0] = len else error("Unsupported argument type: " .. btype, 2) end end sql_param.__index = sql_param sql_param.__tostring = function () return '' end -- sql_statement methods local statement_methods = {} function statement_methods.bind_create(self, btype, max_len) local sql_type = sysbench.sql.type local param = setmetatable({}, sql_param) if btype == sql_type.TINYINT or btype == sql_type.SMALLINT or btype == sql_type.INT or btype == sql_type.BIGINT then param.type = sql_type.BIGINT param.buffer = ffi.new('int64_t[1]') param.max_len = 8 elseif btype == sql_type.FLOAT or btype == sql_type.DOUBLE then param.type = sql_type.DOUBLE param.buffer = ffi.new('double[1]') param.max_len = 8 elseif btype == sql_type.CHAR or btype == sql_type.VARCHAR then param.type = sql_type.VARCHAR param.buffer = ffi.new('char[?]', max_len) param.max_len = max_len else error("Unsupported argument type: " .. btype, 2) end param.data_len = ffi.new('unsigned long[1]') param.is_null = ffi.new('char[1]') return param end function statement_methods.bind_param(self, ...) local len = select('#', ...) if len < 1 then return nil end local binds = ffi.new("sql_bind[?]", len) for i, param in ipairs({...}) do binds[i-1].type = param.type binds[i-1].buffer = param.buffer binds[i-1].data_len = param.data_len binds[i-1].max_len = param.max_len binds[i-1].is_null = param.is_null end return ffi.C.db_bind_param(self, binds, len) end function statement_methods.execute(self) local rs = ffi.C.db_execute(self) return self.connection:check_error(rs, '') end function statement_methods.next_result(self) local rs = ffi.C.db_stmt_next_result(self) return self.connection:check_error(rs, '') end function statement_methods.close(self) return ffi.C.db_close(self) end -- sql_statement metatable local statement_mt = { __index = statement_methods, __tostring = function() return '' end, __gc = ffi.C.db_close, } ffi.metatype("sql_statement", statement_mt) local bind_mt = { __tostring = function() return '' end, } ffi.metatype("sql_bind", bind_mt) -- sql_result methods local result_methods = {} -- Returns the next row of values from a result set, or nil if there are no more -- rows to fetch. Values are returned as an array, i.e. a table with numeric -- indexes starting from 1. The total number of values (i.e. fields in a result -- set) can be obtained from sql_result.nfields. function result_methods.fetch_row(self) local res = {} local row = ffi.C.db_fetch_row(self) if row == nil then return nil end for i = 0, self.nfields-1 do if row.values[i].ptr ~= nil then -- not a NULL value res[i+1] = ffi.string(row.values[i].ptr, tonumber(row.values[i].len)) end end return res end function result_methods.free(self) return assert(ffi.C.db_free_results(self) == 0, "db_free_results() failed") end -- sql_results metatable local result_mt = { __index = result_methods, __tostring = function() return '' end, __gc = ffi.C.db_free_results } ffi.metatype("sql_result", result_mt) -- error codes sysbench.sql.error = {} sysbench.sql.error.NONE = ffi.C.DB_ERROR_NONE sysbench.sql.error.IGNORABLE = ffi.C.DB_ERROR_IGNORABLE sysbench.sql.error.FATAL = ffi.C.DB_ERROR_FATAL ================================================ FILE: src/lua/oltp_common.lua ================================================ -- Copyright (C) 2006-2018 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ----------------------------------------------------------------------------- -- Common code for OLTP benchmarks. -- ----------------------------------------------------------------------------- function init() assert(event ~= nil, "this script is meant to be included by other OLTP scripts and " .. "should not be called directly.") end if sysbench.cmdline.command == nil then error("Command is required. Supported commands: prepare, warmup, run, " .. "cleanup, help") end -- Command line options sysbench.cmdline.options = { table_size = {"Number of rows per table", 10000}, range_size = {"Range size for range SELECT queries", 100}, tables = {"Number of tables", 1}, point_selects = {"Number of point SELECT queries per transaction", 10}, simple_ranges = {"Number of simple range SELECT queries per transaction", 1}, sum_ranges = {"Number of SELECT SUM() queries per transaction", 1}, order_ranges = {"Number of SELECT ORDER BY queries per transaction", 1}, distinct_ranges = {"Number of SELECT DISTINCT queries per transaction", 1}, index_updates = {"Number of UPDATE index queries per transaction", 1}, non_index_updates = {"Number of UPDATE non-index queries per transaction", 1}, delete_inserts = {"Number of DELETE/INSERT combinations per transaction", 1}, range_selects = {"Enable/disable all range SELECT queries", true}, auto_inc = {"Use AUTO_INCREMENT column as Primary Key (for MySQL), " .. "or its alternatives in other DBMS. When disabled, use " .. "client-generated IDs", true}, create_table_options = {"Extra CREATE TABLE options", ""}, skip_trx = {"Don't start explicit transactions and execute all queries " .. "in the AUTOCOMMIT mode", false}, secondary = {"Use a secondary index in place of the PRIMARY KEY", false}, create_secondary = {"Create a secondary index in addition to the PRIMARY KEY", true}, reconnect = {"Reconnect after every N events. The default (0) is to not reconnect", 0}, mysql_storage_engine = {"Storage engine, if MySQL is used", "innodb"}, pgsql_variant = {"Use this PostgreSQL variant when running with the " .. "PostgreSQL driver. The only currently supported " .. "variant is 'redshift'. When enabled, " .. "create_secondary is automatically disabled, and " .. "delete_inserts is set to 0"} } -- Prepare the dataset. This command supports parallel execution, i.e. will -- benefit from executing with --threads > 1 as long as --tables > 1 function cmd_prepare() local drv = sysbench.sql.driver() local con = drv:connect() for i = sysbench.tid % sysbench.opt.threads + 1, sysbench.opt.tables, sysbench.opt.threads do create_table(drv, con, i) end end -- Preload the dataset into the server cache. This command supports parallel -- execution, i.e. will benefit from executing with --threads > 1 as long as -- --tables > 1 -- -- PS. Currently, this command is only meaningful for MySQL/InnoDB benchmarks function cmd_warmup() local drv = sysbench.sql.driver() local con = drv:connect() assert(drv:name() == "mysql", "warmup is currently MySQL only") -- Do not create on disk tables for subsequent queries con:query("SET tmp_table_size=2*1024*1024*1024") con:query("SET max_heap_table_size=2*1024*1024*1024") for i = sysbench.tid % sysbench.opt.threads + 1, sysbench.opt.tables, sysbench.opt.threads do local t = "sbtest" .. i print("Preloading table " .. t) con:query("ANALYZE TABLE sbtest" .. i) con:query(string.format( "SELECT AVG(id) FROM " .. "(SELECT * FROM %s FORCE KEY (PRIMARY) " .. "LIMIT %u) t", t, sysbench.opt.table_size)) con:query(string.format( "SELECT COUNT(*) FROM " .. "(SELECT * FROM %s WHERE k LIKE '%%0%%' LIMIT %u) t", t, sysbench.opt.table_size)) end end -- Implement parallel prepare and warmup commands, define 'prewarm' as an alias -- for 'warmup' sysbench.cmdline.commands = { prepare = {cmd_prepare, sysbench.cmdline.PARALLEL_COMMAND}, warmup = {cmd_warmup, sysbench.cmdline.PARALLEL_COMMAND}, prewarm = {cmd_warmup, sysbench.cmdline.PARALLEL_COMMAND} } -- Template strings of random digits with 11-digit groups separated by dashes -- 10 groups, 119 characters local c_value_template = "###########-###########-###########-" .. "###########-###########-###########-" .. "###########-###########-###########-" .. "###########" -- 5 groups, 59 characters local pad_value_template = "###########-###########-###########-" .. "###########-###########" function get_c_value() return sysbench.rand.string(c_value_template) end function get_pad_value() return sysbench.rand.string(pad_value_template) end function create_table(drv, con, table_num) local id_index_def, id_def local engine_def = "" local extra_table_options = "" local query if sysbench.opt.secondary then id_index_def = "KEY xid" else id_index_def = "PRIMARY KEY" end if drv:name() == "mysql" then if sysbench.opt.auto_inc then id_def = "INTEGER NOT NULL AUTO_INCREMENT" else id_def = "INTEGER NOT NULL" end engine_def = "/*! ENGINE = " .. sysbench.opt.mysql_storage_engine .. " */" elseif drv:name() == "pgsql" then if not sysbench.opt.auto_inc then id_def = "INTEGER NOT NULL" elseif pgsql_variant == 'redshift' then id_def = "INTEGER IDENTITY(1,1)" else id_def = "SERIAL" end else error("Unsupported database driver:" .. drv:name()) end print(string.format("Creating table 'sbtest%d'...", table_num)) query = string.format([[ CREATE TABLE sbtest%d( id %s, k INTEGER DEFAULT '0' NOT NULL, c CHAR(120) DEFAULT '' NOT NULL, pad CHAR(60) DEFAULT '' NOT NULL, %s (id) ) %s %s]], table_num, id_def, id_index_def, engine_def, sysbench.opt.create_table_options) con:query(query) if (sysbench.opt.table_size > 0) then print(string.format("Inserting %d records into 'sbtest%d'", sysbench.opt.table_size, table_num)) end if sysbench.opt.auto_inc then query = "INSERT INTO sbtest" .. table_num .. "(k, c, pad) VALUES" else query = "INSERT INTO sbtest" .. table_num .. "(id, k, c, pad) VALUES" end con:bulk_insert_init(query) local c_val local pad_val for i = 1, sysbench.opt.table_size do c_val = get_c_value() pad_val = get_pad_value() if (sysbench.opt.auto_inc) then query = string.format("(%d, '%s', '%s')", sysbench.rand.default(1, sysbench.opt.table_size), c_val, pad_val) else query = string.format("(%d, %d, '%s', '%s')", i, sysbench.rand.default(1, sysbench.opt.table_size), c_val, pad_val) end con:bulk_insert_next(query) end con:bulk_insert_done() if sysbench.opt.create_secondary then print(string.format("Creating a secondary index on 'sbtest%d'...", table_num)) con:query(string.format("CREATE INDEX k_%d ON sbtest%d(k)", table_num, table_num)) end end local t = sysbench.sql.type local stmt_defs = { point_selects = { "SELECT c FROM sbtest%u WHERE id=?", t.INT}, simple_ranges = { "SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ?", t.INT, t.INT}, sum_ranges = { "SELECT SUM(k) FROM sbtest%u WHERE id BETWEEN ? AND ?", t.INT, t.INT}, order_ranges = { "SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c", t.INT, t.INT}, distinct_ranges = { "SELECT DISTINCT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c", t.INT, t.INT}, index_updates = { "UPDATE sbtest%u SET k=k+1 WHERE id=?", t.INT}, non_index_updates = { "UPDATE sbtest%u SET c=? WHERE id=?", {t.CHAR, 120}, t.INT}, deletes = { "DELETE FROM sbtest%u WHERE id=?", t.INT}, inserts = { "INSERT INTO sbtest%u (id, k, c, pad) VALUES (?, ?, ?, ?)", t.INT, t.INT, {t.CHAR, 120}, {t.CHAR, 60}}, } function prepare_begin() stmt.begin = con:prepare("BEGIN") end function prepare_commit() stmt.commit = con:prepare("COMMIT") end function prepare_for_each_table(key) for t = 1, sysbench.opt.tables do stmt[t][key] = con:prepare(string.format(stmt_defs[key][1], t)) local nparam = #stmt_defs[key] - 1 if nparam > 0 then param[t][key] = {} end for p = 1, nparam do local btype = stmt_defs[key][p+1] local len if type(btype) == "table" then len = btype[2] btype = btype[1] end if btype == sysbench.sql.type.VARCHAR or btype == sysbench.sql.type.CHAR then param[t][key][p] = stmt[t][key]:bind_create(btype, len) else param[t][key][p] = stmt[t][key]:bind_create(btype) end end if nparam > 0 then stmt[t][key]:bind_param(unpack(param[t][key])) end end end function prepare_point_selects() prepare_for_each_table("point_selects") end function prepare_simple_ranges() prepare_for_each_table("simple_ranges") end function prepare_sum_ranges() prepare_for_each_table("sum_ranges") end function prepare_order_ranges() prepare_for_each_table("order_ranges") end function prepare_distinct_ranges() prepare_for_each_table("distinct_ranges") end function prepare_index_updates() prepare_for_each_table("index_updates") end function prepare_non_index_updates() prepare_for_each_table("non_index_updates") end function prepare_delete_inserts() prepare_for_each_table("deletes") prepare_for_each_table("inserts") end function thread_init() drv = sysbench.sql.driver() con = drv:connect() -- Create global nested tables for prepared statements and their -- parameters. We need a statement and a parameter set for each combination -- of connection/table/query stmt = {} param = {} for t = 1, sysbench.opt.tables do stmt[t] = {} param[t] = {} end -- This function is a 'callback' defined by individual benchmark scripts prepare_statements() end -- Close prepared statements function close_statements() for t = 1, sysbench.opt.tables do for k, s in pairs(stmt[t]) do stmt[t][k]:close() end end if (stmt.begin ~= nil) then stmt.begin:close() end if (stmt.commit ~= nil) then stmt.commit:close() end end function thread_done() close_statements() con:disconnect() end function cleanup() local drv = sysbench.sql.driver() local con = drv:connect() for i = 1, sysbench.opt.tables do print(string.format("Dropping table 'sbtest%d'...", i)) con:query("DROP TABLE IF EXISTS sbtest" .. i ) end end local function get_table_num() return sysbench.rand.uniform(1, sysbench.opt.tables) end local function get_id() return sysbench.rand.default(1, sysbench.opt.table_size) end function begin() stmt.begin:execute() end function commit() stmt.commit:execute() end function execute_point_selects() local tnum = get_table_num() local i for i = 1, sysbench.opt.point_selects do param[tnum].point_selects[1]:set(get_id()) stmt[tnum].point_selects:execute() end end local function execute_range(key) local tnum = get_table_num() for i = 1, sysbench.opt[key] do local id = get_id() param[tnum][key][1]:set(id) param[tnum][key][2]:set(id + sysbench.opt.range_size - 1) stmt[tnum][key]:execute() end end function execute_simple_ranges() execute_range("simple_ranges") end function execute_sum_ranges() execute_range("sum_ranges") end function execute_order_ranges() execute_range("order_ranges") end function execute_distinct_ranges() execute_range("distinct_ranges") end function execute_index_updates() local tnum = get_table_num() for i = 1, sysbench.opt.index_updates do param[tnum].index_updates[1]:set(get_id()) stmt[tnum].index_updates:execute() end end function execute_non_index_updates() local tnum = get_table_num() for i = 1, sysbench.opt.non_index_updates do param[tnum].non_index_updates[1]:set_rand_str(c_value_template) param[tnum].non_index_updates[2]:set(get_id()) stmt[tnum].non_index_updates:execute() end end function execute_delete_inserts() local tnum = get_table_num() for i = 1, sysbench.opt.delete_inserts do local id = get_id() local k = get_id() param[tnum].deletes[1]:set(id) param[tnum].inserts[1]:set(id) param[tnum].inserts[2]:set(k) param[tnum].inserts[3]:set_rand_str(c_value_template) param[tnum].inserts[4]:set_rand_str(pad_value_template) stmt[tnum].deletes:execute() stmt[tnum].inserts:execute() end end -- Re-prepare statements if we have reconnected, which is possible when some of -- the listed error codes are in the --mysql-ignore-errors list function sysbench.hooks.before_restart_event(errdesc) if errdesc.sql_errno == 2013 or -- CR_SERVER_LOST errdesc.sql_errno == 2055 or -- CR_SERVER_LOST_EXTENDED errdesc.sql_errno == 2006 or -- CR_SERVER_GONE_ERROR errdesc.sql_errno == 2011 -- CR_TCP_CONNECTION then close_statements() prepare_statements() end end function check_reconnect() if sysbench.opt.reconnect > 0 then transactions = (transactions or 0) + 1 if transactions % sysbench.opt.reconnect == 0 then close_statements() con:reconnect() prepare_statements() end end end ================================================ FILE: src/lua/oltp_delete.lua ================================================ #!/usr/bin/env sysbench -- Copyright (C) 2006-2017 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ---------------------------------------------------------------------- -- Delete-Only OLTP benchmark -- ---------------------------------------------------------------------- require("oltp_common") function prepare_statements() prepare_for_each_table("deletes") end function event() local tnum = sysbench.rand.uniform(1, sysbench.opt.tables) local id = sysbench.rand.default(1, sysbench.opt.table_size) param[tnum].deletes[1]:set(id) stmt[tnum].deletes:execute() check_reconnect() end ================================================ FILE: src/lua/oltp_insert.lua ================================================ #!/usr/bin/env sysbench -- Copyright (C) 2006-2017 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ---------------------------------------------------------------------- -- Insert-Only OLTP benchmark -- ---------------------------------------------------------------------- require("oltp_common") sysbench.cmdline.commands.prepare = { function () if (not sysbench.opt.auto_inc) then -- Create empty tables on prepare when --auto-inc is off, since IDs -- generated on prepare may collide later with values generated by -- sysbench.rand.unique() sysbench.opt.table_size=0 end cmd_prepare() end, sysbench.cmdline.PARALLEL_COMMAND } function prepare_statements() -- We do not use prepared statements here, but oltp_common.sh expects this -- function to be defined end function event() local table_name = "sbtest" .. sysbench.rand.uniform(1, sysbench.opt.tables) local k_val = sysbench.rand.default(1, sysbench.opt.table_size) local c_val = get_c_value() local pad_val = get_pad_value() if (drv:name() == "pgsql" and sysbench.opt.auto_inc) then con:query(string.format("INSERT INTO %s (k, c, pad) VALUES " .. "(%d, '%s', '%s')", table_name, k_val, c_val, pad_val)) else if (sysbench.opt.auto_inc) then i = 0 else -- Convert a uint32_t value to SQL INT i = sysbench.rand.unique() - 2147483648 end con:query(string.format("INSERT INTO %s (id, k, c, pad) VALUES " .. "(%d, %d, '%s', '%s')", table_name, i, k_val, c_val, pad_val)) end check_reconnect() end ================================================ FILE: src/lua/oltp_point_select.lua ================================================ #!/usr/bin/env sysbench -- Copyright (C) 2006-2017 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ---------------------------------------------------------------------- -- OLTP Point Select benchmark -- ---------------------------------------------------------------------- require("oltp_common") function prepare_statements() -- use 1 query per event, rather than sysbench.opt.point_selects which -- defaults to 10 in other OLTP scripts sysbench.opt.point_selects=1 prepare_point_selects() end function event() execute_point_selects() check_reconnect() end ================================================ FILE: src/lua/oltp_read_only.lua ================================================ #!/usr/bin/env sysbench -- Copyright (C) 2006-2017 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ---------------------------------------------------------------------- -- Read-Only OLTP benchmark -- ---------------------------------------------------------------------- require("oltp_common") function prepare_statements() prepare_point_selects() if not sysbench.opt.skip_trx then prepare_begin() prepare_commit() end if sysbench.opt.range_selects then prepare_simple_ranges() prepare_sum_ranges() prepare_order_ranges() prepare_distinct_ranges() end end function event() if not sysbench.opt.skip_trx then begin() end execute_point_selects() if sysbench.opt.range_selects then execute_simple_ranges() execute_sum_ranges() execute_order_ranges() execute_distinct_ranges() end if not sysbench.opt.skip_trx then commit() end check_reconnect() end ================================================ FILE: src/lua/oltp_read_write.lua ================================================ #!/usr/bin/env sysbench -- Copyright (C) 2006-2017 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ---------------------------------------------------------------------- -- Read/Write OLTP benchmark -- ---------------------------------------------------------------------- require("oltp_common") function prepare_statements() if not sysbench.opt.skip_trx then prepare_begin() prepare_commit() end prepare_point_selects() if sysbench.opt.range_selects then prepare_simple_ranges() prepare_sum_ranges() prepare_order_ranges() prepare_distinct_ranges() end prepare_index_updates() prepare_non_index_updates() prepare_delete_inserts() end function event() if not sysbench.opt.skip_trx then begin() end execute_point_selects() if sysbench.opt.range_selects then execute_simple_ranges() execute_sum_ranges() execute_order_ranges() execute_distinct_ranges() end execute_index_updates() execute_non_index_updates() execute_delete_inserts() if not sysbench.opt.skip_trx then commit() end check_reconnect() end ================================================ FILE: src/lua/oltp_update_index.lua ================================================ #!/usr/bin/env sysbench -- Copyright (C) 2006-2017 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ---------------------------------------------------------------------- -- Update-Index OLTP benchmark -- ---------------------------------------------------------------------- require("oltp_common") function prepare_statements() prepare_index_updates() end function event() execute_index_updates(con) check_reconnect() end ================================================ FILE: src/lua/oltp_update_non_index.lua ================================================ #!/usr/bin/env sysbench -- Copyright (C) 2006-2017 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ---------------------------------------------------------------------- -- Update-Non-Index OLTP benchmark -- ---------------------------------------------------------------------- require("oltp_common") function prepare_statements() prepare_non_index_updates() end function event() execute_non_index_updates() check_reconnect() end ================================================ FILE: src/lua/oltp_write_only.lua ================================================ #!/usr/bin/env sysbench -- Copyright (C) 2006-2017 Alexey Kopytov -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- ---------------------------------------------------------------------- -- Write-Only OLTP benchmark -- ---------------------------------------------------------------------- require("oltp_common") function prepare_statements() if not sysbench.opt.skip_trx then prepare_begin() prepare_commit() end prepare_index_updates() prepare_non_index_updates() prepare_delete_inserts() end function event() if not sysbench.opt.skip_trx then begin() end execute_index_updates() execute_non_index_updates() execute_delete_inserts() if not sysbench.opt.skip_trx then commit() end check_reconnect() end ================================================ FILE: src/lua/prime-test.lua ================================================ #!/usr/bin/env sysbench -- you can run this script like this: -- $ ./prime-test.lua --cpu-max-prime=20000 --threads=8 --histogram --report-interval=1 run sysbench.cmdline.options = { -- the default values for built-in options are currently ignored, see -- https://github.com/akopytov/sysbench/issues/151 ["cpu-max-prime"] = {"CPU maximum prime", 10000}, ["threads"] = {"Number of threads", 1}, ["histogram"] = {"Show histogram", "off"}, ["report-interval"] = {"Report interval", 1} } function event() local n = 0 for c = 3, sysbench.opt.cpu_max_prime do local t = math.sqrt(c) local isprime = true for l = 2, t do if c % l == 0 then isprime = false break end end if isprime then n = n + 1 end end end function sysbench.hooks.report_cumulative(stat) local seconds = stat.time_interval print(string.format([[ { "errors": %4.0f, "events": %4.0f, "latency_avg": %4.10f, "latency_max": %4.10f, "latency_min": %4.10f, "latency_pct": %4.10f, "latency_sum": %4.10f, "other": %4.0f, "reads": %4.0f, "reconnects": %4.0f, "threads_running": %4.0f, "time_interval": %4.10f, "time_total": %4.10f, "writes": %4.0f } ]], stat.errors, stat.events, stat.latency_avg, stat.latency_max, stat.latency_min, stat.latency_pct, stat.latency_sum, stat.other, stat.reads, stat.reconnects, stat.threads_running, stat.time_interval, stat.time_total, stat.writes)) end ================================================ FILE: src/lua/select_random_points.lua ================================================ #!/usr/bin/env sysbench -- This test is designed for testing MariaDB's key_cache_segments for MyISAM, -- and should work with other storage engines as well. -- -- For details about key_cache_segments please refer to: -- http://kb.askmonty.org/v/segmented-key-cache -- require("oltp_common") -- Add random_points to the list of standard OLTP options sysbench.cmdline.options.random_points = {"Number of random points in the IN() clause in generated SELECTs", 10} -- Override standard prepare/cleanup OLTP functions, as this benchmark does not -- support multiple tables oltp_prepare = prepare oltp_cleanup = cleanup function prepare() assert(sysbench.opt.tables == 1, "this benchmark does not support " .. "--tables > 1") oltp_prepare() end function cleanup() assert(sysbench.opt.tables == 1, "this benchmark does not support " .. "--tables > 1") oltp_cleanup() end function thread_init() drv = sysbench.sql.driver() con = drv:connect() local points = string.rep("?, ", sysbench.opt.random_points - 1) .. "?" stmt = con:prepare(string.format([[ SELECT id, k, c, pad FROM sbtest1 WHERE k IN (%s) ]], points)) params = {} for j = 1, sysbench.opt.random_points do params[j] = stmt:bind_create(sysbench.sql.type.INT) end stmt:bind_param(unpack(params)) rlen = sysbench.opt.table_size / sysbench.opt.threads thread_id = sysbench.tid % sysbench.opt.threads end function thread_done() stmt:close() con:disconnect() end function event() -- To prevent overlapping of our range queries we need to partition the whole -- table into 'threads' segments and then make each thread work with its -- own segment. for i = 1, sysbench.opt.random_points do local rmin = rlen * thread_id local rmax = rmin + rlen params[i]:set(sysbench.rand.default(rmin, rmax)) end stmt:execute() check_reconnect() end ================================================ FILE: src/lua/select_random_ranges.lua ================================================ #!/usr/bin/env sysbench -- This test is designed for testing MariaDB's key_cache_segments for MyISAM, -- and should work with other storage engines as well. -- -- For details about key_cache_segments please refer to: -- http://kb.askmonty.org/v/segmented-key-cache -- require("oltp_common") -- Add --number-of-ranges and --delta to the list of standard OLTP options sysbench.cmdline.options.number_of_ranges = {"Number of random BETWEEN ranges per SELECT", 10} sysbench.cmdline.options.delta = {"Size of BETWEEN ranges", 5} -- Override standard prepare/cleanup OLTP functions, as this benchmark does not -- support multiple tables oltp_prepare = prepare oltp_cleanup = cleanup function prepare() assert(sysbench.opt.tables == 1, "this benchmark does not support " .. "--tables > 1") oltp_prepare() end function cleanup() assert(sysbench.opt.tables == 1, "this benchmark does not support " .. "--tables > 1") oltp_cleanup() end function thread_init() drv = sysbench.sql.driver() con = drv:connect() local ranges = string.rep("k BETWEEN ? AND ? OR ", sysbench.opt.number_of_ranges - 1) .. "k BETWEEN ? AND ?" stmt = con:prepare(string.format([[ SELECT count(k) FROM sbtest1 WHERE %s]], ranges)) params = {} for j = 1, sysbench.opt.number_of_ranges*2 do params[j] = stmt:bind_create(sysbench.sql.type.INT) end stmt:bind_param(unpack(params)) rlen = sysbench.opt.table_size / sysbench.opt.threads thread_id = sysbench.tid % sysbench.opt.threads end function thread_done() stmt:close() con:disconnect() end function event() -- To prevent overlapping of our range queries we need to partition the whole -- table into 'threads' segments and then make each thread work with its -- own segment. for i = 1, sysbench.opt.number_of_ranges*2, 2 do local rmin = rlen * thread_id local rmax = rmin + rlen local val = sysbench.rand.default(rmin, rmax) params[i]:set(val) params[i+1]:set(val + sysbench.opt.delta) end stmt:execute() check_reconnect() end ================================================ FILE: src/sb_barrier.c ================================================ /* Copyright (C) 2016-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Thread barrier implementation. It differs from pthread_barrier_t in two ways: - it's more portable (will also work on OS X). - it allows defining a callback function which is called right before signaling the participating threads to continue, i.e. as soon as the required number of threads reach the barrier. The callback can also signal an error to sb_barrier_wait() callers by returning a non-zero value. In which case sb_barrier_wait() returns a negative value to all callers. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "sb_barrier.h" int sb_barrier_init(sb_barrier_t *barrier, unsigned int count, sb_barrier_cb_t callback, void *arg) { if (count == 0) return 1; if (pthread_mutex_init(&barrier->mutex, NULL) || pthread_cond_init(&barrier->cond, NULL)) return 1; barrier->init_count = count; barrier->count = count; barrier->callback = callback; barrier->arg = arg; barrier->serial = 0; barrier->error = 0; return 0; } int sb_barrier_wait(sb_barrier_t *barrier) { int res; pthread_mutex_lock(&barrier->mutex); if (!--barrier->count) { barrier->serial++; barrier->count = barrier->init_count; res = SB_BARRIER_SERIAL_THREAD; pthread_cond_broadcast(&barrier->cond); if (barrier->callback != NULL && barrier->callback(barrier->arg) != 0) { barrier->error = 1; res = -1; } pthread_mutex_unlock(&barrier->mutex); } else { unsigned int serial = barrier->serial; do { pthread_cond_wait(&barrier->cond, &barrier->mutex); } while (serial == barrier->serial); res = barrier->error ? -1 : 0; pthread_mutex_unlock(&barrier->mutex); } return res; } void sb_barrier_destroy(sb_barrier_t *barrier) { pthread_mutex_destroy(&barrier->mutex); pthread_cond_destroy(&barrier->cond); } ================================================ FILE: src/sb_barrier.h ================================================ /* Copyright (C) 2016-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Thread barrier implementation. */ #ifndef SB_BARRIER_H #define SB_BARRIER_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_PTHREAD_H # include #endif #define SB_BARRIER_SERIAL_THREAD 1 typedef int (*sb_barrier_cb_t)(void *); typedef struct { unsigned int count; unsigned int init_count; unsigned int serial; pthread_mutex_t mutex; pthread_cond_t cond; sb_barrier_cb_t callback; void *arg; int error; } sb_barrier_t; int sb_barrier_init(sb_barrier_t *barrier, unsigned int count, sb_barrier_cb_t callback, void *arg); int sb_barrier_wait(sb_barrier_t *barrier); void sb_barrier_destroy(sb_barrier_t *barrier); #endif /* SB_BARRIER_H */ ================================================ FILE: src/sb_ck_pr.h ================================================ /* Copyright (C) 2017 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * This file incorporates work covered by the following copyright and * permission notice: * * Copyright 2010 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Compatibility wrappers for ConcurrencyKit functions. ConcurrencyKit does not implement 64-bit atomic primitives on some 32-bit architectures (e.g. x86, ARMv6) natively. Newer versions support the CK_USE_CC_BUILTINS define which allows resorting to compiler builtins emulating 64-bit atomics on 32-bit architectures. However, one might want to build with an old, distribution-provided CK version where that option is not available. For those versions, define 64-bit atomics as aliases to GCC builtins. A cleaner solution would be to define the corresponding sysbench data structures as 32-bit integers on those architectures, but the amount of extra code to implement and support is not worth it. Code below has been copied with modifications from gcc/ck_pr.h from the ConcurrencyKit distribution. */ #ifndef SB_CK_H #define SB_CK_H #include "ck_pr.h" #if !defined(CK_F_PR_LOAD_64) #ifndef __GNUC__ # error Unsupported platform #endif #include #define CK_PR_ACCESS(x) (*(volatile __typeof__(x) *)&(x)) #define CK_PR_LOAD(S, M, T) \ CK_CC_INLINE static T \ ck_pr_md_load_##S(const M *target) \ { \ T r; \ ck_pr_barrier(); \ r = CK_PR_ACCESS(*(const T *)target); \ ck_pr_barrier(); \ return (r); \ } \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ ck_pr_barrier(); \ CK_PR_ACCESS(*(T *)target) = v; \ ck_pr_barrier(); \ return; \ } #define CK_PR_LOAD_S(S, T) CK_PR_LOAD(S, T, T) CK_PR_LOAD_S(64, uint64_t) #undef CK_PR_LOAD_S #undef CK_PR_LOAD #define CK_PR_LOAD_SAFE(SRC, TYPE) ck_pr_md_load_##TYPE((SRC)) #define CK_PR_STORE_SAFE(DST, VAL, TYPE) \ ck_pr_md_store_##TYPE( \ ((void)sizeof(*(DST) = (VAL)), (DST)), \ (VAL)) #define ck_pr_load_64(SRC) CK_PR_LOAD_SAFE((SRC), 64) #define ck_pr_store_64(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), 64) /* * Atomic compare and swap. */ #define CK_PR_CAS(S, M, T) \ CK_CC_INLINE static bool \ ck_pr_cas_##S(M *target, T compare, T set) \ { \ bool z; \ z = __sync_bool_compare_and_swap((T *)target, compare, set); \ return z; \ } #define CK_PR_CAS_S(S, T) CK_PR_CAS(S, T, T) CK_PR_CAS_S(64, uint64_t) #undef CK_PR_CAS_S #undef CK_PR_CAS #define CK_PR_CAS_O(S, T) \ CK_CC_INLINE static bool \ ck_pr_cas_##S##_value(T *target, T compare, T set, T *v) \ { \ set = __sync_val_compare_and_swap(target, compare, set);\ *v = set; \ return (set == compare); \ } CK_PR_CAS_O(64, uint64_t) #undef CK_PR_CAS_O /* * Atomic store-only binary operations. */ #define CK_PR_BINARY(K, S, M, T) \ CK_CC_INLINE static void \ ck_pr_##K##_##S(M *target, T d) \ { \ d = __sync_fetch_and_##K((T *)target, d); \ return; \ } #define CK_PR_BINARY_S(K, S, T) CK_PR_BINARY(K, S, T, T) #define CK_PR_GENERATE(K) \ CK_PR_BINARY_S(K, 64, uint64_t) CK_PR_GENERATE(add) CK_PR_GENERATE(sub) CK_PR_GENERATE(and) CK_PR_GENERATE(or) CK_PR_GENERATE(xor) #undef CK_PR_GENERATE #undef CK_PR_BINARY_S #undef CK_PR_BINARY #define CK_PR_UNARY(S, M, T) \ CK_CC_INLINE static void \ ck_pr_inc_##S(M *target) \ { \ ck_pr_add_##S(target, (T)1); \ return; \ } \ CK_CC_INLINE static void \ ck_pr_dec_##S(M *target) \ { \ ck_pr_sub_##S(target, (T)1); \ return; \ } #define CK_PR_UNARY_S(S, M) CK_PR_UNARY(S, M, M) CK_PR_UNARY_S(64, uint64_t) #undef CK_PR_UNARY_S #undef CK_PR_UNARY #define CK_PR_FAA(S, M, T, C) \ CK_CC_INLINE static C \ ck_pr_faa_##S(M *target, T delta) \ { \ T previous; \ C punt; \ punt = (C)ck_pr_md_load_##S(target); \ previous = (T)punt; \ while (ck_pr_cas_##S##_value(target, \ (C)previous, \ (C)(previous + delta), \ &previous) == false) \ ck_pr_stall(); \ \ return ((C)previous); \ } #define CK_PR_FAS(S, M, C) \ CK_CC_INLINE static C \ ck_pr_fas_##S(M *target, C update) \ { \ C previous; \ previous = ck_pr_md_load_##S(target); \ while (ck_pr_cas_##S##_value(target, \ previous, \ update, \ &previous) == false) \ ck_pr_stall(); \ \ return (previous); \ } #define CK_PR_FAA_S(S, M) CK_PR_FAA(S, M, M, M) #define CK_PR_FAS_S(S, M) CK_PR_FAS(S, M, M) CK_PR_FAA_S(64, uint64_t) CK_PR_FAS_S(64, uint64_t) #undef CK_PR_FAA_S #undef CK_PR_FAA #undef CK_PR_FAS_S #undef CK_PR_FAS #endif /* !CK_F_PR_LOAD_64*/ #endif /* SB_CK_H */ ================================================ FILE: src/sb_counter.c ================================================ /* Copyright (C) 2017 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "sb_counter.h" #include "sysbench.h" #include "sb_util.h" #include "sb_ck_pr.h" sb_counters_t *sb_counters CK_CC_CACHELINE; static sb_counters_t last_intermediate_counters; static sb_counters_t last_cumulative_counters; /* Initialize per-thread stats */ int sb_counters_init(void) { SB_COMPILE_TIME_ASSERT(sizeof(sb_counters_t) % CK_MD_CACHELINE == 0); sb_counters = sb_alloc_per_thread_array(sizeof(sb_counters_t)); return sb_counters == NULL; } void sb_counters_done(void) { if (sb_counters != NULL) { free(sb_counters); sb_counters = NULL; } } static void sb_counters_merge(sb_counters_t dst) { for (size_t t = 0; t < SB_CNT_MAX; t++) for (size_t i = 0; i < sb_globals.threads; i++) dst[t] += sb_counter_val(i, t); } static void sb_counters_checkpoint(sb_counters_t dst, sb_counters_t cp) { for (size_t i = 0; i < SB_CNT_MAX; i++) { uint64_t tmp = cp[i]; cp[i] = dst[i]; dst[i] = dst[i] - tmp; } } /* Return aggregate counter values since the last intermediate report. This is not thread-safe as it updates the global last report state, so it must be called from a single thread. */ void sb_counters_agg_intermediate(sb_counters_t val) { memset(val, 0, sizeof(sb_counters_t)); sb_counters_merge(val); sb_counters_checkpoint(val, last_intermediate_counters); } /* Return aggregate counter values since the last cumulative report. This is not thread-safe as it updates the global last report state, so it must be called from a single thread. */ void sb_counters_agg_cumulative(sb_counters_t val) { memset(val, 0, sizeof(sb_counters_t)); sb_counters_merge(val); sb_counters_checkpoint(val, last_cumulative_counters); } ================================================ FILE: src/sb_counter.h ================================================ /* Copyright (C) 2017 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_COUNTER_H #define SB_COUNTER_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef STDC_HEADERS # include #endif #include "sb_util.h" #include "sb_ck_pr.h" /* Statistic counter types */ typedef enum { SB_CNT_OTHER, /* unknown type of queries */ SB_CNT_READ, /* reads */ SB_CNT_WRITE, /* writes */ SB_CNT_EVENT, /* events */ SB_CNT_ERROR, /* errors */ SB_CNT_RECONNECT, /* reconnects */ SB_CNT_BYTES_READ, /* bytes read */ SB_CNT_BYTES_WRITTEN, /* bytes written */ SB_CNT_MAX } sb_counter_type_t; /* sizeof(sb_counters_t) must be a multiple of CK_MD_CACHELINE to avoid cache line sharing. */ typedef uint64_t sb_counters_t[SB_ALIGN(SB_CNT_MAX * sizeof(uint64_t), CK_MD_CACHELINE) / sizeof(uint64_t)]; extern sb_counters_t *sb_counters; int sb_counters_init(void); void sb_counters_done(void); /* Cannot use C99 inline here, because CK atomic primitives use static inlines which in turn leads to compiler warnings. So for performance reasons the following functions are defined 'static inline' too everywhere except sb_lua.c where they are declared and defined as external linkage functions to be available from LuaJIT FFI. */ #ifndef SB_LUA_EXPORT # define SB_LUA_INLINE static inline #else # define SB_LUA_INLINE uint64_t sb_counter_val(int thread_id, sb_counter_type_t type); void sb_counter_add(int thread_id, sb_counter_type_t type, uint64_t val); void sb_counter_inc(int thread_id, sb_counter_type_t type); #endif /* Return the current value for a given counter */ SB_LUA_INLINE uint64_t sb_counter_val(int thread_id, sb_counter_type_t type) { return ck_pr_load_64(&sb_counters[thread_id][type]); } /* Add a given value to a given stat counter for a given thread */ SB_LUA_INLINE void sb_counter_add(int thread_id, sb_counter_type_t type, uint64_t val) { ck_pr_store_64(&sb_counters[thread_id][type], sb_counter_val(thread_id, type) + val); } /* Increment a given stat counter for a given thread */ SB_LUA_INLINE void sb_counter_inc(int thread_id, sb_counter_type_t type) { sb_counter_add(thread_id, type, 1); } #undef SB_LUA_INLINE /* Return aggregate counter values since the last intermediate report. This is not thread-safe as it updates the global last report state, so it must be called from a single thread. */ void sb_counters_agg_intermediate(sb_counters_t val); /* Return aggregate counter values since the last cumulative report. This is not thread-safe as it updates the global last report state, so it must be called from a single thread. */ void sb_counters_agg_cumulative(sb_counters_t val); #endif ================================================ FILE: src/sb_global.h ================================================ /* Copyright (C) 2016 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Global and portability-related macros */ #ifndef SB_GLOBAL_H #define SB_GLOBAL_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #endif /* SB_GLOBAL_H */ ================================================ FILE: src/sb_histogram.c ================================================ /* Copyright (C) 2011-2018 Alexey Kopytov. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef STDC_HEADERS # include # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_MATH_H # include #endif #include "sysbench.h" #include "sb_histogram.h" #include "sb_logger.h" #include "sb_rand.h" #include "sb_ck_pr.h" #include "ck_cc.h" #include "sb_util.h" /* Number of slots for current histogram array. TODO: replace this constant with some autodetection code based on the number of available cores or some such. */ #define SB_HISTOGRAM_NSLOTS 128 /* Global latency histogram */ sb_histogram_t sb_latency_histogram CK_CC_CACHELINE; int sb_histogram_init(sb_histogram_t *h, size_t size, double range_min, double range_max) { size_t i; uint64_t *tmp; /* Allocate memory for cumulative_array + temp_array + all slot arrays */ tmp = (uint64_t *) calloc(size * (SB_HISTOGRAM_NSLOTS + 2), sizeof(uint64_t)); h->interm_slots = (uint64_t **) malloc(SB_HISTOGRAM_NSLOTS * sizeof(uint64_t *)); if (tmp == NULL || h->interm_slots == NULL) { log_text(LOG_FATAL, "Failed to allocate memory for a histogram object, size = %zd", size); return 1; } h->cumulative_array = tmp; tmp += size; h->temp_array = tmp; tmp += size; for (i = 0; i < SB_HISTOGRAM_NSLOTS; i++) { h->interm_slots[i] = tmp; tmp += size; } h->range_deduct = log(range_min); h->range_mult = (size - 1) / (log(range_max) - h->range_deduct); h->range_min = range_min; h->range_max = range_max; h->array_size = size; pthread_rwlock_init(&h->lock, NULL); return 0; } void sb_histogram_update(sb_histogram_t *h, double value) { size_t slot; ssize_t i; slot = sb_rand_uniform_uint64() % SB_HISTOGRAM_NSLOTS; i = floor((log(value) - h->range_deduct) * h->range_mult + 0.5); if (SB_UNLIKELY(i < 0)) i = 0; else if (SB_UNLIKELY(i >= (ssize_t) (h->array_size))) i = h->array_size - 1; ck_pr_inc_64(&h->interm_slots[slot][i]); } double sb_histogram_get_pct_intermediate(sb_histogram_t *h, double percentile) { size_t i, s; uint64_t nevents, ncur, nmax; double res; nevents = 0; /* This can be called concurrently with other sb_histogram_get_pct_*() functions, so use the lock to protect shared structures. This will not block sb_histogram_update() calls, but we make sure we don't lose any concurrent increments by atomically fetching each array element and replacing it with 0. */ pthread_rwlock_wrlock(&h->lock); /* Merge intermediate slots into temp_array. */ const size_t size = h->array_size; uint64_t * const array = h->temp_array; for (i = 0; i < size; i++) { array[i] = ck_pr_fas_64(&h->interm_slots[0][i], 0); nevents += array[i]; } for (s = 1; s < SB_HISTOGRAM_NSLOTS; s++) { for (i = 0; i < size; i++) { uint64_t t; t = ck_pr_fas_64(&h->interm_slots[s][i], 0); array[i] += t; nevents += t; } } /* Now that we have an aggregate 'snapshot' of current arrays and the total number of events in it, calculate the current, intermediate percentile value to return. */ nmax = floor(nevents * percentile / 100 + 0.5); ncur = 0; for (i = 0; i < size; i++) { ncur += array[i]; if (ncur >= nmax) break; } res = exp(i / h->range_mult + h->range_deduct); /* Finally, add temp_array into accumulated values in cumulative_array. */ for (i = 0; i < size; i++) { h->cumulative_array[i] += array[i]; } h->cumulative_nevents += nevents; pthread_rwlock_unlock(&h->lock); return res; } /* Aggregate arrays from intermediate slots into cumulative_array. This should be called with the histogram lock write-locked. */ static void merge_intermediate_into_cumulative(sb_histogram_t *h) { size_t i, s; uint64_t nevents; nevents = h->cumulative_nevents; const size_t size = h->array_size; uint64_t * const array = h->cumulative_array; for (s = 0; s < SB_HISTOGRAM_NSLOTS; s++) { for (i = 0; i < size; i++) { uint64_t t = ck_pr_fas_64(&h->interm_slots[s][i], 0); array[i] += t; nevents += t; } } h->cumulative_nevents = nevents; } /* Calculate a given percentile from the cumulative array. This should be called with the histogram lock either read- or write-locked. */ static double get_pct_cumulative(sb_histogram_t *h, double percentile) { size_t i; uint64_t ncur, nmax; nmax = floor(h->cumulative_nevents * percentile / 100 + 0.5); ncur = 0; for (i = 0; i < h->array_size; i++) { ncur += h->cumulative_array[i]; if (ncur >= nmax) break; } return exp(i / h->range_mult + h->range_deduct); } double sb_histogram_get_pct_cumulative(sb_histogram_t *h, double percentile) { double res; /* This can be called concurrently with other sb_histogram_get_pct_*() functions, so use the lock to protect shared structures. This will not block sb_histogram_update() calls, but we make sure we don't lose any concurrent increments by atomically fetching each array element and replacing it with 0. */ pthread_rwlock_wrlock(&h->lock); merge_intermediate_into_cumulative(h); res = get_pct_cumulative(h, percentile); pthread_rwlock_unlock(&h->lock); return res; } double sb_histogram_get_pct_checkpoint(sb_histogram_t *h, double percentile) { double res; /* This can be called concurrently with other sb_histogram_get_pct_*() functions, so use the lock to protect shared structures. This will not block sb_histogram_update() calls, but we make sure we don't lose any concurrent increments by atomically fetching each array element and replacing it with 0. */ pthread_rwlock_wrlock(&h->lock); merge_intermediate_into_cumulative(h); res = get_pct_cumulative(h, percentile); /* Reset the cumulative array */ memset(h->cumulative_array, 0, h->array_size * sizeof(uint64_t)); h->cumulative_nevents = 0; pthread_rwlock_unlock(&h->lock); return res; } void sb_histogram_print(sb_histogram_t *h) { uint64_t maxcnt; int width; size_t i; pthread_rwlock_wrlock(&h->lock); merge_intermediate_into_cumulative(h); uint64_t * const array = h->cumulative_array; maxcnt = 0; for (i = 0; i < h->array_size; i++) { if (array[i] > maxcnt) maxcnt = array[i]; } if (maxcnt == 0) return; printf(" value ------------- distribution ------------- count\n"); for (i = 0; i < h->array_size; i++) { if (array[i] == 0) continue; width = floor(array[i] * (double) 40 / maxcnt + 0.5); printf("%12.3f |%-40.*s %lu\n", exp(i / h->range_mult + h->range_deduct), /* value */ width, "****************************************", /* distribution */ (unsigned long) array[i]); /* count */ } pthread_rwlock_unlock(&h->lock); } void sb_histogram_done(sb_histogram_t *h) { pthread_rwlock_destroy(&h->lock); free(h->cumulative_array); free(h->interm_slots); } /* Allocate a new histogram and initialize it with sb_histogram_init(). */ sb_histogram_t *sb_histogram_new(size_t size, double range_min, double range_max) { sb_histogram_t *h; if ((h = malloc(sizeof(*h))) == NULL) return NULL; if (sb_histogram_init(h, size, range_min, range_max)) { free(h); return NULL; } return h; } /* Deallocate a histogram allocated with sb_histogram_new(). */ void sb_histogram_delete(sb_histogram_t *h) { sb_histogram_done(h); free(h); } ================================================ FILE: src/sb_histogram.h ================================================ /* Copyright (C) 2011-2017 Alexey Kopytov. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_HISTOGRAM_H #define SB_HISTOGRAM_H #include #ifdef HAVE_PTHREAD_H # include #endif typedef struct { /* Cumulative histogram array. Updated 'on demand' by sb_histogram_get_pct_intermediate(). Protected by 'lock'. */ uint64_t *cumulative_array; /* Total number of events in cumulative_array. Updated on demand by sb_histogram_get_pct_intermediate(). Protected by 'lock'. */ uint64_t cumulative_nevents; /* Temporary array for intermediate percentile calculations. Protected by 'lock'. */ uint64_t *temp_array; /* Intermediate histogram values are split into multiple slots and updated with atomics. Aggregations into cumulative values is performed by sb_histogram_get_pct_intermediate() function. */ uint64_t **interm_slots; /* Number of elements in each array */ size_t array_size; /* Lower bound of values to track */ double range_min; /* Upper bound of values to track */ double range_max; /* Value to deduct to calculate histogram range based on array element */ double range_deduct; /* Value to multiply to calculate histogram range based array element */ double range_mult; /* rwlock to protect cumulative_array and cumulative_nevents from concurrent updates. */ pthread_rwlock_t lock; } sb_histogram_t; /* Global latency histogram */ extern sb_histogram_t sb_latency_histogram; /* Allocate a new histogram and initialize it with sb_histogram_init(). */ sb_histogram_t *sb_histogram_new(size_t size, double range_min, double range_max); /* Deallocate a histogram allocated with sb_histogram_new(). */ void sb_histogram_delete(sb_histogram_t *h); /* Initialize a new histogram object with a given array size and value bounds. */ int sb_histogram_init(sb_histogram_t *h, size_t size, double range_min, double range_max); /* Update histogram with a given value. */ void sb_histogram_update(sb_histogram_t *h, double value); /* Calculate a given percentile value from the intermediate histogram values, then merge intermediate values into cumulative ones atomically, i.e. in a way that no concurrent updates are lost and will be accounted in either the current or later merge of intermediate clues. */ double sb_histogram_get_pct_intermediate(sb_histogram_t *h, double percentile); /* Merge intermediate histogram values into cumulative ones and calculate a given percentile value from the cumulative array. */ double sb_histogram_get_pct_cumulative(sb_histogram_t *h, double percentile); /* Similar to sb_histogram_get_pct_cumulative(), but also resets cumulative stats right after calculating the returned percentile. The reset happens atomically so that no conucrrent updates are lost after percentile calculation. This is currently used only by 'checkpoint' reports. */ double sb_histogram_get_pct_checkpoint(sb_histogram_t *h, double percentile); /* Print a given histogram to stdout */ void sb_histogram_print(sb_histogram_t *h); /* Destroy a given histogram object */ void sb_histogram_done(sb_histogram_t *h); #endif ================================================ FILE: src/sb_list.h ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2014 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_LIST_H #define SB_LIST_H typedef struct sb_list_item_t { struct sb_list_item_t *next_p; struct sb_list_item_t *prev_p; } sb_list_item_t; typedef sb_list_item_t sb_list_item; typedef sb_list_item_t sb_list_t ; #ifndef offsetof # define offsetof(type, member) ((size_t) &((type *)0)->member) #endif #define SB_LIST_DECLARE(name) \ SB_LIST_T name = { &(name), &(name) } #define SB_LIST_INIT(head_p) \ do { \ (head_p)->next_p = (head_p); \ (head_p)->prev_p = (head_p); \ } while (0) #define SB_LIST_ITEM_INIT(item_p) \ SB_LIST_INIT(item_p) #define SB_LIST_ADD(item_p, head_p) \ do { \ (item_p)->next_p = (head_p)->next_p; \ (item_p)->prev_p = (head_p); \ (head_p)->next_p = (item_p); \ (item_p)->next_p->prev_p = (item_p); \ } while (0) #define SB_LIST_ADD_TAIL(item_p, head_p) \ do { \ (item_p)->prev_p = (head_p)->prev_p; \ (item_p)->next_p = (head_p); \ (head_p)->prev_p = (item_p); \ (item_p)->prev_p->next_p = (item_p); \ } while (0); #define SB_LIST_DELETE(old_item_p) \ do { \ (old_item_p)->next_p->prev_p = (old_item_p)->prev_p; \ (old_item_p)->prev_p->next_p = (old_item_p)->next_p; \ } while (0) #define SB_LIST_REPLACE(item_p, old_item_p) \ do { \ (item_p)->next_p = (old_item_p)->next_p; \ (item_p)->prev_p = (old_item_p)->prev_p; \ (item_p)->next_p->prev_p = (item_p); \ (item_p)->prev_p->next_p = (item_p); \ } while (0) #define SB_LIST_IS_EMPTY(head_p) \ ((head_p)->next_p == (head_p)) #define SB_LIST_ITEM_IN_LIST(item_p) \ ((item_p)->next_p != (item_p)) #define SB_LIST_ITEM_FIRST(item_p, head_p) \ ((item_p)->prev_p != (head_p)) #define SB_LIST_ITEM_LAST(item_p, head_p) \ ((item_p)->next_p == (head_p)) #define SB_LIST_ITEM_NEXT(item_p) \ ((item_p)->next_p) #define SB_LIST_ITEM_PREV(item_p) \ ((item_p)->prev_p) #define SB_LIST_ENTRY(ptr, type, member) \ ((type *)(void *)(((char *)(ptr) - offsetof(type, member)))) #define SB_LIST_ONCE(pos_p, head_p) \ pos_p= (head_p)->next_p; if (pos_p != (head_p)) #define SB_LIST_FOR_EACH(pos_p, head_p) \ for (pos_p = (head_p)->next_p; pos_p != (head_p); pos_p = pos_p->next_p) #define SB_LIST_ENUM_START(head_p) \ (head_p) #define SB_LIST_ENUM_NEXT(pos_p, head_p) \ ((pos_p->next_p != (head_p)) ? (pos_p->next_p) : NULL) #define SB_LIST_FOR_EACH_SAFE(pos_p, temp_p, head_p) \ for (pos_p = (head_p)->next_p, temp_p = (pos_p)->next_p; pos_p != (head_p); \ pos_p = temp_p, temp_p = (pos_p)->next_p) #define SB_LIST_FOR_EACH_REV_SAFE(pos_p, temp_p, head_p) \ for (pos_p = (head_p)->prev_p, temp_p = (pos_p)->prev_p; pos_p != (head_p); \ pos_p = temp_p, temp_p = (pos_p)->prev_p) #endif /* SB_LIST_H */ ================================================ FILE: src/sb_logger.c ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef STDC_HEADERS # include # include # include #endif #ifdef HAVE_ERRNO_H # include #endif #ifdef HAVE_MATH_H # include #endif #include "sysbench.h" #include "sb_list.h" #include "sb_logger.h" #include "sb_histogram.h" #include "ck_cc.h" #define TEXT_BUFFER_SIZE 4096 #define ERROR_BUFFER_SIZE 256 /* Use 1024-element array for latency histogram tracking values between 0.001 milliseconds and 100 seconds. */ #define OPER_LOG_GRANULARITY 1024 #define OPER_LOG_MIN_VALUE 1e-3 #define OPER_LOG_MAX_VALUE 1E5 /* Array of message handlers (one chain per message type) */ static sb_list_t handlers[LOG_MSG_TYPE_MAX]; /* set after logger initialization */ static unsigned char initialized; static pthread_mutex_t text_mutex; static unsigned int text_cnt; static char text_buf[TEXT_BUFFER_SIZE]; static int text_handler_init(void); static int text_handler_process(log_msg_t *msg); static int oper_handler_init(void); static int oper_handler_done(void); /* Built-in log handlers */ /* Text messages handler */ static sb_arg_t text_handler_args[] = { SB_OPT("verbosity", "verbosity level {5 - debug, 0 - only critical messages}", "3", INT), SB_OPT_END }; static log_handler_t text_handler = { { &text_handler_init, &text_handler_process, NULL, }, text_handler_args, {0,0} }; /* Operation start/stop messages handler */ static sb_arg_t oper_handler_args[] = { SB_OPT("percentile", "percentile to calculate in latency statistics (1-100). " "Use the special value of 0 to disable percentile calculations", "95", INT), SB_OPT("histogram", "print latency histogram in report", "off", BOOL), SB_OPT_END }; static log_handler_t oper_handler = { { oper_handler_init, NULL, oper_handler_done, }, oper_handler_args, {0,0} }; /* Register logger and all handlers */ int log_register(void) { unsigned int i; for (i = 0; i < LOG_MSG_TYPE_MAX; i++) SB_LIST_INIT(handlers + i); log_add_handler(LOG_MSG_TYPE_TEXT, &text_handler); log_add_handler(LOG_MSG_TYPE_OPER, &oper_handler); return 0; } /* Display command line options for registered log handlers */ void log_print_help(void) { unsigned int i; sb_list_item_t *pos; log_handler_t *handler; printf("Log options:\n"); for (i = 0; i < LOG_MSG_TYPE_MAX; i++) { SB_LIST_FOR_EACH(pos, handlers + i) { handler = SB_LIST_ENTRY(pos, log_handler_t, listitem); if (handler->args != NULL) sb_print_options(handler->args); } } } /* Initialize logger and all handlers */ int log_init(void) { unsigned int i; sb_list_item_t *pos; log_handler_t *handler; for (i = 0; i < LOG_MSG_TYPE_MAX; i++) { SB_LIST_FOR_EACH(pos, handlers + i) { handler = SB_LIST_ENTRY(pos, log_handler_t, listitem); if (handler->ops.init != NULL && handler->ops.init()) return 1; } } /* required to let log_text() pass messages to handlers */ initialized = 1; return 0; } /* Uninitialize logger and all handlers */ void log_done(void) { unsigned int i; sb_list_item_t *pos; log_handler_t *handler; for (i = 0; i < LOG_MSG_TYPE_MAX; i++) { SB_LIST_FOR_EACH(pos, handlers + i) { handler = SB_LIST_ENTRY(pos, log_handler_t, listitem); if (handler->ops.done != NULL) handler->ops.done(); } } initialized = 0; } /* Add handler for a specified type of messages */ int log_add_handler(log_msg_type_t type, log_handler_t *handler) { if (type <= LOG_MSG_TYPE_MIN || type >= LOG_MSG_TYPE_MAX) return 1; if (handler->args != NULL) sb_register_arg_set(handler->args); SB_LIST_ADD_TAIL(&handler->listitem, handlers + type); return 0; } /* Main function to dispatch log messages */ void log_msg(log_msg_t *msg) { sb_list_item_t *pos; log_handler_t *handler; SB_LIST_FOR_EACH(pos, handlers + msg->type) { handler = SB_LIST_ENTRY(pos, log_handler_t, listitem); if (handler->ops.process != NULL) handler->ops.process(msg); } } static const char *get_msg_prefix(log_msg_priority_t priority) { const char * prefix; switch (priority) { case LOG_FATAL: prefix = "FATAL: "; break; case LOG_ALERT: prefix = "ALERT: "; break; case LOG_WARNING: prefix = "WARNING: "; break; case LOG_DEBUG: prefix = "DEBUG: "; break; default: prefix = ""; break; } return prefix; } /* printf-like wrapper to log text messages */ void log_text(log_msg_priority_t priority, const char *fmt, ...) { log_msg_t msg; log_msg_text_t text_msg; char buf[TEXT_BUFFER_SIZE]; va_list ap; int n, clen, maxlen; maxlen = TEXT_BUFFER_SIZE; clen = 0; va_start(ap, fmt); n = vsnprintf(buf + clen, maxlen, fmt, ap); va_end(ap); if (n < 0 || n >= maxlen) n = maxlen; clen += n; maxlen -= n; snprintf(buf + clen, maxlen, "\n"); /* No race condition here because log_init() is supposed to be called in a single-threaded stage */ if (!initialized) { printf("%s%s", get_msg_prefix(priority), buf); return; } msg.type = LOG_MSG_TYPE_TEXT; msg.data = (void *)&text_msg; text_msg.priority = priority; text_msg.text = buf; text_msg.flags = 0; log_msg(&msg); } /* variant of log_text() which prepends log lines with the elapsed time of a specified timer. */ void log_timestamp(log_msg_priority_t priority, double seconds, const char *fmt, ...) { log_msg_t msg; log_msg_text_t text_msg; char buf[TEXT_BUFFER_SIZE]; va_list ap; int n, clen, maxlen; maxlen = TEXT_BUFFER_SIZE; clen = 0; n = snprintf(buf, maxlen, "[ %.0fs ] ", seconds); clen += n; maxlen -= n; va_start(ap, fmt); n = vsnprintf(buf + clen, maxlen, fmt, ap); va_end(ap); if (n < 0 || n >= maxlen) n = maxlen; clen += n; maxlen -= n; snprintf(buf + clen, maxlen, "\n"); /* No race condition here because log_init() is supposed to be called in a single-threaded stage */ if (!initialized) { printf("%s%s", get_msg_prefix(priority), buf); return; } msg.type = LOG_MSG_TYPE_TEXT; msg.data = (void *)&text_msg; text_msg.priority = priority; text_msg.text = buf; /* Skip duplicate checks */ text_msg.flags = LOG_MSG_TEXT_ALLOW_DUPLICATES; log_msg(&msg); } /* printf-like wrapper to log system error messages */ void log_errno(log_msg_priority_t priority, const char *fmt, ...) { char buf[TEXT_BUFFER_SIZE]; char errbuf[ERROR_BUFFER_SIZE]; va_list ap; int n; int old_errno; char *tmp; old_errno = errno; #ifdef HAVE_STRERROR_R #ifdef STRERROR_R_CHAR_P tmp = strerror_r(old_errno, errbuf, sizeof(errbuf)); #else strerror_r(old_errno, errbuf, sizeof(errbuf)); tmp = errbuf; #endif /* STRERROR_R_CHAR_P */ #else /* !HAVE_STRERROR_P */ strncpy(errbuf, strerror(old_errno), sizeof(errbuf)); tmp = errbuf; #endif /* HAVE_STRERROR_P */ va_start(ap, fmt); n = vsnprintf(buf, TEXT_BUFFER_SIZE, fmt, ap); va_end(ap); if (n < 0 || n == TEXT_BUFFER_SIZE) return; snprintf(buf + n, TEXT_BUFFER_SIZE - n, " errno = %d (%s)", old_errno, tmp); log_text(priority, "%s", buf); } /* Initialize text handler */ int text_handler_init(void) { #ifdef HAVE_SETVBUF /* Set stdout to unbuffered mode */ setvbuf(stdout, NULL, _IONBF, 0); #endif sb_globals.verbosity = sb_get_value_int("verbosity"); if (sb_globals.verbosity > LOG_DEBUG) { printf("Invalid value for verbosity: %d\n", sb_globals.verbosity); return 1; } pthread_mutex_init(&text_mutex, NULL); text_cnt = 0; text_buf[0] = '\0'; return 0; } /* Print text message to the log */ int text_handler_process(log_msg_t *msg) { log_msg_text_t *text_msg = (log_msg_text_t *)msg->data; if (text_msg->priority > sb_globals.verbosity) return 0; if (!(text_msg->flags & LOG_MSG_TEXT_ALLOW_DUPLICATES)) { pthread_mutex_lock(&text_mutex); if (!strcmp(text_buf, text_msg->text)) { text_cnt++; pthread_mutex_unlock(&text_mutex); return 0; } else { if (text_cnt > 0) printf("(last message repeated %u times)\n", text_cnt); text_cnt = 0; strncpy(text_buf, text_msg->text, TEXT_BUFFER_SIZE); } pthread_mutex_unlock(&text_mutex); } printf("%s%s", get_msg_prefix(text_msg->priority), text_msg->text); return 0; } /* Initialize operation messages handler */ int oper_handler_init(void) { int tmp; tmp = sb_get_value_int("percentile"); if (tmp < 0 || tmp > 100) { log_text(LOG_FATAL, "Invalid value for --percentile: %d", tmp); return 1; } sb_globals.percentile = tmp; sb_globals.histogram = sb_get_value_flag("histogram"); if (sb_globals.percentile == 0 && sb_globals.histogram != 0) { log_text(LOG_FATAL, "--histogram cannot be used with --percentile=0"); return 1; } if (sb_histogram_init(&sb_latency_histogram, OPER_LOG_GRANULARITY, OPER_LOG_MIN_VALUE, OPER_LOG_MAX_VALUE)) return 1; return 0; } /* Uninitialize operations messages handler */ int oper_handler_done(void) { sb_histogram_done(&sb_latency_histogram); return 0; } ================================================ FILE: src/sb_logger.h ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2016 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_LOGGER_H #define SB_LOGGER_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_PTHREAD_H # include #endif #include "sb_util.h" #include "sb_options.h" #include "sb_timer.h" #include "sb_histogram.h" /* Text message flags (used in the 'flags' field of log_text_msg_t) */ #define LOG_MSG_TEXT_ALLOW_DUPLICATES 1 /* Message types definition */ typedef enum { LOG_MSG_TYPE_MIN, /* used for internal purposes */ LOG_MSG_TYPE_TEXT, /* arbitrary text messages */ LOG_MSG_TYPE_OPER, /* operation start/stop messages */ LOG_MSG_TYPE_MAX /* used for internal purposes */ } log_msg_type_t; /* Message priorities definition */ typedef enum { LOG_FATAL, /* system is unusable */ LOG_ALERT, /* user actions must be taken */ LOG_WARNING, /* warnings */ LOG_NOTICE, /* normal but significant messages */ LOG_INFO, /* informational messages */ LOG_DEBUG, /* debug-level messages */ LOG_MAX /* used for internal purposes */ } log_msg_priority_t; /* Text message definition */ typedef struct { log_msg_priority_t priority; char *text; unsigned int flags; } log_msg_text_t; /* Operation start/stop message definition */ typedef enum { LOG_MSG_OPER_START, LOG_MSG_OPER_STOP } log_msg_oper_action_t; typedef struct { log_msg_oper_action_t action; int thread_id; } log_msg_oper_t; /* General log message definition */ typedef struct { log_msg_type_t type; void *data; } log_msg_t; /* Log handler operations definition */ typedef int log_op_register(void); /* register handler options */ typedef int log_op_init(void); /* initialize log handler */ typedef int log_op_process(log_msg_t *msg); /* process message */ typedef int log_op_done(void); /* uninitialize log handler */ /* Log handler operations structure */ typedef struct { log_op_init *init; log_op_process *process; log_op_done *done; } log_handler_ops_t; /* Log handler definition */ typedef struct { log_handler_ops_t ops; /* handler operations */ sb_arg_t *args; /* handler arguments */ sb_list_item_t listitem; /* can be linked in a list */ } log_handler_t; /* Register logger */ int log_register(void); /* Display command line options for all register log handlers */ void log_print_help(void); /* Initialize logger */ int log_init(void); /* Add handler for a specified type of messages */ int log_add_handler(log_msg_type_t type, log_handler_t *handler); /* Main function to dispatch log messages */ void log_msg(log_msg_t *); /* printf-like wrapper to log text messages */ void log_text(log_msg_priority_t priority, const char *fmt, ...) SB_ATTRIBUTE_FORMAT(printf, 2, 3); /* variant of log_text() which prepends log lines with a elapsed time of the specified timer. */ void log_timestamp(log_msg_priority_t priority, double seconds, const char *fmt, ...) SB_ATTRIBUTE_FORMAT(printf, 3, 4); /* printf-like wrapper to log system error messages */ void log_errno(log_msg_priority_t priority, const char *fmt, ...) SB_ATTRIBUTE_FORMAT(printf, 2, 3); /* Uninitialize logger */ void log_done(void); #endif /* SB_LOGGER_H */ ================================================ FILE: src/sb_lua.c ================================================ /* Copyright (C) 2006 MySQL AB Copyright (C) 2006-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_LIBGEN_H # include #endif #include "sb_lua.h" #include "lua.h" #include "lualib.h" #include "lauxlib.h" #define SB_LUA_EXPORT #include "sb_counter.h" #undef SB_LUA_EXPORT #include "db_driver.h" #include "sb_rand.h" #include "sb_thread.h" #include "sb_ck_pr.h" /* Auto-generated headers for internal scripts. If you add a new header here, make sure it is also added to the internal_scripts array below. */ #include "lua/internal/sysbench.lua.h" #include "lua/internal/sysbench.cmdline.lua.h" #include "lua/internal/sysbench.rand.lua.h" #include "lua/internal/sysbench.sql.lua.h" #include "lua/internal/sysbench.histogram.lua.h" #define EVENT_FUNC "event" #define PREPARE_FUNC "prepare" #define CLEANUP_FUNC "cleanup" #define HELP_FUNC "help" #define THREAD_INIT_FUNC "thread_init" #define THREAD_DONE_FUNC "thread_done" #define THREAD_RUN_FUNC "thread_run" #define INIT_FUNC "init" #define DONE_FUNC "done" #define REPORT_INTERMEDIATE_HOOK "report_intermediate" #define REPORT_CUMULATIVE_HOOK "report_cumulative" #define xfree(ptr) ({ if ((ptr) != NULL) free((void *) ptr); ptr = NULL; }) /* Interpreter context */ typedef struct { db_conn_t *con; /* Database connection */ db_driver_t *driver; lua_State *L; } sb_lua_ctxt_t; typedef struct { int id; db_bind_type_t type; void *buf; unsigned long buflen; char is_null; } sb_lua_bind_t; typedef struct { const char *name; const unsigned char *source; /* Use a pointer, since _len variables are not compile-time constants */ size_t *source_len; } internal_script_t; typedef enum { SB_LUA_ERROR_NONE, SB_LUA_ERROR_RESTART_EVENT } sb_lua_error_t; bool sb_lua_more_events(int); int sb_lua_set_test_args(sb_arg_t *, size_t); /* Lua interpreter states */ static lua_State **states CK_CC_CACHELINE; static sb_test_t sbtest CK_CC_CACHELINE; static TLS sb_lua_ctxt_t tls_lua_ctxt CK_CC_CACHELINE; /* List of pre-loaded internal scripts */ static internal_script_t internal_scripts[] = { {"sysbench.rand.lua", sysbench_rand_lua, &sysbench_rand_lua_len}, {"sysbench.lua", sysbench_lua, &sysbench_lua_len}, {"sysbench.cmdline.lua", sysbench_cmdline_lua, &sysbench_cmdline_lua_len}, {"sysbench.sql.lua", sysbench_sql_lua, &sysbench_sql_lua_len}, {"sysbench.histogram.lua", sysbench_histogram_lua, &sysbench_histogram_lua_len}, {NULL, NULL, 0} }; /* Main (global) interpreter state */ static lua_State *gstate; /* Custom command name */ static const char * sb_lua_custom_command; /* Lua test operations */ static int sb_lua_op_init(void); static int sb_lua_op_done(void); static int sb_lua_op_thread_init(int); static int sb_lua_op_thread_run(int); static int sb_lua_op_thread_done(int); static sb_operations_t lua_ops = { .init = sb_lua_op_init, .thread_init = sb_lua_op_thread_init, .thread_done = sb_lua_op_thread_done, .report_intermediate = db_report_intermediate, .report_cumulative = db_report_cumulative, .done = sb_lua_op_done }; /* Lua test commands */ static int sb_lua_cmd_prepare(void); static int sb_lua_cmd_cleanup(void); static int sb_lua_cmd_help(void); /* Initialize interpreter state */ static lua_State *sb_lua_new_state(void); /* Close interpretet state */ static int sb_lua_close_state(lua_State *); static int read_cmdline_options(lua_State *L); static bool sb_lua_hook_defined(lua_State *, const char *); static bool sb_lua_hook_push(lua_State *, const char *); static void sb_lua_report_intermediate(sb_stat_t *); static void sb_lua_report_cumulative(sb_stat_t *); static int sb_lua_do_jitcmd(lua_State *L, const char *cmd); static void call_error(lua_State *L, const char *name) { const char * const err = lua_tostring(L, -1); log_text(LOG_FATAL, "`%s' function failed: %s", name, err ? err : "(not a string)"); lua_pop(L, 1); } static void report_error(lua_State *L) { const char * const err = lua_tostring(L, -1); log_text(LOG_FATAL, "%s", err ? err : "(not a string)"); lua_pop(L, 1); } static bool func_available(lua_State *L, const char *func) { lua_getglobal(L, func); bool rc = lua_isfunction(L, -1); lua_pop(L, 1); return rc; } /* Export command line options */ static int do_export_options(lua_State *L, bool global) { sb_list_item_t *pos; option_t *opt; char *tmp; if (!global) { lua_getglobal(L, "sysbench"); lua_pushliteral(L, "opt"); lua_newtable(L); } pos = sb_options_enum_start(); while ((pos = sb_options_enum_next(pos, &opt)) != NULL) { /* The only purpose of the following check if to keep compatibility with legacy scripts where options were exported to the global namespace. In which case name collisions with user-defined functions and variables might occur. For example, the --help option might redefine the help() function. */ if (global) { lua_getglobal(L, opt->name); if (lua_isfunction(L, -1)) { lua_pop(L, 1); continue; } lua_pop(L, 1); } else { lua_pushstring(L, opt->name); } switch (opt->type) { case SB_ARG_TYPE_BOOL: lua_pushboolean(L, sb_opt_to_flag(opt)); break; case SB_ARG_TYPE_INT: lua_pushnumber(L, sb_opt_to_int(opt)); break; case SB_ARG_TYPE_DOUBLE: lua_pushnumber(L, sb_opt_to_double(opt)); break; case SB_ARG_TYPE_SIZE: lua_pushnumber(L, sb_opt_to_size(opt)); break; case SB_ARG_TYPE_STRING: tmp = sb_opt_to_string(opt); lua_pushstring(L, tmp ? tmp : ""); break; case SB_ARG_TYPE_LIST: lua_newtable(L); sb_list_item_t *val; int count = 1; SB_LIST_FOR_EACH(val, sb_opt_to_list(opt)) { lua_pushstring(L, SB_LIST_ENTRY(val, value_t, listitem)->data); lua_rawseti(L, -2, count++); } break; case SB_ARG_TYPE_FILE: /* no need to export anything */ lua_pushnil(L); break; default: log_text(LOG_WARNING, "Global option '%s' will not be exported, because" " the type is unknown", opt->name); lua_pushnil(L); break; } /* set var = value */ if (global) lua_setglobal(L, opt->name); else lua_settable(L, -3); } if (!global) lua_settable(L, -3); /* set sysbench.opt */ return 0; } /* Export option values to the 'sysbench.opt' table. */ static int export_options(lua_State *L) { if (do_export_options(L, false)) return 1; return 0; } /* Load a specified Lua script */ sb_test_t *sb_load_lua(const char *testname) { if (testname != NULL) { char *tmp = strdup(testname); sbtest.sname = strdup(basename(tmp)); sbtest.lname = tmp; } else { sbtest.sname = strdup(""); sbtest.lname = NULL; } /* Initialize global interpreter state */ gstate = sb_lua_new_state(); if (gstate == NULL) goto error; if (read_cmdline_options(gstate)) goto error; /* Test commands */ if (func_available(gstate, PREPARE_FUNC)) sbtest.builtin_cmds.prepare = &sb_lua_cmd_prepare; if (func_available(gstate, CLEANUP_FUNC)) sbtest.builtin_cmds.cleanup = &sb_lua_cmd_cleanup; if (func_available(gstate, HELP_FUNC)) sbtest.builtin_cmds.help = &sb_lua_cmd_help; /* Test operations */ sbtest.ops = lua_ops; if (func_available(gstate, THREAD_RUN_FUNC)) sbtest.ops.thread_run = &sb_lua_op_thread_run; if (sb_lua_hook_defined(gstate, REPORT_INTERMEDIATE_HOOK)) sbtest.ops.report_intermediate = sb_lua_report_intermediate; if (sb_lua_hook_defined(gstate, REPORT_CUMULATIVE_HOOK)) sbtest.ops.report_cumulative = sb_lua_report_cumulative; /* Allocate per-thread interpreters array */ states = (lua_State **)calloc(sb_globals.threads, sizeof(lua_State *)); if (states == NULL) goto error; return &sbtest; error: sb_lua_done(); return NULL; } void sb_lua_done(void) { sb_lua_close_state(gstate); gstate = NULL; xfree(states); if (sbtest.args != NULL) { for (size_t i = 0; sbtest.args[i].name != NULL; i++) { xfree(sbtest.args[i].name); xfree(sbtest.args[i].desc); xfree(sbtest.args[i].value); } xfree(sbtest.args); } xfree(sbtest.sname); xfree(sbtest.lname); } /* Initialize Lua script */ int sb_lua_op_init(void) { if (export_options(gstate)) return 1; lua_getglobal(gstate, INIT_FUNC); if (!lua_isnil(gstate, -1)) { if (lua_pcall(gstate, 0, 0, 0)) { call_error(gstate, INIT_FUNC); return 1; } } if (!func_available(gstate, EVENT_FUNC)) { log_text(LOG_FATAL, "cannot find the event() function in %s", sbtest.sname); return 1; } return 0; } int sb_lua_op_thread_init(int thread_id) { lua_State * L; L = sb_lua_new_state(); if (L == NULL) return 1; states[thread_id] = L; if (export_options(L)) return 1; lua_getglobal(L, THREAD_INIT_FUNC); if (!lua_isnil(L, -1)) { lua_pushnumber(L, thread_id); if (lua_pcall(L, 1, 1, 0)) { call_error(L, THREAD_INIT_FUNC); return 1; } } return 0; } int sb_lua_op_thread_run(int thread_id) { lua_State * const L = states[thread_id]; lua_getglobal(L, THREAD_RUN_FUNC); lua_pushnumber(L, thread_id); if (lua_pcall(L, 1, 1, 0)) { call_error(L, THREAD_RUN_FUNC); return 1; } return 0; } int sb_lua_op_thread_done(int thread_id) { lua_State * const L = states[thread_id]; int rc = 0; lua_getglobal(L, THREAD_DONE_FUNC); if (!lua_isnil(L, -1)) { lua_pushnumber(L, thread_id); if (lua_pcall(L, 1, 1, 0)) { call_error(L, THREAD_DONE_FUNC); rc = 1; } } sb_lua_close_state(L); return rc; } int sb_lua_op_done(void) { lua_getglobal(gstate, DONE_FUNC); if (!lua_isnil(gstate, -1)) { if (lua_pcall(gstate, 0, 0, 0)) { call_error(gstate, DONE_FUNC); return 1; } } sb_lua_done(); return 0; } /* Pre-load internal scripts */ static int load_internal_scripts(lua_State *L) { for (internal_script_t *s = internal_scripts; s->name != NULL; s++) { if (luaL_loadbuffer(L, (const char *) s->source, s->source_len[0], s->name)) { log_text(LOG_FATAL, "failed to load internal module '%s': %s", s->name, lua_tostring(L, -1)); lua_pop(L, 1); return 1; } lua_call(L, 0, 0); } return 0; } static void sb_lua_var_number(lua_State *L, const char *name, lua_Number n) { lua_pushstring(L, name); lua_pushnumber(L, n); lua_settable(L, -3); } static void sb_lua_var_string(lua_State *L, const char *name, const char *s) { lua_pushstring(L, name); lua_pushstring(L, s); lua_settable(L, -3); } /* Set package.path and package.cpath in a given environment. Also honor LUA_PATH/LUA_CPATH to mimic the default Lua behavior. */ static void sb_lua_set_paths(lua_State *L) { lua_getglobal(L, "package"); int top = lua_gettop(L); lua_pushliteral(L, "./?.lua;"); lua_pushliteral(L, "./?/init.lua;"); lua_pushliteral(L, "./src/lua/?.lua;"); const char *home = getenv("HOME"); if (home != NULL) { lua_pushstring(L, home); lua_pushliteral(L, "/.luarocks/share/lua/5.1/?.lua;"); lua_pushstring(L, home); lua_pushliteral(L, "/.luarocks/share/lua/5.1/?/init.lua;"); lua_pushstring(L, home); lua_pushliteral(L, "/.luarocks/share/lua/?.lua;"); lua_pushstring(L, home); lua_pushliteral(L, "/.luarocks/share/lua/?/init.lua;"); } lua_pushliteral(L, "/usr/local/share/lua/5.1/?.lua;"); lua_pushliteral(L, "/usr/share/lua/5.1/?.lua;"); lua_pushliteral(L, DATADIR "/?.lua;"); lua_concat(L, lua_gettop(L) - top); /* Mimic the default Lua behavior with respect to LUA_PATH and ';;' */ const char *path = getenv("LUA_PATH"); if (path != NULL) { const char *def = lua_tostring(L, -1); path = luaL_gsub(L, path, ";;", ";\1;"); luaL_gsub(L, path, "\1", def); lua_remove(L, -2); lua_remove(L, -2); } lua_setfield(L, top, "path"); lua_pushliteral(L, "./?" DLEXT ";"); if (home != NULL) { lua_pushstring(L, home); lua_pushliteral(L, "/.luarocks/lib/lua/5.1/?" DLEXT ";"); lua_pushstring(L, home); lua_pushliteral(L, "/.luarocks/lib/lua/?" DLEXT ";"); } lua_pushliteral(L, "/usr/local/lib/lua/5.1/?" DLEXT ";"); lua_pushliteral(L, "/usr/lib/lua/5.1/?" DLEXT ";"); lua_pushliteral(L, LIBDIR ";"); lua_concat(L, lua_gettop(L) - top); /* Mimic the default Lua behavior with respect to LUA_CPATH and ';;' */ path = getenv("LUA_CPATH"); if (path != NULL) { const char *def = lua_tostring(L, -1); path = luaL_gsub(L, path, ";;", ";\1;"); luaL_gsub(L, path, "\1", def); lua_remove(L, -2); lua_remove(L, -2); } lua_setfield(L, top, "cpath"); lua_pop(L, 1); /* package */ } /* Create a deep copy of the 'args' array and store it in sbtest.args */ int sb_lua_set_test_args(sb_arg_t *args, size_t len) { sbtest.args = malloc((len + 1) * sizeof(sb_arg_t)); for (size_t i = 0; i < len; i++) { sbtest.args[i].name = strdup(args[i].name); sbtest.args[i].desc = strdup(args[i].desc); sbtest.args[i].type = args[i].type; sbtest.args[i].value = args[i].value != NULL ? strdup(args[i].value) : NULL; sbtest.args[i].validate = args[i].validate; } sbtest.args[len] = (sb_arg_t) {.name = NULL}; return 0; } /* Parse command line options definitions, if present in the script as a sysbench.cmdline.options table. If there was a parsing error, return 1. Return 0 on success. */ static int read_cmdline_options(lua_State *L) { lua_getglobal(L, "sysbench"); lua_getfield(L, -1, "cmdline"); lua_getfield(L, -1, "read_cmdline_options"); if (!lua_isfunction(L, -1)) { log_text(LOG_WARNING, "Cannot find sysbench.cmdline.read_cmdline_options()"); lua_pop(L, 3); return 1; } if (lua_pcall(L, 0, 1, 0) != 0) { call_error(L, "sysbench.cmdline.read_cmdline_options"); lua_pop(L, 2); return 1; } int rc = lua_toboolean(L, -1) == 0; lua_pop(L, 3); return rc; } /* Allocate and initialize new interpreter state */ static lua_State *sb_lua_new_state(void) { lua_State *L; L = luaL_newstate(); luaL_openlibs(L); if (sb_globals.luajit_cmd && sb_lua_do_jitcmd(L, sb_globals.luajit_cmd)) return NULL; sb_lua_set_paths(L); /* Export variables into per-state 'sysbench' table */ lua_newtable(L); /* sysbench.tid */ sb_lua_var_number(L, "tid", sb_tls_thread_id); lua_pushliteral(L, "error"); lua_newtable(L); sb_lua_var_number(L, "NONE", SB_LUA_ERROR_NONE); sb_lua_var_number(L, "RESTART_EVENT", SB_LUA_ERROR_RESTART_EVENT); lua_settable(L, -3); /* sysbench.error */ /* sysbench.version */ sb_lua_var_string(L, "version", PACKAGE_VERSION); /* sysbench.version_string */ sb_lua_var_string(L, "version_string", PACKAGE_NAME " " PACKAGE_VERSION SB_GIT_SHA); lua_pushliteral(L, "cmdline"); lua_newtable(L); lua_pushliteral(L, "argv"); lua_createtable(L, sb_globals.argc, 0); for (int i = 0; i < sb_globals.argc; i++) { lua_pushstring(L, sb_globals.argv[i]); lua_rawseti(L, -2, i); } lua_settable(L, -3); /* sysbench.cmdline.argv */ /* Export command name as sysbench.cmdline.command */ if (sb_globals.cmdname) { lua_pushliteral(L, "command"); lua_pushstring(L, sb_globals.cmdname); lua_settable(L, -3); } /* Export script path as sysbench.cmdline.script_path */ sb_lua_var_string(L, "script_path", sbtest.lname); lua_settable(L, -3); /* sysbench.cmdline */ lua_setglobal(L, "sysbench"); luaL_newmetatable(L, "sysbench.stmt"); luaL_newmetatable(L, "sysbench.rs"); if (load_internal_scripts(L)) return NULL; int rc; if ((rc = luaL_loadfile(L, sbtest.lname)) != 0) { if (rc != LUA_ERRFILE) goto loaderr; /* Try to handle the given string as a module name */ lua_getglobal(L, "require"); lua_pushstring(L, sbtest.lname); if (lua_pcall(L, 1, 1, 0)) { const char *msg = lua_tostring(L, -1); if (msg && strncmp(msg, "module ", 7)) goto loaderr; log_text(LOG_FATAL, "Cannot find benchmark '%s': no such built-in test, " "file or module", sbtest.lname); return NULL; } } else if (lua_pcall(L, 0, 0, 0)) goto loaderr; /* Create new L context */ tls_lua_ctxt.L = L; return L; loaderr: report_error(L); return NULL; } /* Close interpreter state */ int sb_lua_close_state(lua_State *state) { sb_lua_ctxt_t * const ctxt = &tls_lua_ctxt; if (state != NULL) lua_close(state); if (ctxt != NULL) ctxt->L = NULL; return 0; } /* Execute a given command */ static int execute_command(const char *cmd) { if (export_options(gstate)) return 1; lua_getglobal(gstate, cmd); if (lua_pcall(gstate, 0, 1, 0) != 0) { call_error(gstate, cmd); return 1; } lua_pop(gstate, 1); return 0; } /* Prepare command */ int sb_lua_cmd_prepare(void) { return execute_command(PREPARE_FUNC); } /* Cleanup command */ int sb_lua_cmd_cleanup(void) { return execute_command(CLEANUP_FUNC); } /* Help command */ int sb_lua_cmd_help(void) { return execute_command(HELP_FUNC); } /* Check if a specified hook exists */ static bool sb_lua_hook_defined(lua_State *L, const char *name) { if (L == NULL) return false; lua_getglobal(L, "sysbench"); lua_getfield(L, -1, "hooks"); lua_getfield(L, -1, name); bool rc = lua_isfunction(L, -1); lua_pop(L, 3); return rc; } /* Push a specified hook on stack */ static bool sb_lua_hook_push(lua_State *L, const char *name) { if (L == NULL) return false; lua_getglobal(L, "sysbench"); lua_getfield(L, -1, "hooks"); lua_getfield(L, -1, name); if (!lua_isfunction(L, -1)) { lua_pop(L, 3); return false; } lua_remove(L, -2); /* hooks */ lua_remove(L, -2); /* sysbench */ return true; } bool sb_lua_loaded(void) { return gstate != NULL; } /* Check if a specified custom command exists */ bool sb_lua_custom_command_defined(const char *name) { lua_State * const L = gstate; lua_getglobal(L, "sysbench"); lua_getfield(L, -1, "cmdline"); lua_getfield(L, -1, "command_defined"); if (!lua_isfunction(L, -1)) { log_text(LOG_WARNING, "Cannot find the sysbench.cmdline.command_defined function"); lua_pop(L, 3); return 1; } lua_pushstring(L, name); if (lua_pcall(L, 1, 1, 0) != 0) { call_error(L, "sysbench.cmdline.command_defined"); lua_pop(L, 2); return 1; } bool rc = lua_toboolean(L, -1); lua_pop(L, 3); return rc; } /* Check if a specified custom command supports parallel execution */ static bool sb_lua_custom_command_parallel(const char *name) { lua_State * const L = gstate; lua_getglobal(L, "sysbench"); lua_getfield(L, -1, "cmdline"); lua_getfield(L, -1, "command_parallel"); if (!lua_isfunction(L, -1)) { log_text(LOG_WARNING, "Cannot find the sysbench.cmdline.command_parallel function"); lua_pop(L, 3); return 1; } lua_pushstring(L, name); if (lua_pcall(L, 1, 1, 0) != 0) { call_error(L, "sysbench.cmdline.command_parallel"); lua_pop(L, 2); return 1; } bool rc = lua_toboolean(L, -1); lua_pop(L, 3); return rc; } static int call_custom_command(lua_State *L) { if (export_options(L)) return 1; lua_getglobal(L, "sysbench"); lua_getfield(L, -1, "cmdline"); lua_getfield(L, -1, "call_command"); if (!lua_isfunction(L, -1)) { log_text(LOG_WARNING, "Cannot find the sysbench.cmdline.call_command function"); lua_pop(L, 3); return 1; } lua_pushstring(L, sb_lua_custom_command); if (lua_pcall(L, 1, 1, 0) != 0) { call_error(L, "sysbench.cmdline.call_command"); lua_pop(L, 2); return 1; } bool rc = lua_toboolean(L, -1); lua_pop(L, 3); return rc ? EXIT_SUCCESS : EXIT_FAILURE; } static void *cmd_worker_thread(void *arg) { sb_thread_ctxt_t *ctxt= (sb_thread_ctxt_t *)arg; sb_tls_thread_id = ctxt->id; /* Initialize thread-local RNG state */ sb_rand_thread_init(); lua_State * const L = sb_lua_new_state(); if (L == NULL) { log_text(LOG_FATAL, "failed to create a thread to execute command"); return NULL; } call_custom_command(L); sb_lua_close_state(L); return NULL; } /* Call a specified custom command */ int sb_lua_call_custom_command(const char *name) { sb_lua_custom_command = name; if (sb_lua_custom_command_parallel(name) && sb_globals.threads > 1) { int err; if ((err = sb_thread_create_workers(cmd_worker_thread))) return err; return sb_thread_join_workers(); } return call_custom_command(gstate); } #define stat_to_number(name) sb_lua_var_number(L, #name, stat->name) static void stat_to_lua_table(lua_State *L, sb_stat_t *stat) { lua_newtable(L); stat_to_number(threads_running); stat_to_number(time_interval); stat_to_number(time_total); stat_to_number(latency_pct); stat_to_number(events); stat_to_number(reads); stat_to_number(writes); stat_to_number(other); stat_to_number(errors); stat_to_number(reconnects); } /* Call sysbench.hooks.report_intermediate */ static void sb_lua_report_intermediate(sb_stat_t *stat) { lua_State * const L = tls_lua_ctxt.L; if (!sb_lua_hook_push(L, REPORT_INTERMEDIATE_HOOK)) return; stat_to_lua_table(L, stat); /* The following is only available for intermediate reports with tx_rate > 0 */ stat_to_number(queue_length); stat_to_number(concurrency); if (lua_pcall(L, 1, 0, 0)) { call_error(L, REPORT_INTERMEDIATE_HOOK); } } /* Call sysbench.hooks.report_cumulative */ static void sb_lua_report_cumulative(sb_stat_t *stat) { lua_State * const L = tls_lua_ctxt.L; /* This may be called either from a separate checkpoint thread (in which case options are exported by sb_lua_report_thread_init(), or from the master thread on benchmark exit. In the latter case, options must be exported, as we don't normally do that for the global Lua state. */ if (L == gstate) export_options(L); if (!sb_lua_hook_push(L, REPORT_CUMULATIVE_HOOK)) return; stat_to_lua_table(L, stat); /* The following stats are only available for cumulative reports */ stat_to_number(latency_min); stat_to_number(latency_max); stat_to_number(latency_avg); stat_to_number(latency_sum); if (lua_pcall(L, 1, 0, 0)) { call_error(L, REPORT_CUMULATIVE_HOOK); } } #undef stat_to_number int sb_lua_report_thread_init(void) { if (tls_lua_ctxt.L == NULL) { sb_lua_new_state(); export_options(tls_lua_ctxt.L); } return 0; } void sb_lua_report_thread_done(void *arg) { (void) arg; /* unused */ if (sb_lua_loaded()) sb_lua_close_state(tls_lua_ctxt.L); } /* Perform a LuaJIT engine control command. This is taken with modifications from luajit.c */ int sb_lua_do_jitcmd(lua_State *L, const char *cmd) { const char *opt = strchr(cmd, '='); lua_pushlstring(L, cmd, opt ? (size_t) (opt - cmd) : strlen(cmd)); lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, -1, "jit"); /* Get jit.* module table. */ lua_remove(L, -2); lua_pushvalue(L, -2); lua_gettable(L, -2); /* Lookup library function. */ if (!lua_isfunction(L, -1)) { lua_pop(L, 2); /* Drop non-function and jit.* table, keep module name. */ /* Load add-on module. */ lua_getglobal(L, "require"); lua_pushliteral(L, "jit."); lua_pushvalue(L, -3); lua_concat(L, 2); if (lua_pcall(L, 1, 1, 0)) { const char *msg = lua_tostring(L, -1); if (msg && !strncmp(msg, "module ", 7)) goto nomodule; call_error(L, "require"); return 1; } lua_getfield(L, -1, "start"); if (lua_isnil(L, -1)) { nomodule: log_text(LOG_FATAL, "unknown luaJIT command or jit.* modules not installed"); return 1; } lua_remove(L, -2); /* Drop module table. */ } else { lua_remove(L, -2); /* Drop jit.* table. */ } lua_remove(L, -2); /* Drop module name. */ int narg = 0; if (opt && *++opt) { for (;;) { /* Split arguments. */ const char *p = strchr(opt, ','); narg++; if (!p) break; if (p == opt) lua_pushnil(L); else lua_pushlstring(L, opt, (size_t) (p - opt)); opt = p + 1; } if (*opt) lua_pushstring(L, opt); else lua_pushnil(L); } if (lua_pcall(L, narg, 0, 0)) { call_error(L, "lua_pcall"); return 1; } return 0; } ================================================ FILE: src/sb_lua.h ================================================ /* Copyright (C) 2006 MySQL AB Copyright (C) 2006-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "sysbench.h" #include "lua.h" /* Load a specified Lua script */ sb_test_t *sb_load_lua(const char *testname); void sb_lua_done(void); int sb_lua_hook_call(lua_State *L, const char *name); bool sb_lua_custom_command_defined(const char *name); int sb_lua_call_custom_command(const char *name); int sb_lua_report_thread_init(void); void sb_lua_report_thread_done(void *); bool sb_lua_loaded(void); ================================================ FILE: src/sb_options.c ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef STDC_HEADERS # include # include # include # include #endif #ifdef HAVE_LIMITS_H # include #endif #include "sb_options.h" #include "sysbench.h" #define VALUE_DELIMITER '=' #define VALUE_SEPARATOR ',' #define COMMENT_CHAR '#' #define MAXSTRLEN 256 /* Global options list */ static sb_list_t options; /* List of size modifiers (kilo, mega, giga, tera) */ static const char sizemods[] = "KMGT"; /* Convert dashes to underscores in option names */ static void convert_dashes(char *); /* Compare option names */ static int opt_name_cmp(const char *, const char *); /* Array of option formats as displayed by sb_print_options(). The order and number of elements must match sb_arg_type_t! */ static char *opt_formats[] = { NULL, /* SB_ARG_TYPE_NULL */ "[=on|off]", /* SB_ARG_TYPE_FLAG */ "=N", /* SB_ARG_TYPE_INT */ "=SIZE", /* SB_ARG_TYPE_SIZE */ "=N", /* SB_ARG_TYPE_DOUBLE */ "=STRING", /* SB_ARG_TYPE_STRING */ "=[LIST,...]", /* SB_ARG_TYPE_LIST */ "=FILENAME" /* SB_ARG_TYPE_FILE */ }; /* Initialize options library */ int sb_options_init(void) { SB_LIST_INIT(&options); return 0; } /* Release resource allocated by the options library */ int sb_options_done(void) { free_options(&options); return 0; } /* Register set of command line arguments */ int sb_register_arg_set(sb_arg_t *set) { unsigned int i; for (i=0; set[i].name != NULL; i++) { option_t * const opt = set_option(set[i].name, set[i].value, set[i].type); if (opt == NULL) return 1; opt->validate = set->validate; } return 0; } option_t *sb_find_option(const char *name) { return find_option(&options, name); } static void read_config_file(const char *filename) { /* read config options from file */ FILE *fp = fopen(filename, "r"); if (!fp) { perror(filename); } else { read_config(fp, &options); fclose(fp); } } option_t *set_option(const char *name, const char *value, sb_arg_type_t type) { option_t *opt; char *tmpbuf; char *tmp; opt = add_option(&options, name); if (opt == NULL) return NULL; free_values(&opt->values); opt->type = type; if (opt->validate != NULL && !opt->validate(name, value)) return NULL; if (type != SB_ARG_TYPE_BOOL && (value == NULL || value[0] == '\0')) return opt; switch (type) { case SB_ARG_TYPE_BOOL: if (value == NULL || !strcmp(value, "on") || !strcmp(value, "true") || !strcmp(value, "1")) { add_value(&opt->values, "on"); } else if (strcmp(value, "off") && strcmp(value, "false") && strcmp(value, "0")) { return NULL; } break; case SB_ARG_TYPE_INT: case SB_ARG_TYPE_SIZE: case SB_ARG_TYPE_DOUBLE: case SB_ARG_TYPE_STRING: add_value(&opt->values, value); break; case SB_ARG_TYPE_LIST: if (value == NULL) break; tmpbuf = strdup(value); tmp = tmpbuf; for (tmp = strtok(tmp, ","); tmp != NULL; tmp = strtok(NULL, ",")) add_value(&opt->values, tmp); free(tmpbuf); break; case SB_ARG_TYPE_FILE: read_config_file(value); break; default: printf("Unknown argument type: %d", type); return NULL; } return opt; } void sb_print_options(sb_arg_t *opts) { unsigned int i; unsigned int len; unsigned int maxlen; char *fmt; /* Count the maximum name length */ for (i = 0, maxlen = 0; opts[i].name != NULL; i++) { len = strlen(opts[i].name); len += (opts[i].type < SB_ARG_TYPE_MAX) ? strlen(opt_formats[opts[i].type]) : 8 /* =UNKNOWN */; if (len > maxlen) maxlen = len; } for (i = 0; opts[i].name != NULL; i++) { if (opts[i].type < SB_ARG_TYPE_MAX) fmt = opt_formats[opts[i].type]; else fmt = "=UNKNOWN"; printf(" --%s%-*s%s", opts[i].name, (int)(maxlen - strlen(opts[i].name) + 1), fmt, opts[i].desc); if (opts[i].value != NULL) printf(" [%s]", opts[i].value); printf("\n"); } printf("\n"); } int sb_opt_to_flag(option_t *opt) { return !SB_LIST_IS_EMPTY(&opt->values); } int sb_get_value_flag(const char *name) { option_t *opt; opt = find_option(&options, name); if (opt == NULL) return 0; return sb_opt_to_flag(opt); } int sb_opt_to_int(option_t *opt) { value_t *val; sb_list_item_t *pos; long res; char *endptr; SB_LIST_ONCE(pos, &opt->values) { val = SB_LIST_ENTRY(pos, value_t, listitem); res = strtol(val->data, &endptr, 10); if (*endptr != '\0' || res > INT_MAX || res < INT_MIN) { fprintf(stderr, "Invalid value for the '%s' option: '%s'\n", opt->name, val->data); exit(EXIT_FAILURE); } return (int) res; } return 0; } int sb_get_value_int(const char *name) { option_t *opt; opt = find_option(&options, name); if (opt == NULL) return 0; return sb_opt_to_int(opt);; } unsigned long long sb_opt_to_size(option_t *opt) { value_t *val; sb_list_item_t *pos; unsigned long long res = 0; char mult = 0; int rc; unsigned int i, n; char *c; SB_LIST_ONCE(pos, &opt->values) { val = SB_LIST_ENTRY(pos, value_t, listitem); /* * Reimplentation of sscanf(val->data, "%llu%c", &res, &mult), since * there is no standard on how to specify long long values */ res = 0; for (rc = 0, c = val->data; *c != '\0'; c++) { if (*c < '0' || *c > '9') { if (rc == 1) { rc = 2; mult = *c; } break; } rc = 1; res = res * 10 + *c - '0'; } if (rc == 2) { for (n = 0; sizemods[n] != '\0'; n++) if (toupper(mult) == sizemods[n]) break; if (sizemods[n] != '\0') { for (i = 0; i <= n; i++) res *= 1024; } else res = 0; /* Unknown size modifier */ } } return res; } unsigned long long sb_get_value_size(const char *name) { option_t *opt; opt = find_option(&options, name); if (opt == NULL) return 0; return sb_opt_to_size(opt); } double sb_opt_to_double(option_t *opt) { value_t *val; sb_list_item_t *pos; double res = 0; SB_LIST_FOR_EACH(pos, &opt->values) { val = SB_LIST_ENTRY(pos, value_t, listitem); res = strtod(val->data, NULL); } return res; } double sb_get_value_double(const char *name) { option_t *opt; opt = find_option(&options, name); if (opt == NULL) return 0; return sb_opt_to_double(opt); } char *sb_opt_to_string(option_t *opt) { value_t *val; sb_list_item_t *pos; SB_LIST_ONCE(pos, &opt->values) { val = SB_LIST_ENTRY(pos, value_t, listitem); return val->data; } return NULL; } char *sb_get_value_string(const char *name) { option_t *opt; opt = find_option(&options, name); if (opt == NULL) return NULL; return sb_opt_to_string(opt); } bool sb_opt_copy(const char *to, const char *from) { option_t *opt = find_option(&options, from); if (opt == NULL) return false; set_option(to, sb_opt_to_string(opt), opt->type); return true; } sb_list_t *sb_opt_to_list(option_t *opt) { return &opt->values; } sb_list_t *sb_get_value_list(const char *name) { option_t *opt; opt = find_option(&options, name); if (opt == NULL) return NULL; return sb_opt_to_list(opt); } char *sb_print_value_size(char *buf, unsigned int buflen, double value) { unsigned int i; for (i = 0; i < sizeof(sizemods) && value >= 1024; i++, value /= 1024) /* empty */ ; if (i > 0) snprintf(buf, buflen, "%.5g%ci", value, sizemods[i-1]); else snprintf(buf, buflen, "%.5g", value); return buf; } value_t *new_value() { value_t *newval; newval = (value_t *)malloc(sizeof(value_t)); if (newval != NULL) memset(newval, 0, sizeof(value_t)); return newval; } option_t *new_option() { option_t *newopt; newopt = (option_t *)malloc(sizeof(option_t)); if (newopt != NULL) { memset(newopt, 0, sizeof(option_t)); SB_LIST_INIT(&newopt->values); } return newopt; } void free_values(sb_list_t *values) { sb_list_item_t *next; sb_list_item_t *cur; value_t *val; if (values == NULL) return; SB_LIST_FOR_EACH_SAFE(cur, next, values) { val = SB_LIST_ENTRY(cur, value_t, listitem); if (val->data != NULL) free(val->data); SB_LIST_DELETE(cur); free(val); } } void free_options(sb_list_t *options) { sb_list_item_t *next; sb_list_item_t *cur; option_t *opt; if (options == NULL) return; SB_LIST_FOR_EACH_SAFE(cur, next, options) { opt = SB_LIST_ENTRY(cur, option_t, listitem); if (opt->name != NULL) free(opt->name); free_values(&opt->values); free(opt); } } int remove_value(sb_list_t *values, char *valname) { value_t * value; if (values == NULL || valname == NULL) return 1; if ((value = find_value(values, valname)) == NULL) return 1; if (value->data != NULL) { free(value->data); } SB_LIST_DELETE(&value->listitem); free(value); return 0; } int remove_option(sb_list_t * options, char * optname) { option_t * option; if (options == NULL || optname == NULL) return 1; if ((option = find_option(options, optname)) == NULL) return 1; free_values(&option->values); if (option->name != NULL) free(option->name); SB_LIST_DELETE(&option->listitem); free(option); return 0; } value_t *add_value(sb_list_t *values, const char *data) { value_t *newval; if (values == NULL || data == NULL) return NULL; if ((newval = new_value()) == NULL) return NULL; if ((newval->data = strdup(data)) == NULL) { free(newval); return NULL; } SB_LIST_ADD_TAIL(&newval->listitem, values); return newval; } value_t *find_value(sb_list_t *values, const char *data) { sb_list_item_t *pos; value_t *value; if (values == NULL || data == NULL) return NULL; SB_LIST_FOR_EACH(pos, values) { value = SB_LIST_ENTRY(pos, value_t, listitem); if (!strcmp(value->data, data)) return value; } return NULL; } option_t *add_option(sb_list_t *options, const char *name) { option_t *option; if (options == NULL || name == NULL) return NULL; if ((option = find_option(options, name)) != NULL) return option; if ((option = new_option()) == NULL) return NULL; option->name = strdup(name); convert_dashes(option->name); SB_LIST_ADD_TAIL(&option->listitem, options); return option; } void convert_dashes(char *s) { while (*s != '\0') { if (*s == '-') *s = '_'; s++; } } int opt_name_cmp(const char *s1, const char *s2) { for (/* empty */; *s1 != '\0'; s1++, s2++) { if (*s1 == *s2) continue; if ((*s1 != '-' && *s1 != '_') || (*s2 != '-' && *s2 != '_')) break; } return *s1 - *s2; } option_t *find_option(sb_list_t *options, const char *name) { sb_list_item_t *pos; option_t *opt; if (options == NULL || name == NULL) return NULL; SB_LIST_FOR_EACH(pos, options) { opt = SB_LIST_ENTRY(pos, option_t, listitem); if (!opt_name_cmp(opt->name, name)) return opt; } return NULL; } sb_list_item_t *sb_options_enum_start(void) { return SB_LIST_ENUM_START(&options); } sb_list_item_t *sb_options_enum_next(sb_list_item_t *pos, option_t **opt) { pos = SB_LIST_ENUM_NEXT(pos, &options); if (pos == NULL) return NULL; *opt = SB_LIST_ENTRY(pos, option_t, listitem); return pos; } sb_list_t *read_config(FILE *fp, sb_list_t *options) { char buf[MAXSTRLEN]; char *tmp; char qc; option_t *newopt; int optlen; int nline; if (fp == NULL || options == NULL) return NULL; nline = 0; while (fgets(buf, MAXSTRLEN, fp) != NULL) { nline++; tmp = strchr(buf, VALUE_DELIMITER); if (tmp == NULL) continue; if (*tmp != '\0') *tmp++ = '\0'; if ((newopt = add_option(options, buf)) == NULL) return NULL; free_values(&newopt->values); while (*tmp != '\0') { if (isspace((int)*tmp)) { tmp++; continue; } if (*tmp == COMMENT_CHAR) break; else if (*tmp == '\'' || *tmp == '\"') { qc = *tmp; for (tmp++, optlen = 0; tmp[optlen] != '\0' && tmp[optlen] != qc; optlen++) { /* Empty */ } if (tmp[optlen] == '\0') { fprintf(stderr, "unexpected EOL on line %d\n", nline); return NULL; } tmp[optlen++] = '\0'; add_value(&newopt->values, tmp); for (tmp = tmp + optlen; *tmp != '\0' && *tmp != VALUE_SEPARATOR; tmp++) { /* Empty */ } if (*tmp == VALUE_SEPARATOR) tmp++; } else { for (optlen = 0; tmp[optlen] != '\0' && tmp[optlen] != VALUE_SEPARATOR && !isspace(tmp[optlen]); optlen++) { /* Empty */ } if (tmp[optlen] != '\0') tmp[optlen++] = '\0'; add_value(&newopt->values, tmp); tmp += optlen; } } } return options; } int write_config(FILE *fp, sb_list_t *options) { option_t *opt; value_t *val; sb_list_item_t *pos_opt; sb_list_item_t *pos_val; if (fp == NULL || options == NULL) return 1; SB_LIST_FOR_EACH(pos_opt, options) { opt = SB_LIST_ENTRY(pos_opt, option_t, listitem); if (opt->ignore || opt->name == NULL) continue; opt->ignore = 1; fprintf(fp, "%s %c ", opt->name, VALUE_DELIMITER); SB_LIST_FOR_EACH(pos_val, &opt->values) { val = SB_LIST_ENTRY(pos_val, value_t, listitem); if (!val->ignore && val->data != NULL) fprintf(fp, "%s", val->data); if (!SB_LIST_ITEM_LAST(pos_val, &opt->values)) fprintf(fp, "%c ", VALUE_SEPARATOR); } fputc('\n', fp); } return 0; } ================================================ FILE: src/sb_options.h ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2017 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef OPTIONS_H #define OPTIONS_H #include #include #include "sb_list.h" /* Helper option declaration macros */ #define SB_OPT(n, d, v, t) \ { .name = (n), \ .desc = (d), \ .type = SB_ARG_TYPE_##t, \ .value = (v) } #define SB_OPT_END { .type = SB_ARG_TYPE_NULL } /* Option types definition */ typedef enum { SB_ARG_TYPE_NULL, SB_ARG_TYPE_BOOL, SB_ARG_TYPE_INT, SB_ARG_TYPE_SIZE, SB_ARG_TYPE_DOUBLE, SB_ARG_TYPE_STRING, SB_ARG_TYPE_LIST, SB_ARG_TYPE_FILE, SB_ARG_TYPE_MAX } sb_arg_type_t; /* Option validation function */ typedef bool sb_opt_validate_t(const char *, const char *); /* Test option definition */ typedef struct { const char *name; const char *desc; const char *value; sb_arg_type_t type; sb_opt_validate_t *validate; } sb_arg_t; typedef struct { char *data; char ignore; sb_list_item_t listitem; } value_t; typedef struct { char *name; sb_arg_type_t type; sb_list_t values; char ignore; sb_opt_validate_t *validate; sb_list_item_t listitem; } option_t; /* Initilize options library */ int sb_options_init(void); /* Release resource allocated by the options library */ int sb_options_done(void); /* Register set of command line arguments */ int sb_register_arg_set(sb_arg_t *set); /* Set value 'value' of type 'type' for option 'name' */ option_t *set_option(const char *name, const char *value, sb_arg_type_t type); /* Find option specified by 'name' */ option_t *sb_find_option(const char *name); /* Print list of options specified by 'opts' */ void sb_print_options(sb_arg_t *opts); int sb_get_value_flag(const char *name); int sb_get_value_int(const char *name); unsigned long long sb_get_value_size(const char *name); double sb_get_value_double(const char *name); char *sb_get_value_string(const char *name); sb_list_t *sb_get_value_list(const char *name); char *sb_print_value_size(char *buf, unsigned int buflen, double value); int sb_opt_to_flag(option_t *); int sb_opt_to_int(option_t *); unsigned long long sb_opt_to_size(option_t *); double sb_opt_to_double(option_t *); char *sb_opt_to_string(option_t *); sb_list_t *sb_opt_to_list(option_t *); bool sb_opt_copy(const char *to, const char *from); sb_list_item_t *sb_options_enum_start(void); sb_list_item_t *sb_options_enum_next(sb_list_item_t *, option_t **); value_t *new_value(void); option_t *new_option(void); void free_values(sb_list_t *); void free_options(sb_list_t *); value_t *add_value(sb_list_t *, const char *); value_t *find_value(sb_list_t *, const char *); option_t *add_option(sb_list_t *, const char *); option_t *find_option(sb_list_t *, const char *); int remove_value(sb_list_t *, char *); int remove_option(sb_list_t *, char *); sb_list_t *read_config(FILE *, sb_list_t *); int write_config(FILE *, sb_list_t *); #endif /* OPTIONS_H */ ================================================ FILE: src/sb_rand.c ================================================ /* Copyright (C) 2016-2017 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * This file incorporates work covered by the following copyright and * permission notice: * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_MATH_H # include #endif #include "sb_options.h" #include "sb_rand.h" #include "sb_logger.h" #include "sb_ck_pr.h" TLS sb_rng_state_t sb_rng_state CK_CC_CACHELINE; /* Exported variables */ int sb_rand_seed; /* optional seed set on the command line */ /* Random numbers command line options */ static sb_arg_t rand_args[] = { SB_OPT("rand-type", "random numbers distribution {uniform, gaussian, pareto, zipfian} " "to use by default", "uniform", STRING), SB_OPT("rand-seed", "seed for random number generator. When 0, the current time is " "used as an RNG seed.", "0", INT), SB_OPT("rand-pareto-h", "shape parameter for the Pareto distribution", "0.2", DOUBLE), SB_OPT("rand-zipfian-exp", "shape parameter (exponent, theta) for the Zipfian distribution", "0.8", DOUBLE), SB_OPT_END }; static rand_dist_t rand_type; /* pointer to the default PRNG as defined by --rand-type */ static uint32_t (*rand_func)(uint32_t, uint32_t); static unsigned int rand_iter; static unsigned int rand_pct; static unsigned int rand_res; /* Pre-computed FP constants to avoid unnecessary conversions and divisions at runtime. */ static double rand_iter_mult; static double rand_pct_mult; static double rand_pct_2_mult; static double rand_res_mult; /* parameters for Pareto distribution */ static double pareto_h; /* parameter h */ static double pareto_power; /* parameter pre-calculated by h */ /* parameter and precomputed values for the Zipfian distribution */ static double zipf_exp; static double zipf_s; static double zipf_hIntegralX1; /* Unique sequence generator state */ static uint32_t rand_unique_index CK_CC_CACHELINE; static uint32_t rand_unique_offset; extern inline uint64_t sb_rand_uniform_uint64(void); extern inline double sb_rand_uniform_double(void); extern inline uint64_t xoroshiro_rotl(const uint64_t, int); extern inline uint64_t xoroshiro_next(uint64_t s[2]); static void rand_unique_seed(uint32_t index, uint32_t offset); /* Helper functions for the Zipfian distribution */ static double hIntegral(double x, double e); static double hIntegralInverse(double x, double e); static double h(double x, double e); static double helper1(double x); static double helper2(double x); int sb_rand_register(void) { sb_register_arg_set(rand_args); return 0; } /* Initialize random numbers generation */ int sb_rand_init(void) { char *s; sb_rand_seed = sb_get_value_int("rand-seed"); s = sb_get_value_string("rand-type"); if (!strcmp(s, "uniform")) { rand_type = DIST_TYPE_UNIFORM; rand_func = &sb_rand_uniform; } else if (!strcmp(s, "gaussian")) { rand_type = DIST_TYPE_GAUSSIAN; rand_func = &sb_rand_gaussian; } else if (!strcmp(s, "pareto")) { rand_type = DIST_TYPE_PARETO; rand_func = &sb_rand_pareto; } else if (!strcmp(s, "zipfian")) { rand_type = DIST_TYPE_ZIPFIAN; rand_func = &sb_rand_zipfian; } else { log_text(LOG_FATAL, "Invalid random numbers distribution: %s.", s); return 1; } rand_iter = sb_get_value_int("rand-spec-iter"); rand_iter_mult = 1.0 / rand_iter; rand_pct = sb_get_value_int("rand-spec-pct"); rand_pct_mult = rand_pct / 100.0; rand_pct_2_mult = rand_pct / 200.0; rand_res = sb_get_value_int("rand-spec-res"); rand_res_mult = 100.0 / (100.0 - rand_res); pareto_h = sb_get_value_double("rand-pareto-h"); pareto_power = log(pareto_h) / log(1.0-pareto_h); zipf_exp = sb_get_value_double("rand-zipfian-exp"); if (zipf_exp < 0) { log_text(LOG_FATAL, "--rand-zipfian-exp must be >= 0"); return 1; } zipf_s = 2 - hIntegralInverse(hIntegral(2.5, zipf_exp) - h(2, zipf_exp), zipf_exp); zipf_hIntegralX1 = hIntegral(1.5, zipf_exp) - 1; /* Seed PRNG for the main thread. Worker threads do their own seeding */ sb_rand_thread_init(); /* Seed the unique sequence generator */ rand_unique_seed(random(), random()); return 0; } void sb_rand_print_help(void) { printf("Pseudo-Random Numbers Generator options:\n"); sb_print_options(rand_args); } void sb_rand_done(void) { } /* Initialize thread-local RNG state */ void sb_rand_thread_init(void) { /* We use libc PRNG to seed xoroshiro128+ */ sb_rng_state[0] = (((uint64_t) random()) << 32) | (((uint64_t) random()) & UINT32_MAX); sb_rng_state[1] = (((uint64_t) random()) << 32) | (((uint64_t) random()) & UINT32_MAX); } /* Return random number in the specified range with distribution specified with the --rand-type command line option */ uint32_t sb_rand_default(uint32_t a, uint32_t b) { return rand_func(a,b); } /* uniform distribution */ uint32_t sb_rand_uniform(uint32_t a, uint32_t b) { return a + sb_rand_uniform_double() * (b - a + 1); } /* gaussian distribution */ uint32_t sb_rand_gaussian(uint32_t a, uint32_t b) { double sum; double t; unsigned int i; t = b - a + 1; for(i=0, sum=0; i < rand_iter; i++) sum += sb_rand_uniform_double() * t; return a + (uint32_t) (sum * rand_iter_mult) ; } /* Pareto distribution */ uint32_t sb_rand_pareto(uint32_t a, uint32_t b) { return a + (uint32_t) ((b - a + 1) * pow(sb_rand_uniform_double(), pareto_power)); } /* Generate random string */ void sb_rand_str(const char *fmt, char *buf) { unsigned int i; for (i=0; fmt[i] != '\0'; i++) { if (fmt[i] == '#') buf[i] = sb_rand_uniform('0', '9'); else if (fmt[i] == '@') buf[i] = sb_rand_uniform('a', 'z'); else buf[i] = fmt[i]; } } /* Generates a random string of ASCII characters between '0' and 'z' of a length between min and max. buf should have enough room for max len bytes. Returns the number of characters written into the buffer. */ uint32_t sb_rand_varstr(char *buf, uint32_t min_len, uint32_t max_len) { unsigned int i; uint32_t num_chars; if (max_len == 0) { return 0; /* we can't be sure buf is long enough to populate, so be safe */ } if (min_len > max_len) { min_len = 1; } num_chars = sb_rand_uniform(min_len, max_len); for (i=0; i < num_chars; i++) { buf[i] = sb_rand_uniform('0', 'z'); } return num_chars; } /* Unique random sequence generator. This is based on public domain code from https://github.com/preshing/RandomSequence */ static uint32_t rand_unique_permute(uint32_t x) { static const uint32_t prime = UINT32_C(4294967291); if (x >= prime) return x; /* The 5 integers out of range are mapped to themselves. */ uint32_t residue = ((uint64_t) x * x) % prime; return (x <= prime / 2) ? residue : prime - residue; } static void rand_unique_seed(uint32_t index, uint32_t offset) { rand_unique_index = rand_unique_permute(rand_unique_permute(index) + 0x682f0161); rand_unique_offset = rand_unique_permute(rand_unique_permute(offset) + 0x46790905); } /* This is safe to be called concurrently from multiple threads */ uint32_t sb_rand_unique(void) { uint32_t index = ck_pr_faa_32(&rand_unique_index, 1); return rand_unique_permute((rand_unique_permute(index) + rand_unique_offset) ^ 0x5bf03635); } /* Implementation of the Zipf distribution is based on RejectionInversionZipfSampler.java from the Apache Commons RNG project (https://commons.apache.org/proper/commons-rng/) implementing the rejection inversion sampling method for a descrete, bounded Zipf distribution that is in turn based on the method described in: Wolfgang Hörmann and Gerhard Derflinger. "Rejection-inversion to generate variates from monotone discrete distributions", ACM Transactions on Modeling and Computer Simulation, (TOMACS) 6.3 (1996): 169-184. */ static uint32_t sb_rand_zipfian_int(uint32_t n, double e, double s, double hIntegralX1) { /* The paper describes an algorithm for exponents larger than 1 (Algorithm ZRI). The original method uses H(x) = (v + x)^(1 - q) / (1 - q) as the integral of the hat function. This function is undefined for q = 1, which is the reason for the limitation of the exponent. If instead the integral function H(x) = ((v + x)^(1 - q) - 1) / (1 - q) is used, for which a meaningful limit exists for q = 1, the method works for all positive exponents. The following implementation uses v = 0 and generates integral number in the range [1, numberOfElements]. This is different to the original method where v is defined to be positive and numbers are taken from [0, i_max]. This explains why the implementation looks slightly different. */ const double hIntegralNumberOfElements = hIntegral(n + 0.5, e); for (;;) { double u = hIntegralNumberOfElements + sb_rand_uniform_double() * (hIntegralX1 - hIntegralNumberOfElements); /* u is uniformly distributed in (hIntegralX1, hIntegralNumberOfElements] */ double x = hIntegralInverse(u, e); uint32_t k = (uint32_t) (x + 0.5); /* Limit k to the range [1, numberOfElements] if it would be outside due to numerical inaccuracies. */ if (SB_UNLIKELY(k < 1)) k = 1; else if (SB_UNLIKELY(k > n)) k = n; /* Here, the distribution of k is given by: P(k = 1) = C * (hIntegral(1.5) - hIntegralX1) = C P(k = m) = C * (hIntegral(m + 1/2) - hIntegral(m - 1/2)) for m >= 2 where C = 1 / (hIntegralNumberOfElements - hIntegralX1) */ if (k - x <= s || u >= hIntegral(k + 0.5, e) - h(k, e)) { /* Case k = 1: The right inequality is always true, because replacing k by 1 gives u >= hIntegral(1.5) - h(1) = hIntegralX1 and u is taken from (hIntegralX1, hIntegralNumberOfElements]. Therefore, the acceptance rate for k = 1 is P(accepted | k = 1) = 1 and the probability that 1 is returned as random value is P(k = 1 and accepted) = P(accepted | k = 1) * P(k = 1) = C = C / 1^exponent Case k >= 2: The left inequality (k - x <= s) is just a short cut to avoid the more expensive evaluation of the right inequality (u >= hIntegral(k + 0.5) - h(k)) in many cases. If the left inequality is true, the right inequality is also true: Theorem 2 in the paper is valid for all positive exponents, because the requirements h'(x) = -exponent/x^(exponent + 1) < 0 and (-1/hInverse'(x))'' = (1+1/exponent) * x^(1/exponent-1) >= 0 are both fulfilled. Therefore, f(x) = x - hIntegralInverse(hIntegral(x + 0.5) - h(x)) is a non-decreasing function. If k - x <= s holds, k - x <= s + f(k) - f(2) is obviously also true which is equivalent to -x <= -hIntegralInverse(hIntegral(k + 0.5) - h(k)), -hIntegralInverse(u) <= -hIntegralInverse(hIntegral(k + 0.5) - h(k)), and finally u >= hIntegral(k + 0.5) - h(k). Hence, the right inequality determines the acceptance rate: P(accepted | k = m) = h(m) / (hIntegrated(m+1/2) - hIntegrated(m-1/2)) The probability that m is returned is given by P(k = m and accepted) = P(accepted | k = m) * P(k = m) = C * h(m) = C / m^exponent. In both cases the probabilities are proportional to the probability mass function of the Zipf distribution. */ return k; } } } uint32_t sb_rand_zipfian(uint32_t a, uint32_t b) { /* sb_rand_zipfian_int() returns a number in the range [1, b - a + 1] */ return a + sb_rand_zipfian_int(b - a + 1, zipf_exp, zipf_s, zipf_hIntegralX1) - 1; } /* H(x) is defined as (x^(1 - exponent) - 1) / (1 - exponent), exponent != 1 log(x), if exponent == 1 H(x) is an integral function of h(x), the derivative of H(x) is h(x). */ static double hIntegral(double x, double e) { const double logX = log(x); return helper2((1 - e) * logX) * logX; } /* h(x) = 1 / x^exponent */ static double h(double x, double e) { return exp(-e * log(x)); } /* The inverse function of H(x) */ static double hIntegralInverse(double x, double e) { double t = x * (1 -e); if (t < -1) { /* Limit value to the range [-1, +inf). t could be smaller than -1 in some rare cases due to numerical errors. */ t = -1; } return exp(helper1(t) * x); } /* Helper function that calculates log(1 + x) / x. A Taylor series expansion is used, if x is close to 0. */ static double helper1(double x) { if (fabs(x) > 1e-8) return log1p(x) / x; else return 1 - x * (0.5 - x * (0.33333333333333333 - 0.25 * x)); } /* Helper function that calculates (exp(x) - 1) / x. A Taylor series expansion is used, if x is close to 0. */ static double helper2(double x) { if (fabs(x) > 1e-8) return expm1(x) / x; else return 1 + x * 0.5 * (1 + x * 0.33333333333333333 * (1 + 0.25 * x)); } ================================================ FILE: src/sb_rand.h ================================================ /* Copyright (C) 2016-2017 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_RAND_H #define SB_RAND_H #include #include "xoroshiro128plus.h" /* Random numbers distributions */ typedef enum { DIST_TYPE_UNIFORM, DIST_TYPE_GAUSSIAN, DIST_TYPE_PARETO, DIST_TYPE_ZIPFIAN } rand_dist_t; typedef uint64_t sb_rng_state_t [2]; /* optional seed set on the command line */ extern int sb_rand_seed; /* Thread-local RNG state */ extern TLS sb_rng_state_t sb_rng_state; /* Return a uniformly distributed pseudo-random 64-bit unsigned integer */ inline uint64_t sb_rand_uniform_uint64(void) { return xoroshiro_next(sb_rng_state); } /* Return a uniformly distributed pseudo-random double in the [0, 1) interval */ inline double sb_rand_uniform_double(void) { const uint64_t x = sb_rand_uniform_uint64(); const union { uint64_t i; double d; } u = { .i = UINT64_C(0x3FF) << 52 | x >> 12 }; return u.d - 1.0; } int sb_rand_register(void); void sb_rand_print_help(void); int sb_rand_init(void); void sb_rand_done(void); void sb_rand_thread_init(void); /* Generator functions */ uint32_t sb_rand_default(uint32_t, uint32_t); uint32_t sb_rand_uniform(uint32_t, uint32_t); uint32_t sb_rand_gaussian(uint32_t, uint32_t); uint32_t sb_rand_pareto(uint32_t, uint32_t); uint32_t sb_rand_zipfian(uint32_t, uint32_t); uint32_t sb_rand_unique(void); void sb_rand_str(const char *, char *); uint32_t sb_rand_varstr(char *, uint32_t, uint32_t); #endif /* SB_RAND_H */ ================================================ FILE: src/sb_thread.c ================================================ /* Copyright (C) 2016-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Wrappers around pthread_create() and friends to provide necessary (de-)initialization. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_PTHREAD_H # include #endif #ifndef HAVE_PTHREAD_CANCEL #include #endif #include "sb_thread.h" #include "sb_rand.h" #include "sb_logger.h" #include "sysbench.h" #include "sb_ck_pr.h" pthread_attr_t sb_thread_attr; /* Thread descriptors */ static sb_thread_ctxt_t *threads; /* Stack size for each thread */ static int thread_stack_size; int sb_thread_init(void) { thread_stack_size = sb_get_value_size("thread-stack-size"); if (thread_stack_size <= 0) { log_text(LOG_FATAL, "Invalid value for thread-stack-size: %d.\n", thread_stack_size); return 1; } /* initialize attr */ pthread_attr_init(&sb_thread_attr); #ifdef PTHREAD_SCOPE_SYSTEM pthread_attr_setscope(&sb_thread_attr,PTHREAD_SCOPE_SYSTEM); #endif pthread_attr_setstacksize(&sb_thread_attr, thread_stack_size); #ifdef HAVE_THR_SETCONCURRENCY /* Set thread concurrency (required on Solaris) */ thr_setconcurrency(sb_globals.threads); #endif threads = malloc(sb_globals.threads * sizeof(sb_thread_ctxt_t)); if (threads == NULL) { log_text(LOG_FATAL, "Memory allocation failure.\n"); return EXIT_FAILURE; } return EXIT_SUCCESS; } void sb_thread_done(void) { if (threads != NULL) free(threads); } #ifndef HAVE_PTHREAD_CANCEL #define PTHREAD_CANCELED ((void *) -1) struct sb_thread_proxy { void *(*start_routine) (void *); void *arg; }; static int thread_cancel_signal = SIGUSR1; static void thread_cancel_handler(int sig) { if (sig == thread_cancel_signal) pthread_exit(PTHREAD_CANCELED); } static int install_thread_signal_handler(void) { struct sigaction action; memset(&action, 0, sizeof(action)); sigemptyset(&action.sa_mask); action.sa_flags = 0; action.sa_handler = thread_cancel_handler; return sigaction(thread_cancel_signal, &action, NULL); } static void* thread_start_routine_proxy(void *arg) { struct sb_thread_proxy *proxy = arg; void *(*start_routine) (void *) = proxy->start_routine; void *real_arg = proxy->arg; free(proxy); install_thread_signal_handler(); return start_routine(real_arg); } #endif int sb_thread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) { #ifdef HAVE_PTHREAD_CANCEL return pthread_create(thread, attr, start_routine, arg); #else struct sb_thread_proxy *proxy = malloc(sizeof(struct sb_thread_proxy)); if (!proxy) { return EXIT_FAILURE; } proxy->start_routine = start_routine; proxy->arg = arg; int rv = pthread_create(thread, attr, thread_start_routine_proxy, proxy); if (rv) { free(proxy); } return rv; #endif } int sb_thread_join(pthread_t thread, void **retval) { return pthread_join(thread, retval); } int sb_thread_cancel(pthread_t thread) { #ifdef HAVE_PTHREAD_CANCEL return pthread_cancel(thread); #else return pthread_kill(thread, thread_cancel_signal); #endif } int sb_thread_create_workers(void *(*worker_routine)(void*)) { unsigned int i; log_text(LOG_NOTICE, "Initializing worker threads...\n"); for(i = 0; i < sb_globals.threads; i++) { threads[i].id = i; } for(i = 0; i < sb_globals.threads; i++) { int err; if ((err = sb_thread_create(&(threads[i].thread), &sb_thread_attr, worker_routine, (void*)(threads + i))) != 0) { log_errno(LOG_FATAL, "sb_thread_create() for thread #%d failed.", i); return EXIT_FAILURE; } } return EXIT_SUCCESS; } int sb_thread_join_workers(void) { for(unsigned i = 0; i < sb_globals.threads; i++) { int err; if((err = sb_thread_join(threads[i].thread, NULL)) != 0) log_errno(LOG_FATAL, "sb_thread_join() for thread #%d failed.", i); ck_pr_dec_uint(&sb_globals.threads_running); } return EXIT_SUCCESS; } ================================================ FILE: src/sb_thread.h ================================================ /* Copyright (C) 2016-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Wrappers around pthread_create() and friends to provide necessary (de-)initialization. */ #ifndef SB_THREAD_H #define SB_THREAD_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_PTHREAD_H # include #endif /* Thread context definition */ typedef struct { pthread_t thread; unsigned int id; } sb_thread_ctxt_t; extern pthread_attr_t sb_thread_attr; int sb_thread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); int sb_thread_join(pthread_t thread, void **retval); int sb_thread_cancel(pthread_t thread); int sb_thread_create_workers(void *(*worker_routine)(void*)); int sb_thread_join_workers(void); int sb_thread_init(void); void sb_thread_done(void); #endif /* SB_THREAD_H */ ================================================ FILE: src/sb_timer.c ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2017 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef STDC_HEADERS # include #endif #ifdef HAVE_STRING_H # include #endif #include "sb_logger.h" #include "sb_timer.h" #include "sb_util.h" /* Some functions for simple time operations */ /* initialize timer */ void sb_timer_init(sb_timer_t *t) { SB_COMPILE_TIME_ASSERT(sizeof(sb_timer_t) % CK_MD_CACHELINE == 0); memset(&t->time_start, 0, sizeof(struct timespec)); memset(&t->time_end, 0, sizeof(struct timespec)); ck_spinlock_init(&t->lock); sb_timer_reset(t); } /* Reset timer counters, but leave the current state intact */ void sb_timer_reset(sb_timer_t *t) { t->min_time = UINT64_MAX; t->max_time = 0; t->sum_time = 0; t->events = 0; t->queue_time = 0; } /* Clone a timer */ void sb_timer_copy(sb_timer_t *to, sb_timer_t *from) { memcpy(to, from, sizeof(sb_timer_t)); ck_spinlock_init(&to->lock); } /* check whether the timer is running */ bool sb_timer_running(sb_timer_t *t) { return TIMESPEC_DIFF(t->time_start, t->time_end) > 0; } /* get time elapsed since the previous call to sb_timer_current() for the specified timer without stopping it. The first call returns time elapsed since the timer was started. */ uint64_t sb_timer_current(sb_timer_t *t) { struct timespec tmp; uint64_t res; SB_GETTIME(&tmp); res = TIMESPEC_DIFF(tmp, t->time_start); t->time_start = tmp; return res; } /* Atomically reset a given timer after copying its state into the timer pointed to by 'old'. */ void sb_timer_checkpoint(sb_timer_t *t, sb_timer_t *old) { ck_spinlock_lock(&t->lock); memcpy(old, t, sizeof(*old)); ck_spinlock_init(&old->lock); sb_timer_reset(t); ck_spinlock_unlock(&t->lock); } /* get average time per event */ uint64_t sb_timer_avg(sb_timer_t *t) { if(t->events == 0) return 0; /* return zero if there were no events */ return (t->sum_time / t->events); } /* get total time for all events */ uint64_t sb_timer_sum(sb_timer_t *t) { return t->sum_time; } /* get minimum time */ uint64_t sb_timer_min(sb_timer_t *t) { if (t->events == 0) return 0; return t->min_time; } /* get maximum time */ uint64_t sb_timer_max(sb_timer_t *t) { return t->max_time; } /* sum data from several timers. used in summing data from multiple threads */ sb_timer_t sb_timer_merge(sb_timer_t *t1, sb_timer_t *t2) { sb_timer_t t; /* Initialize to avoid warnings */ memset(&t, 0, sizeof(sb_timer_t)); t.sum_time = t1->sum_time+t2->sum_time; t.events = t1->events+t2->events; if (t1->max_time > t2->max_time) t.max_time = t1->max_time; else t.max_time = t2->max_time; if (t1->min_timemin_time) t.min_time = t1->min_time; else t.min_time = t2->min_time; return t; } ================================================ FILE: src/sb_timer.h ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_TIMER_H #define SB_TIMER_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #include #include #include "sb_util.h" #include "ck_spinlock.h" #define NS_PER_SEC 1000000000 #define US_PER_SEC 1000000 #define MS_PER_SEC 1000 #define NS_PER_MS (NS_PER_SEC / MS_PER_SEC) /* Convert nanoseconds to seconds and vice versa */ #define NS2SEC(nsec) ((nsec) / (double) NS_PER_SEC) #define SEC2NS(sec) ((uint64_t) (sec) * NS_PER_SEC) /* Convert nanoseconds to milliseconds and vice versa */ #define NS2MS(nsec) ((nsec) / (double) NS_PER_MS) #define MS2NS(sec) ((sec) * (uint64_t) NS_PER_MS) /* Convert milliseconds to seconds and vice versa */ #define MS2SEC(msec) ((msec) / (double) MS_PER_SEC) #define SEC2MS(sec) ((sec) * MS_PER_SEC) /* Difference between two 'timespec' values in nanoseconds */ #define TIMESPEC_DIFF(a,b) (SEC2NS(a.tv_sec - b.tv_sec) + \ (a.tv_nsec - b.tv_nsec)) /* Wrapper over various *gettime* functions */ #ifdef HAVE_CLOCK_GETTIME # define SB_GETTIME(tsp) clock_gettime(CLOCK_MONOTONIC, tsp) #else # define SB_GETTIME(tsp) \ do { \ struct timeval tv; \ gettimeofday(&tv, NULL); \ (tsp)->tv_sec = tv.tv_sec; \ (tsp)->tv_nsec = tv.tv_usec * 1000; \ } while (0) #endif typedef enum {TIMER_UNINITIALIZED, TIMER_INITIALIZED, TIMER_STOPPED, \ TIMER_RUNNING} timer_state_t; /* Timer structure definition */ typedef struct { struct timespec time_start; struct timespec time_end; uint64_t events; uint64_t queue_time; uint64_t min_time; uint64_t max_time; uint64_t sum_time; ck_spinlock_t lock; char pad[SB_CACHELINE_PAD(sizeof(struct timespec)*2 + sizeof(uint64_t)*5 + sizeof(ck_spinlock_t))]; } sb_timer_t; static inline int sb_nanosleep(uint64_t ns) { struct timespec ts = { ns / NS_PER_SEC, ns % NS_PER_SEC }; return nanosleep(&ts, NULL); } /* timer control functions */ /* Initialize timer */ void sb_timer_init(sb_timer_t *); /* Reset timer counters, but leave the current state intact */ void sb_timer_reset(sb_timer_t *t); /* check whether the timer is running */ bool sb_timer_running(sb_timer_t *t); /* start timer */ static inline void sb_timer_start(sb_timer_t *t) { ck_spinlock_lock(&t->lock); SB_GETTIME(&t->time_start); ck_spinlock_unlock(&t->lock); } /* stop timer */ static inline uint64_t sb_timer_stop(sb_timer_t *t) { ck_spinlock_lock(&t->lock); SB_GETTIME(&t->time_end); uint64_t elapsed = TIMESPEC_DIFF(t->time_end, t->time_start) + t->queue_time; t->events++; t->sum_time += elapsed; if (SB_UNLIKELY(elapsed < t->min_time)) t->min_time = elapsed; if (SB_UNLIKELY(elapsed > t->max_time)) t->max_time = elapsed; ck_spinlock_unlock(&t->lock); return elapsed; } /* get the current timer value in nanoseconds without affecting its state, i.e. is safe to be used concurrently on a shared timer. */ static inline uint64_t sb_timer_value(sb_timer_t *t) { struct timespec ts; SB_GETTIME(&ts); return TIMESPEC_DIFF(ts, t->time_start) + t->queue_time; } /* Clone a timer */ void sb_timer_copy(sb_timer_t *to, sb_timer_t *from); /* get time elapsed since the previous call to sb_timer_checkpoint() for the specified timer without stopping it. The first call returns time elapsed since the timer was started. */ uint64_t sb_timer_current(sb_timer_t *t); /* Atomically reset a given timer after copying its state into the timer pointed to by 'old'. */ void sb_timer_checkpoint(sb_timer_t *t, sb_timer_t *old); /* get average time per event */ uint64_t sb_timer_avg(sb_timer_t *); /* get total time for all events */ uint64_t sb_timer_sum(sb_timer_t *); /* get minimum time */ uint64_t sb_timer_min(sb_timer_t *); /* get maximum time */ uint64_t sb_timer_max(sb_timer_t *); /* sum data from two timers. used in summing data from multiple threads */ sb_timer_t sb_timer_merge(sb_timer_t *, sb_timer_t *); #endif /* SB_TIMER_H */ ================================================ FILE: src/sb_util.c ================================================ /* Copyright (C) 2017-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef STDC_HEADERS # include # include #endif #ifdef HAVE_UNISTD_H # include #endif #include "sb_util.h" #include "sb_logger.h" /* Allocate a buffer of a specified size such that the address is a multiple of a specified alignment. */ void *sb_memalign(size_t size, size_t alignment) { void *buf; #ifdef HAVE_POSIX_MEMALIGN int ret= posix_memalign(&buf, alignment, size); if (ret != 0) buf = NULL; #elif defined(HAVE_MEMALIGN) buf = memalign(alignment, size); #elif defined(HAVE_VALLOC) /* Allocate on page boundary */ (void) alignment; /* unused */ buffer = valloc(size); #else # error Cannot find an aligned allocation library function! #endif return buf; } /* Get OS page size */ size_t sb_getpagesize(void) { #ifdef _SC_PAGESIZE return sysconf(_SC_PAGESIZE); #else return getpagesize(); #endif } ================================================ FILE: src/sb_util.h ================================================ /* Copyright (C) 2017 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_UTIL_H #define SB_UTIL_H /* General utility macros and functions. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_UNISTD_H # include #endif #include "ck_md.h" #include "ck_cc.h" #ifdef HAVE_FUNC_ATTRIBUTE_FORMAT # define SB_ATTRIBUTE_FORMAT(style, m, n) __attribute__((format(style, m, n))) #else # define SB_ATTRIBUTE_FORMAT(style, m, n) #endif #ifdef HAVE_FUNC_ATTRIBUTE_UNUSED # define SB_ATTRIBUTE_UNUSED __attribute__((unused)) #else # define SB_ATTRIBUTE_UNUSED #endif #if defined(__MACH__) # define DLEXT ".dylib" #else # define DLEXT ".so" #endif /* Calculate the smallest multiple of m that is not smaller than n, when m is a power of 2. */ #define SB_ALIGN(n, m) (((n) + ((m) - 1)) & ~((m) - 1)) /* Calculate padding, i.e. distance from n to SB_ALIGN(n, m), where m is a power of 2. */ #define SB_PAD(n, m) (SB_ALIGN((n),(m)) - (n)) /* Calculate padding to cache line size. */ #define SB_CACHELINE_PAD(n) (SB_PAD((n), CK_MD_CACHELINE)) /* Minimum/maximum values */ #ifdef __GNUC__ # define SB_MIN(a,b) \ ({ __typeof__ (a) _a = (a); \ __typeof__ (b) _b = (b); \ _a < _b ? _a : _b; }) # define SB_MAX(a,b) \ ({ __typeof__ (a) _a = (a); \ __typeof__ (b) _b = (b); \ _a > _b ? _a : _b; }) #else # define SB_MIN(a,b) (((a) < (b)) ? (a) : (b)) # define SB_MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif /* __GNUC__ */ #define SB_LIKELY(x) CK_CC_LIKELY(x) #define SB_UNLIKELY(x) CK_CC_UNLIKELY(x) /* SB_CONTAINER_OF */ #ifdef __GNUC__ # define SB_MEMBER_TYPE(type, member) __typeof__ (((type *)0)->member) #else # define SB_MEMBER_TYPE(type, member) const void #endif /* __GNUC__ */ #define SB_CONTAINER_OF(ptr, type, member) ((type *)(void *)( \ (char *)(SB_MEMBER_TYPE(type, member) *){ ptr } - offsetof(type, member))) /* Compile-time assertion */ #define SB_COMPILE_TIME_ASSERT(expr) \ do { \ typedef char cta[(expr) ? 1 : -1] SB_ATTRIBUTE_UNUSED; \ } while(0) #ifdef HAVE_ISATTY # define SB_ISATTY() isatty(0) #else # error No isatty() implementation for this platform! #endif /* Allocate a buffer of a specified size such that the address is a multiple of a specified alignment. */ void *sb_memalign(size_t size, size_t alignment); /* Get OS page size */ size_t sb_getpagesize(void); #endif /* SB_UTIL_H */ ================================================ FILE: src/sysbench.c ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef STDC_HEADERS # include # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_UNISTD_H # include # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_ERRNO_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_PTHREAD_H # include #endif #ifdef HAVE_THREAD_H # include #endif #ifdef HAVE_MATH_H # include #endif #ifdef HAVE_SCHED_H # include #endif #ifdef HAVE_SIGNAL_H # include #endif #ifdef HAVE_LIMITS_H # include #endif #include #include "sysbench.h" #include "sb_options.h" #include "sb_lua.h" #include "db_driver.h" #include "sb_rand.h" #include "sb_thread.h" #include "sb_barrier.h" #include "ck_cc.h" #include "ck_ring.h" #define VERSION_STRING PACKAGE" "PACKAGE_VERSION SB_GIT_SHA /* Maximum queue length for the tx-rate mode. Must be a power of 2 */ #define MAX_QUEUE_LEN 131072 /* Extra thread ID assigned to background threads. This may be used as an index into per-thread arrays (see comment in sb_alloc_per_thread_array(). */ #define SB_BACKGROUND_THREAD_ID sb_globals.threads /* General options */ sb_arg_t general_args[] = { SB_OPT("threads", "number of threads to use", "1", INT), SB_OPT("events", "limit for total number of events", "0", INT), SB_OPT("time", "limit for total execution time in seconds", "10", INT), SB_OPT("warmup-time", "execute events for this many seconds with statistics " "disabled before the actual benchmark run with statistics enabled", "0", INT), SB_OPT("forced-shutdown", "number of seconds to wait after the --time limit before forcing " "shutdown, or 'off' to disable", "off", STRING), SB_OPT("thread-stack-size", "size of stack per thread", "64K", SIZE), SB_OPT("thread-init-timeout", "wait time in seconds for worker threads to initialize", "30", INT), SB_OPT("rate", "average transactions rate. 0 for unlimited rate", "0", INT), SB_OPT("report-interval", "periodically report intermediate statistics with " "a specified interval in seconds. 0 disables intermediate reports", "0", INT), SB_OPT("report-checkpoints", "dump full statistics and reset all counters at " "specified points in time. The argument is a list of comma-separated " "values representing the amount of time in seconds elapsed from start " "of test when report checkpoint(s) must be performed. Report " "checkpoints are off by default.", "", LIST), SB_OPT("debug", "print more debugging info", "off", BOOL), SB_OPT("validate", "perform validation checks where possible", "off", BOOL), SB_OPT("help", "print help and exit", "off", BOOL), SB_OPT("version", "print version and exit", "off", BOOL), SB_OPT("config-file", "File containing command line options", NULL, FILE), SB_OPT("luajit-cmd", "perform LuaJIT control command. This option is " "equivalent to 'luajit -j'. See LuaJIT documentation for more " "information", NULL, STRING), SB_OPT_END }; /* List of available tests */ sb_list_t tests; /* Global variables */ sb_globals_t sb_globals; sb_test_t *current_test; /* Barrier to ensure we start the benchmark run when all workers are ready */ static sb_barrier_t worker_barrier; /* Wait at most this number of seconds for worker threads to initialize */ static int thread_init_timeout; /* Barrier to signal reporting threads */ static sb_barrier_t report_barrier; /* structures to handle queue of events, needed for tx_rate mode */ static pthread_mutex_t queue_mutex; static pthread_cond_t queue_cond; static uint64_t queue_array[MAX_QUEUE_LEN] CK_CC_CACHELINE; static ck_ring_buffer_t queue_ring_buffer[MAX_QUEUE_LEN] CK_CC_CACHELINE; static ck_ring_t queue_ring CK_CC_CACHELINE; static int report_thread_created CK_CC_CACHELINE; static int checkpoints_thread_created; static int eventgen_thread_created; /* per-thread timers for response time stats */ static sb_timer_t *timers; /* Temporary copy of timers for checkpoint reports */ static sb_timer_t *timers_copy; /* Global execution timer */ sb_timer_t sb_exec_timer CK_CC_CACHELINE; /* timers for intermediate/checkpoint reports */ sb_timer_t sb_intermediate_timer CK_CC_CACHELINE; sb_timer_t sb_checkpoint_timer CK_CC_CACHELINE; TLS int sb_tls_thread_id; static void print_header(void); static void print_help(void); static void print_run_mode(sb_test_t *); #ifdef HAVE_ALARM static void sigalrm_thread_init_timeout_handler(int sig) { if (sig != SIGALRM) return; log_text(LOG_FATAL, "Worker threads failed to initialize within %u seconds!", thread_init_timeout); exit(2); } /* Default intermediate reports handler */ void sb_report_intermediate(sb_stat_t *stat) { log_timestamp(LOG_NOTICE, stat->time_total, "thds: %" PRIu32 " eps: %4.2f lat (ms,%u%%): %4.2f", stat->threads_running, stat->events / stat->time_interval, sb_globals.percentile, SEC2MS(stat->latency_pct)); if (sb_globals.tx_rate > 0) log_timestamp(LOG_NOTICE, stat->time_total, "queue length: %" PRIu64 " concurrency: %" PRIu64, stat->queue_length, stat->concurrency); } static void report_get_common_stat(sb_stat_t *stat, sb_counters_t cnt) { memset(stat, 0, sizeof(sb_stat_t)); stat->threads_running = sb_globals.threads_running; stat->events = cnt[SB_CNT_EVENT]; stat->reads = cnt[SB_CNT_READ]; stat->writes = cnt[SB_CNT_WRITE]; stat->other = cnt[SB_CNT_OTHER]; stat->errors = cnt[SB_CNT_ERROR]; stat->reconnects = cnt[SB_CNT_RECONNECT]; stat->bytes_read = cnt[SB_CNT_BYTES_READ]; stat->bytes_written = cnt[SB_CNT_BYTES_WRITTEN]; stat->time_total = NS2SEC(sb_timer_value(&sb_exec_timer)) - sb_globals.warmup_time; } static void report_intermediate(void) { sb_stat_t stat; sb_counters_t cnt; /* sb_globals.report_interval may be set to 0 by the master thread to silence intermediate reports at the end of the test */ if (ck_pr_load_uint(&sb_globals.report_interval) == 0) return; sb_counters_agg_intermediate(cnt); report_get_common_stat(&stat, cnt); stat.latency_pct = MS2SEC(sb_histogram_get_pct_intermediate(&sb_latency_histogram, sb_globals.percentile)); stat.time_interval = NS2SEC(sb_timer_current(&sb_intermediate_timer)); if (sb_globals.tx_rate > 0) { stat.queue_length = ck_ring_size(&queue_ring); stat.concurrency = ck_pr_load_int(&sb_globals.concurrency); } if (current_test && current_test->ops.report_intermediate) current_test->ops.report_intermediate(&stat); else sb_report_intermediate(&stat); } /* Default cumulative reports handler */ void sb_report_cumulative(sb_stat_t *stat) { const unsigned int nthreads = sb_globals.threads; if (sb_globals.forced_shutdown_in_progress) { /* In case we print statistics on forced shutdown, there may be (potentially long running or hung) transactions which are still in progress. We still want to reflect them in statistics, so stop running timers to consider long transactions as done at the forced shutdown time, and print a counter of still running transactions. */ unsigned unfinished = 0; for (unsigned i = 0; i < nthreads; i++) { if (sb_timer_running(&timers_copy[i])) { unfinished++; sb_timer_stop(&timers_copy[i]); }; } if (unfinished > 0) { log_text(LOG_NOTICE, ""); log_text(LOG_NOTICE, "Number of unfinished transactions on " "forced shutdown: %u", unfinished); } } log_text(LOG_NOTICE, ""); log_text(LOG_NOTICE, "Throughput:"); log_text(LOG_NOTICE, " events/s (eps): %.4f", stat->events / stat->time_interval); log_text(LOG_NOTICE, " time elapsed: %.4fs", stat->time_total); log_text(LOG_NOTICE, " total number of events: %" PRIu64, stat->events); log_text(LOG_NOTICE, ""); log_text(LOG_NOTICE, "Latency (ms):"); log_text(LOG_NOTICE, " min: %39.2f", SEC2MS(stat->latency_min)); log_text(LOG_NOTICE, " avg: %39.2f", SEC2MS(stat->latency_avg)); log_text(LOG_NOTICE, " max: %39.2f", SEC2MS(stat->latency_max)); if (sb_globals.percentile > 0) log_text(LOG_NOTICE, " %3dth percentile: %27.2f", sb_globals.percentile, SEC2MS(stat->latency_pct)); else log_text(LOG_NOTICE, " percentile stats: disabled"); log_text(LOG_NOTICE, " sum: %39.2f", SEC2MS(stat->latency_sum)); log_text(LOG_NOTICE, ""); /* Aggregate temporary timers copy */ sb_timer_t t; sb_timer_init(&t); for(unsigned i = 0; i < nthreads; i++) t = sb_timer_merge(&t, &timers_copy[i]); /* Calculate and print events distribution by threads */ const double events_avg = (double) t.events / nthreads; const double time_avg = stat->latency_sum / nthreads; double events_stddev = 0; double time_stddev = 0; for(unsigned i = 0; i < nthreads; i++) { double diff = fabs(events_avg - timers_copy[i].events); events_stddev += diff * diff; diff = fabs(time_avg - NS2SEC(sb_timer_sum(&timers_copy[i]))); time_stddev += diff * diff; } events_stddev = sqrt(events_stddev / nthreads); time_stddev = sqrt(time_stddev / nthreads); log_text(LOG_NOTICE, "Threads fairness:"); log_text(LOG_NOTICE, " events (avg/stddev): %.4f/%3.2f", events_avg, events_stddev); log_text(LOG_NOTICE, " execution time (avg/stddev): %.4f/%3.2f", time_avg, time_stddev); log_text(LOG_NOTICE, ""); if (sb_globals.debug) { log_text(LOG_DEBUG, "Verbose per-thread statistics:\n"); for(unsigned i = 0; i < nthreads; i++) { log_text(LOG_DEBUG, " thread #%3d: min: %.4fs avg: %.4fs max: %.4fs " "events: %" PRIu64, i, NS2SEC(sb_timer_min(&timers_copy[i])), NS2SEC(sb_timer_avg(&timers_copy[i])), NS2SEC(sb_timer_max(&timers_copy[i])), timers_copy[i].events); log_text(LOG_DEBUG, " " "total time taken by event execution: %.4fs", NS2SEC(sb_timer_sum(&timers_copy[i]))); } log_text(LOG_NOTICE, ""); } } /* Do a checkpoint, i.e. aggregate and reset collected statistics */ static void checkpoint(sb_stat_t *stat) { sb_counters_t cnt; sb_counters_agg_cumulative(cnt); report_get_common_stat(stat, cnt); stat->time_interval = NS2SEC(sb_timer_current(&sb_checkpoint_timer)); stat->latency_pct = MS2SEC(sb_histogram_get_pct_checkpoint(&sb_latency_histogram, sb_globals.percentile)); /* Atomically reset each timer after copying it into its timers_copy slot */ for (size_t i = 0; i < sb_globals.threads; i++) sb_timer_checkpoint(&timers[i], &timers_copy[i]); } static void report_cumulative(void) { sb_stat_t stat; sb_timer_t t; checkpoint(&stat); sb_timer_init(&t); /* Aggregate temporary timers copy populated by checkpoint() */ for(size_t i = 0; i < sb_globals.threads; i++) t = sb_timer_merge(&t, &timers_copy[i]); /* Calculate aggregate latency values */ stat.latency_min = NS2SEC(sb_timer_min(&t)); stat.latency_max = NS2SEC(sb_timer_max(&t)); stat.latency_avg = NS2SEC(sb_timer_avg(&t)); stat.latency_sum = NS2SEC(sb_timer_sum(&t)); if (current_test && current_test->ops.report_cumulative) current_test->ops.report_cumulative(&stat); else sb_report_cumulative(&stat); } static void sigalrm_forced_shutdown_handler(int sig) { if (sig != SIGALRM) return; sb_globals.forced_shutdown_in_progress = 1; sb_timer_stop(&sb_exec_timer); sb_timer_stop(&sb_intermediate_timer); sb_timer_stop(&sb_checkpoint_timer); log_text(LOG_FATAL, "The --max-time limit has expired, forcing shutdown..."); report_cumulative(); log_done(); exit(2); } #endif static int register_tests(void) { SB_LIST_INIT(&tests); /* Register tests */ return register_test_fileio(&tests) + register_test_cpu(&tests) + register_test_memory(&tests) + register_test_threads(&tests) + register_test_mutex(&tests) + db_register() + sb_rand_register() ; } /* Print program header */ void print_header(void) { log_text(LOG_NOTICE, "%s (using %s %s)\n", VERSION_STRING, SB_WITH_LUAJIT, LUAJIT_VERSION); } /* Print program usage */ void print_help(void) { sb_list_item_t *pos; sb_test_t *test; printf("Usage:\n"); printf(" sysbench [options]... [testname] [command]\n\n"); printf("Commands implemented by most tests: prepare run cleanup help\n\n"); printf("General options:\n"); sb_print_options(general_args); sb_rand_print_help(); log_print_help(); db_print_help(); printf("Compiled-in tests:\n"); SB_LIST_FOR_EACH(pos, &tests) { test = SB_LIST_ENTRY(pos, sb_test_t, listitem); printf(" %s - %s\n", test->sname, test->lname); } printf("\n"); printf("See 'sysbench help' for a list of options for " "each test.\n\n"); } /* Set an option value if a default value has been previously set with sb_register_arg_set(), i.e. if it's a 'known' option, or ignore_unknown is 'true'. In which case return 0, otherwise return 1. */ static int parse_option(char *name, bool ignore_unknown) { const char *value; char *tmp; option_t *opt; char ctmp = 0; int rc; tmp = strchr(name, '='); if (tmp != NULL) { ctmp = *tmp; *tmp = '\0'; value = tmp + 1; } else { value = NULL; } opt = sb_find_option(name); if (opt != NULL || ignore_unknown) rc = set_option(name, value, opt != NULL ? opt->type : SB_ARG_TYPE_STRING) == NULL; else rc = 1; if (tmp != NULL) *tmp = ctmp; return rc; } /* Parse general command line arguments. Test-specific argument are parsed by parse_test_arguments() at a later stage when a builtin test or a Lua script is known. */ static int parse_general_arguments(int argc, char *argv[]) { const char * testname; const char * cmdname; /* Set default values for general options */ if (sb_register_arg_set(general_args)) return 1; /* Parse command line arguments */ testname = NULL; cmdname = NULL; for (int i = 1; i < argc; i++) { if (strncmp(argv[i], "--", 2)) { if (testname == NULL) { testname = argv[i]; continue; } if (cmdname == NULL) { cmdname = argv[i]; continue; } fprintf(stderr, "Unrecognized command line argument: %s\n", argv[i]); return 1; } else if (!parse_option(argv[i]+2, false)) { /* An option from general_args. Exclude it from future processing */ argv[i] = NULL; } } sb_globals.testname = testname; sb_globals.cmdname = cmdname; return 0; } /* Parse test-specific arguments */ static int parse_test_arguments(sb_test_t *test, int argc, char *argv[]) { /* Set default values */ if (test->args != NULL && sb_register_arg_set(test->args)) return 1; for (int i = 1; i < argc; i++) { /* Skip already parsed and non-option arguments */ if (argv[i] == NULL || strncmp(argv[i], "--", 2)) continue; /* At this stage an unrecognized option must throw a error. */ if (parse_option(argv[i]+2, false)) { fprintf(stderr, "invalid option: %s\n", argv[i]); return 1; } argv[i] = NULL; } return 0; } void print_run_mode(sb_test_t *test) { log_text(LOG_NOTICE, "Running the test with following options:"); log_text(LOG_NOTICE, "Number of threads: %d", sb_globals.threads); if (sb_globals.warmup_time > 0) log_text(LOG_NOTICE, "Warmup time: %ds", sb_globals.warmup_time); if (sb_globals.tx_rate > 0) { log_text(LOG_NOTICE, "Target transaction rate: %d/sec", sb_globals.tx_rate); } if (sb_globals.report_interval) { log_text(LOG_NOTICE, "Report intermediate results every %d second(s)", sb_globals.report_interval); } if (sb_globals.n_checkpoints > 0) { char list_str[MAX_CHECKPOINTS * 12]; char *tmp = list_str; unsigned int i; int n, size = sizeof(list_str); for (i = 0; i < sb_globals.n_checkpoints - 1; i++) { n = snprintf(tmp, size, "%u, ", sb_globals.checkpoints[i]); if (n >= size) break; tmp += n; size -= n; } if (i == sb_globals.n_checkpoints - 1) snprintf(tmp, size, "%u", sb_globals.checkpoints[i]); log_text(LOG_NOTICE, "Report checkpoint(s) at %s seconds", list_str); } if (sb_globals.debug) log_text(LOG_NOTICE, "Debug mode enabled.\n"); if (sb_globals.validate) log_text(LOG_NOTICE, "Validation checks: on.\n"); if (sb_rand_seed) { log_text(LOG_NOTICE, "Initializing random number generator from seed (%d).\n", sb_rand_seed); srandom(sb_rand_seed); } else { log_text(LOG_NOTICE, "Initializing random number generator from current time\n"); srandom(time(NULL)); } if (sb_globals.force_shutdown) log_text(LOG_NOTICE, "Forcing shutdown in %u seconds", (unsigned) NS2SEC(sb_globals.max_time_ns) + sb_globals.timeout); log_text(LOG_NOTICE, ""); if (test->ops.print_mode != NULL) test->ops.print_mode(); } bool sb_more_events(int thread_id) { (void) thread_id; /* unused */ if (sb_globals.error) return false; /* Check if we have a time limit */ if (sb_globals.max_time_ns > 0 && SB_UNLIKELY(sb_timer_value(&sb_exec_timer) >= sb_globals.max_time_ns)) { log_text(LOG_INFO, "Time limit exceeded, exiting..."); return false; } /* Check if we have a limit on the number of events */ const uint64_t max_events = ck_pr_load_64(&sb_globals.max_events); if (max_events > 0 && SB_UNLIKELY(ck_pr_faa_64(&sb_globals.nevents, 1) >= max_events)) { log_text(LOG_INFO, "Event limit exceeded, exiting..."); return false; } /* If we are in tx_rate mode, we take events from queue */ if (sb_globals.tx_rate > 0) { void *ptr = NULL; while (!ck_ring_dequeue_spmc(&queue_ring, queue_ring_buffer, &ptr) && !sb_globals.error) { pthread_mutex_lock(&queue_mutex); pthread_cond_wait(&queue_cond, &queue_mutex); pthread_mutex_unlock(&queue_mutex); /* Re-check for global error and time limit after waiting */ if (sb_globals.error) return false; if (sb_globals.max_time_ns > 0 && SB_UNLIKELY(sb_timer_value(&sb_exec_timer) >= sb_globals.max_time_ns)) { log_text(LOG_INFO, "Time limit exceeded, exiting..."); return false; } } ck_pr_inc_int(&sb_globals.concurrency); timers[thread_id].queue_time = sb_timer_value(&sb_exec_timer) - ((uint64_t *) ptr)[0]; } return true; } void sb_event_start(int thread_id) { sb_timer_start(&timers[thread_id]); } void sb_event_stop(int thread_id) { sb_timer_t *timer = &timers[thread_id]; long long value; value = sb_timer_stop(timer); if (sb_globals.percentile > 0) sb_histogram_update(&sb_latency_histogram, NS2MS(value)); sb_counter_inc(thread_id, SB_CNT_EVENT); if (sb_globals.tx_rate > 0) { ck_pr_dec_int(&sb_globals.concurrency); } } /* Main event loop -- the default thread_run implementation */ static int thread_run(sb_test_t *test, int thread_id) { sb_event_t event; int rc = 0; while (sb_more_events(thread_id) && rc == 0) { event = test->ops.next_event(thread_id); if (event.type == SB_REQ_TYPE_NULL) break; sb_event_start(thread_id); rc = test->ops.execute_event(&event, thread_id); sb_event_stop(thread_id); } return rc; } /* Main worker thread */ static void *worker_thread(void *arg) { sb_thread_ctxt_t *ctxt; unsigned int thread_id; int rc; ctxt = (sb_thread_ctxt_t *)arg; sb_test_t * const test = current_test; sb_tls_thread_id = thread_id = ctxt->id; /* Initialize thread-local RNG state */ sb_rand_thread_init(); log_text(LOG_DEBUG, "Worker thread (#%d) started", thread_id); if (test->ops.thread_init != NULL && test->ops.thread_init(thread_id) != 0) { log_text(LOG_DEBUG, "Worker thread (#%d) failed to initialize!", thread_id); sb_globals.error = 1; /* Avoid blocking the main thread */ sb_barrier_wait(&worker_barrier); return NULL; } log_text(LOG_DEBUG, "Worker thread (#%d) initialized", thread_id); /* Wait for other threads to initialize */ if (sb_barrier_wait(&worker_barrier) < 0) return NULL; if (test->ops.thread_run != NULL) { /* Use benchmark-provided thread_run implementation */ rc = test->ops.thread_run(thread_id); } else { /* Use default thread_run implementation */ rc = thread_run(test, thread_id); } if (rc != 0) sb_globals.error = 1; else if (test->ops.thread_done != NULL) test->ops.thread_done(thread_id); return NULL; } /* Generate exponentially distributed number with a given Lambda */ static inline double sb_rand_exp(double lambda) { return -lambda * log(1 - sb_rand_uniform_double()); } static void *eventgen_thread_proc(void *arg) { (void)arg; /* unused */ sb_tls_thread_id = SB_BACKGROUND_THREAD_ID; /* Initialize thread-local RNG state */ sb_rand_thread_init(); ck_ring_init(&queue_ring, MAX_QUEUE_LEN); if (pthread_mutex_init(&queue_mutex, NULL) || pthread_cond_init(&queue_cond, NULL)) { sb_barrier_wait(&worker_barrier); return NULL; } log_text(LOG_DEBUG, "Event generating thread started"); /* Wait for the worker threads to initialize */ if (sb_barrier_wait(&worker_barrier) < 0) return NULL; eventgen_thread_created = 1; /* Get exponentially distributed time intervals in nanoseconds with Lambda = tx_rate. Alternatively, we can use Lambda = tx_rate / 1e9 */ const double lambda = 1e9 / sb_globals.tx_rate; uint64_t curr_ns = sb_timer_value(&sb_exec_timer); uint64_t intr_ns = sb_rand_exp(lambda); uint64_t next_ns = curr_ns + intr_ns; for (int i = 0; ; i = (i+1) % MAX_QUEUE_LEN) { curr_ns = sb_timer_value(&sb_exec_timer); intr_ns = sb_rand_exp(lambda); next_ns += intr_ns; if (sb_globals.max_time_ns > 0 && SB_UNLIKELY(curr_ns >= sb_globals.max_time_ns)) { /* Wake all waiting threads */ pthread_cond_broadcast(&queue_cond); return NULL; } if (next_ns > curr_ns) sb_nanosleep(next_ns - curr_ns); /* Enqueue a new event */ queue_array[i] = sb_timer_value(&sb_exec_timer); if (ck_ring_enqueue_spmc(&queue_ring, queue_ring_buffer, &queue_array[i]) == false) { sb_globals.error = 1; log_text(LOG_FATAL, "The event queue is full. This means the worker threads are " "unable to keep up with the specified event generation rate"); pthread_cond_broadcast(&queue_cond); return NULL; } /* Wake up one waiting thread, if there are any */ pthread_cond_signal(&queue_cond); } return NULL; } /* Intermediate reports thread */ static void *report_thread_proc(void *arg) { unsigned long long pause_ns; unsigned long long prev_ns; unsigned long long next_ns; unsigned long long curr_ns; const unsigned long long interval_ns = SEC2NS(sb_globals.report_interval); (void)arg; /* unused */ sb_tls_thread_id = SB_BACKGROUND_THREAD_ID; /* Initialize thread-local RNG state */ sb_rand_thread_init(); if (sb_lua_loaded() && sb_lua_report_thread_init()) return NULL; pthread_cleanup_push(sb_lua_report_thread_done, NULL); log_text(LOG_DEBUG, "Reporting thread started"); /* Wait for the signal from the main thread to start reporting */ if (sb_barrier_wait(&report_barrier) < 0) return NULL; report_thread_created = 1; pause_ns = interval_ns; prev_ns = sb_timer_value(&sb_exec_timer) + interval_ns; for (;;) { sb_nanosleep(pause_ns); report_intermediate(); curr_ns = sb_timer_value(&sb_exec_timer); do { next_ns = prev_ns + interval_ns; prev_ns = next_ns; } while (curr_ns >= next_ns); pause_ns = next_ns - curr_ns; } pthread_cleanup_pop(1); return NULL; } /* Checkpoints reports thread */ static void *checkpoints_thread_proc(void *arg) { unsigned long long next_ns; unsigned long long curr_ns; unsigned int i; (void)arg; /* unused */ sb_tls_thread_id = SB_BACKGROUND_THREAD_ID; /* Initialize thread-local RNG state */ sb_rand_thread_init(); if (sb_lua_loaded() && sb_lua_report_thread_init()) return NULL; pthread_cleanup_push(sb_lua_report_thread_done, NULL); log_text(LOG_DEBUG, "Checkpoints report thread started"); /* Wait for the signal from the main thread to start reporting */ if (sb_barrier_wait(&report_barrier) < 0) return NULL; checkpoints_thread_created = 1; for (i = 0; i < sb_globals.n_checkpoints; i++) { next_ns = SEC2NS(sb_globals.checkpoints[i]); curr_ns = sb_timer_value(&sb_exec_timer); if (next_ns <= curr_ns) continue; sb_nanosleep(next_ns - curr_ns); log_timestamp(LOG_NOTICE, NS2SEC(sb_timer_value(&sb_exec_timer)), "Checkpoint report:"); report_cumulative(); } pthread_cleanup_pop(1); return NULL; } /* Callback to start timers when all threads are ready */ static int threads_started_callback(void *arg) { (void) arg; /* unused */ /* Report initialization errors to the main thread */ if (sb_globals.error) return 1; sb_globals.threads_running = sb_globals.threads; sb_timer_start(&sb_exec_timer); sb_timer_copy(&sb_intermediate_timer, &sb_exec_timer); sb_timer_copy(&sb_checkpoint_timer, &sb_exec_timer); log_text(LOG_NOTICE, "Threads started!\n"); return 0; } /* Main test function: start threads, wait for them to finish and measure time. */ static int run_test(sb_test_t *test) { int err; pthread_t report_thread; pthread_t checkpoints_thread; pthread_t eventgen_thread; unsigned int barrier_threads; uint64_t old_max_events = 0; /* initialize test */ if (test->ops.init != NULL && test->ops.init() != 0) return 1; /* print test mode */ print_run_mode(test); /* initialize timers */ sb_timer_init(&sb_exec_timer); sb_timer_init(&sb_intermediate_timer); sb_timer_init(&sb_checkpoint_timer); /* prepare test */ if (test->ops.prepare != NULL && test->ops.prepare() != 0) return 1; pthread_mutex_init(&sb_globals.exec_mutex, NULL); sb_globals.threads_running = 0; /* Calculate the required number of threads for the worker start barrier */ barrier_threads = 1 /* main thread */ + sb_globals.threads + (sb_globals.tx_rate > 0) /* event generation thread */; if (sb_barrier_init(&worker_barrier, barrier_threads, threads_started_callback, NULL)) { log_errno(LOG_FATAL, "sb_barrier_init() failed"); return 1; } /* Calculate the required number of threads for the report start barrier */ barrier_threads = 1 /* main thread */ + (sb_globals.report_interval > 0) /* intermediate reports thread */ + (sb_globals.n_checkpoints > 0) /* checkpoint reports thread */; if (sb_barrier_init(&report_barrier, barrier_threads, NULL, NULL)) { log_errno(LOG_FATAL, "sb_barrier_init() failed"); return 1; } if (sb_globals.report_interval > 0) { /* Create a thread for intermediate statistic reports */ if ((err = sb_thread_create(&report_thread, &sb_thread_attr, &report_thread_proc, NULL)) != 0) { log_errno(LOG_FATAL, "sb_thread_create() for the reporting thread failed."); return 1; } } if (sb_globals.tx_rate > 0) { if ((err = sb_thread_create(&eventgen_thread, &sb_thread_attr, &eventgen_thread_proc, NULL)) != 0) { log_errno(LOG_FATAL, "sb_thread_create() for the reporting thread failed."); return 1; } } if (sb_globals.n_checkpoints > 0) { /* Create a thread for checkpoint statistic reports */ if ((err = sb_thread_create(&checkpoints_thread, &sb_thread_attr, &checkpoints_thread_proc, NULL)) != 0) { log_errno(LOG_FATAL, "sb_thread_create() for the checkpoint thread failed."); return 1; } } if ((err = sb_thread_create_workers(&worker_thread))) return err; #ifdef HAVE_ALARM /* Exit with an error if thread initialization timeout expires */ signal(SIGALRM, sigalrm_thread_init_timeout_handler); alarm(thread_init_timeout); #endif if (sb_globals.warmup_time > 0) { /* Disable the max_events limit for the warmup stage */ old_max_events = sb_globals.max_events; sb_globals.max_events = 0; } if (sb_barrier_wait(&worker_barrier) < 0) { log_text(LOG_FATAL, "Threads initialization failed!"); return 1; } #ifdef HAVE_ALARM alarm(0); if (sb_globals.force_shutdown) { /* Set the alarm to force shutdown */ signal(SIGALRM, sigalrm_forced_shutdown_handler); alarm(NS2SEC(sb_globals.max_time_ns) + sb_globals.timeout); } #endif if (sb_globals.warmup_time > 0) { log_text(LOG_NOTICE, "Warming up for %d seconds...\n", sb_globals.warmup_time); usleep(sb_globals.warmup_time * 1000000); /* Re-enable the max_events limit, if it was set */ ck_pr_store_64(&sb_globals.max_events, old_max_events); /* Perform a checkpoint to reset previously collected stats */ sb_stat_t stat; checkpoint(&stat); } /* Signal the report threads to start reporting */ if (sb_barrier_wait(&report_barrier) < 0) { log_text(LOG_FATAL, "Failed to signal reporting threads"); return 1; } if ((err = sb_thread_join_workers())) return err; sb_timer_stop(&sb_exec_timer); sb_timer_stop(&sb_intermediate_timer); sb_timer_stop(&sb_checkpoint_timer); /* Silence periodic reports if they were on */ ck_pr_store_uint(&sb_globals.report_interval, 0); #ifdef HAVE_ALARM alarm(0); #endif log_text(LOG_INFO, "Done.\n"); /* cleanup test */ if (test->ops.cleanup != NULL && test->ops.cleanup() != 0) return 1; if (report_thread_created) { if (sb_thread_cancel(report_thread) || sb_thread_join(report_thread, NULL)) log_errno(LOG_FATAL, "Terminating the reporting thread failed."); } if (eventgen_thread_created) { /* When a time limit is used, the event generation thread may terminate itself. */ if ((sb_thread_cancel(eventgen_thread) || sb_thread_join(eventgen_thread, NULL)) && sb_globals.max_time_ns == 0) log_text(LOG_FATAL, "Terminating the event generator thread failed."); } if (checkpoints_thread_created) { if (sb_thread_cancel(checkpoints_thread) || sb_thread_join(checkpoints_thread, NULL)) log_errno(LOG_FATAL, "Terminating the checkpoint thread failed."); } /* print test-specific stats */ if (!sb_globals.error) { if (sb_globals.histogram) { log_text(LOG_NOTICE, "Latency histogram (values are in milliseconds)"); sb_histogram_print(&sb_latency_histogram); log_text(LOG_NOTICE, " "); } report_cumulative(); } pthread_mutex_destroy(&sb_globals.exec_mutex); /* finalize test */ if (test->ops.done != NULL) (*(test->ops.done))(); return sb_globals.error != 0; } static sb_test_t *find_test(const char *name) { sb_list_item_t *pos; sb_test_t *test; SB_LIST_FOR_EACH(pos, &tests) { test = SB_LIST_ENTRY(pos, sb_test_t, listitem); if (!strcmp(test->sname, name)) return test; } return NULL; } static int checkpoint_cmp(const void *a_ptr, const void *b_ptr) { const unsigned int a = *(const unsigned int *) a_ptr; const unsigned int b = *(const unsigned int *) b_ptr; return (int) (a - b); } static int init(void) { option_t *opt; char *tmp; sb_list_t *checkpoints_list; sb_list_item_t *pos_val; value_t *val; sb_globals.threads = sb_get_value_int("threads"); thread_init_timeout = sb_get_value_int("thread-init-timeout"); if (sb_globals.threads <= 0) { log_text(LOG_FATAL, "Invalid value for --threads: %d.\n", sb_globals.threads); return 1; } sb_globals.max_events = sb_get_value_int("events"); sb_globals.warmup_time = sb_get_value_int("warmup-time"); if (sb_globals.warmup_time < 0) { log_text(LOG_FATAL, "Invalid value for --warmup-time: %d.\n", sb_globals.warmup_time); return 1; } int max_time = sb_get_value_int("time"); sb_globals.max_time_ns = SEC2NS(max_time); if (!sb_globals.max_events && !sb_globals.max_time_ns) log_text(LOG_WARNING, "Both event and time limits are disabled, " "running an endless test"); if (sb_globals.max_time_ns > 0) { /* Adjust the time limit if warmup time has been requested */ if (sb_globals.warmup_time > 0) { sb_globals.max_time_ns += SEC2NS(sb_globals.warmup_time); } /* Parse the --forced-shutdown value */ tmp = sb_get_value_string("forced-shutdown"); if (tmp == NULL) { sb_globals.force_shutdown = 1; sb_globals.timeout = NS2SEC(sb_globals.max_time_ns) / 20; } else if (strcasecmp(tmp, "off")) { char *endptr; sb_globals.force_shutdown = 1; sb_globals.timeout = (unsigned) strtol(tmp, &endptr, 10); if (*endptr == '%') sb_globals.timeout = (unsigned) (sb_globals.timeout * NS2SEC(sb_globals.max_time_ns) / 100); else if (*tmp == '\0' || *endptr != '\0') { log_text(LOG_FATAL, "Invalid value for --forced-shutdown: '%s'", tmp); return 1; } } else sb_globals.force_shutdown = 0; } int err; if ((err = sb_thread_init())) return err; sb_globals.debug = sb_get_value_flag("debug"); /* Automatically set logger verbosity to 'debug' */ if (sb_globals.debug) { opt = sb_find_option("verbosity"); if (opt != NULL) set_option(opt->name, "5", opt->type); } sb_globals.validate = sb_get_value_flag("validate"); if (sb_rand_init()) { return 1; } sb_globals.tx_rate = sb_get_value_int("rate"); sb_globals.report_interval = sb_get_value_int("report-interval"); sb_globals.n_checkpoints = 0; checkpoints_list = sb_get_value_list("report-checkpoints"); SB_LIST_FOR_EACH(pos_val, checkpoints_list) { char *endptr; long res; val = SB_LIST_ENTRY(pos_val, value_t, listitem); res = strtol(val->data, &endptr, 10); if (*endptr != '\0' || res < 0 || res > INT_MAX) { log_text(LOG_FATAL, "Invalid value for --report-checkpoints: '%s'", val->data); return 1; } if (++sb_globals.n_checkpoints > MAX_CHECKPOINTS) { log_text(LOG_FATAL, "Too many checkpoints in --report-checkpoints " "(up to %d can be defined)", MAX_CHECKPOINTS); return 1; } sb_globals.checkpoints[sb_globals.n_checkpoints-1] = (unsigned int) res; } if (sb_globals.n_checkpoints > 0) { qsort(sb_globals.checkpoints, sb_globals.n_checkpoints, sizeof(unsigned int), checkpoint_cmp); } /* Initialize timers */ timers = sb_alloc_per_thread_array(sizeof(sb_timer_t)); timers_copy = sb_alloc_per_thread_array(sizeof(sb_timer_t)); if (timers == NULL || timers_copy == NULL) { log_text(LOG_FATAL, "Memory allocation failure"); return 1; } for (unsigned i = 0; i < sb_globals.threads; i++) sb_timer_init(&timers[i]); /* LuaJIT commands */ sb_globals.luajit_cmd = sb_get_value_string("luajit-cmd"); return 0; } int main(int argc, char *argv[]) { sb_test_t *test = NULL; int rc; sb_globals.argc = argc; sb_globals.argv = malloc(argc * sizeof(char *)); memcpy(sb_globals.argv, argv, argc * sizeof(char *)); /* Initialize options library */ sb_options_init(); /* First register the logger */ if (log_register()) return EXIT_FAILURE; /* Register available tests */ if (register_tests()) { fprintf(stderr, "Failed to register tests.\n"); return EXIT_FAILURE; } /* Parse command line arguments */ if (parse_general_arguments(argc, argv)) return EXIT_FAILURE; if (sb_get_value_flag("help")) { print_help(); return EXIT_SUCCESS; } if (sb_get_value_flag("version")) { printf("%s\n", VERSION_STRING); return EXIT_SUCCESS; } /* Initialize global variables and logger */ if (init() || log_init() || sb_counters_init()) return EXIT_FAILURE; print_header(); if (sb_globals.testname != NULL && strcmp(sb_globals.testname, "-")) { /* Is it a built-in test name? */ test = find_test(sb_globals.testname); if (test != NULL && sb_globals.cmdname == NULL) { /* Command is a mandatory argument for built-in tests */ fprintf(stderr, "The '%s' test requires a command argument. " "See 'sysbench %s help'\n", test->sname, test->sname); return EXIT_FAILURE; } if (test == NULL) { if ((test = sb_load_lua(sb_globals.testname)) == NULL) return EXIT_FAILURE; if (sb_globals.cmdname == NULL) { /* No command specified, there's nothing more todo */ return test != NULL ? EXIT_SUCCESS: EXIT_FAILURE; } } } else { sb_globals.testname = NULL; if (SB_ISATTY()) log_text(LOG_NOTICE, "Reading the script from the standard input:\n"); test = sb_load_lua(NULL); return test != NULL ? EXIT_SUCCESS : EXIT_FAILURE; } current_test = test; /* Load and parse test-specific options */ if (parse_test_arguments(test, argc, argv)) return EXIT_FAILURE; if (sb_lua_loaded() && sb_lua_custom_command_defined(sb_globals.cmdname)) { rc = sb_lua_call_custom_command(sb_globals.cmdname); } else if (!strcmp(sb_globals.cmdname, "help")) { if (test->builtin_cmds.help != NULL) { test->builtin_cmds.help(); rc = EXIT_SUCCESS; goto end; } else if (test->args != NULL) { printf("%s options:\n", test->sname); sb_print_test_options(); rc = EXIT_SUCCESS; goto end; } /* We don't know want to print as help text, let the user know */ fprintf(stderr, "'%s' test does not implement the 'help' command.\n", test->sname); return EXIT_FAILURE; } else if (!strcmp(sb_globals.cmdname, "prepare")) { if (test->builtin_cmds.prepare == NULL) { fprintf(stderr, "'%s' test does not implement the 'prepare' command.\n", test->sname); rc = EXIT_FAILURE; goto end; } rc = test->builtin_cmds.prepare(); } else if (!strcmp(sb_globals.cmdname, "cleanup")) { if (test->builtin_cmds.cleanup == NULL) { fprintf(stderr, "'%s' test does not implement the 'cleanup' command.\n", test->sname); rc = EXIT_FAILURE; goto end; } rc = test->builtin_cmds.cleanup(); } else if (!strcmp(sb_globals.cmdname, "run")) { rc = run_test(test) ? EXIT_FAILURE : EXIT_SUCCESS; } else { fprintf(stderr, "Unknown command: %s\n", sb_globals.cmdname); rc = EXIT_FAILURE; } end: if (sb_lua_loaded()) sb_lua_done(); db_done(); sb_counters_done(); log_done(); sb_options_done(); sb_rand_done(); sb_thread_done(); free(timers); free(timers_copy); free(sb_globals.argv); return rc; } /* Print a description of available command line options for the current test */ void sb_print_test_options(void) { if (current_test != NULL) sb_print_options(current_test->args); } /* Allocate an array of objects of the specified size for all threads, both worker and background ones. */ void *sb_alloc_per_thread_array(size_t size) { /* We want to exclude queries executed by background threads from statistics generated for worker threads. To simplify code, we allocate all timers and counters for all worker threads + possible background threads created by sysbench for statistic reports, etc. When executing requests from background threads, extra array slots will be used (it depends on the assigned ID for each thread). When aggregating counters and timers, we only consider slots in the range [0, sb_globals.threads - 1], i.e. ignore statistics generated by background threads. Currently we assign the same single thread ID for all background threads, so they also share the same single slot in each allocated array. */ const size_t bsize = (sb_globals.threads + 1) * size; void *ptr = sb_memalign(bsize, CK_MD_CACHELINE); memset(ptr, 0, bsize); return ptr; } ================================================ FILE: src/sysbench.h ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2017 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SYSBENCH_H #define SYSBENCH_H #ifdef STDC_HEADERS # include # include # include # include #endif #ifdef HAVE_UNISTD_H # include # include #endif #ifdef HAVE_PTHREAD_H # include #endif #include "sb_list.h" #include "sb_options.h" #include "sb_timer.h" #include "sb_logger.h" #include "tests/sb_cpu.h" #include "tests/sb_fileio.h" #include "tests/sb_memory.h" #include "tests/sb_threads.h" #include "tests/sb_mutex.h" /* Macros to control global execution mutex */ #define SB_THREAD_MUTEX_LOCK() pthread_mutex_lock(&sb_globals.exec_mutex) #define SB_THREAD_MUTEX_UNLOCK() pthread_mutex_unlock(&sb_globals.exec_mutex) /* Maximum number of elements in --report-checkpoints list */ #define MAX_CHECKPOINTS 256 /* Request types definition */ typedef enum { SB_REQ_TYPE_NULL, SB_REQ_TYPE_CPU, SB_REQ_TYPE_MEMORY, SB_REQ_TYPE_FILE, SB_REQ_TYPE_SQL, SB_REQ_TYPE_THREADS, SB_REQ_TYPE_MUTEX, SB_REQ_TYPE_SCRIPT } sb_event_type_t; /* Request structure definition */ struct sb_test; /* Forward declaration */ typedef struct { int type; struct sb_test_t *test; /* type-specific data */ union { sb_file_request_t file_request; sb_threads_request_t threads_request; sb_mutex_request_t mutex_request; } u; } sb_event_t; /* Statistics */ typedef struct { uint32_t threads_running; /* Number of active threads */ double time_interval; /* Time elapsed since the last report */ double time_total; /* Time elapsed since the benchmark start */ double latency_pct; /* Latency percentile */ double latency_min; /* Minimum latency (cumulative reports only) */ double latency_max; /* Maximum latency (cumulative reports only) */ double latency_avg; /* Average latency (cumulative reports only) */ double latency_sum; /* Sum latency (cumulative reports only) */ uint64_t events; /* Number of executed events */ uint64_t reads; /* Number of read operations */ uint64_t writes; /* Number of write operations */ uint64_t other; /* Number of other operations */ uint64_t errors; /* Number of ignored errors */ uint64_t reconnects; /* Number of reconnects to server */ uint64_t bytes_read; /* Bytes read */ uint64_t bytes_written; /* Bytes written */ uint64_t queue_length; /* Event queue length (tx_rate-only) */ uint64_t concurrency; /* Number of in-flight events (tx_rate-only) */ } sb_stat_t; /* Commands */ typedef int sb_builtin_cmd_func_t(void); typedef int sb_custom_cmd_func_t(int); /* Test operations definition */ typedef int sb_op_init(void); typedef int sb_op_prepare(void); typedef int sb_op_thread_init(int); typedef int sb_op_thread_run(int); typedef void sb_op_print_mode(void); typedef sb_event_t sb_op_next_event(int); typedef int sb_op_execute_event(sb_event_t *, int); typedef void sb_op_report(sb_stat_t *); typedef int sb_op_thread_done(int); typedef int sb_op_cleanup(void); typedef int sb_op_done(void); /* Test commands structure definitions */ typedef struct { sb_builtin_cmd_func_t *help; /* print help */ sb_builtin_cmd_func_t *prepare; /* prepare for the test */ sb_builtin_cmd_func_t *run; /* run the test */ sb_builtin_cmd_func_t *cleanup; /* cleanup the test database, files, etc. */ } sb_builtin_cmds_t; /* Test operations structure definition */ typedef struct { sb_op_init *init; /* initialization function */ sb_op_prepare *prepare; /* called after timers start, but before thread execution */ sb_op_thread_init *thread_init; /* thread initialization (called when each thread starts) */ sb_op_print_mode *print_mode; /* print mode function */ sb_op_next_event *next_event; /* event generation function */ sb_op_execute_event *execute_event; /* event execution function */ sb_op_report *report_intermediate; /* intermediate reports handler */ sb_op_report *report_cumulative; /* cumulative reports handler */ sb_op_thread_run *thread_run; /* main thread loop */ sb_op_thread_done *thread_done; /* thread finalize function */ sb_op_cleanup *cleanup; /* called after exit from thread, but before timers stop */ sb_op_done *done; /* finalize function */ } sb_operations_t; /* Test structure definition */ typedef struct sb_test { const char *sname; const char *lname; sb_operations_t ops; sb_builtin_cmds_t builtin_cmds; sb_arg_t *args; sb_list_item_t listitem; } sb_test_t; /* sysbench global variables */ typedef struct { int error CK_CC_CACHELINE; /* global error flag */ int argc; /* command line arguments count */ char **argv; /* command line arguments */ unsigned int tx_rate; /* target transaction rate */ uint64_t max_events; /* maximum number of events to execute */ uint64_t max_time_ns; /* total execution time limit */ pthread_mutex_t exec_mutex CK_CC_CACHELINE; /* execution mutex */ const char *testname; /* test name or script path to execute */ const char *cmdname; /* command passed from command line */ unsigned int threads CK_CC_CACHELINE; /* number of threads to use */ unsigned int threads_running; /* number of threads currently active */ unsigned int report_interval; /* intermediate reports interval */ unsigned int percentile; /* percentile rank for latency stats */ unsigned int histogram; /* show histogram in latency stats */ /* array of report checkpoints */ unsigned int checkpoints[MAX_CHECKPOINTS]; unsigned int n_checkpoints; /* number of checkpoints */ unsigned char debug; /* debug flag */ unsigned int timeout; /* forced shutdown timeout */ unsigned char validate; /* validation flag */ unsigned char verbosity CK_CC_CACHELINE; /* log verbosity */ int concurrency CK_CC_CACHELINE; /* number of concurrent requests when tx-rate is used */ int force_shutdown CK_CC_CACHELINE; /* whether we must force test shutdown */ int forced_shutdown_in_progress; int warmup_time; /* warmup time */ uint64_t nevents CK_CC_CACHELINE; /* event counter */ const char *luajit_cmd; /* LuaJIT command */ } sb_globals_t; extern sb_globals_t sb_globals CK_CC_CACHELINE; extern pthread_mutex_t event_queue_mutex CK_CC_CACHELINE; /* Global execution timer */ extern sb_timer_t sb_exec_timer CK_CC_CACHELINE; /* timers for checkpoint reports */ extern sb_timer_t sb_intermediate_timer; extern sb_timer_t sb_checkpoint_timer; extern TLS int sb_tls_thread_id; bool sb_more_events(int thread_id); sb_event_t sb_next_event(sb_test_t *test, int thread_id); void sb_event_start(int thread_id); void sb_event_stop(int thread_id); /* Print a description of available command line options for the current test */ void sb_print_test_options(void); /* Default intermediate reports handler */ void sb_report_intermediate(sb_stat_t *stat); /* Default cumulative reports handler */ void sb_report_cumulative(sb_stat_t *stat); /* Allocate an array of objects of the specified size for all threads, both worker and background ones. */ void *sb_alloc_per_thread_array(size_t size); #endif ================================================ FILE: src/tests/Makefile.am ================================================ # Copyright (C) 2004 MySQL AB # Copyright (C) 2004-2008 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA SUBDIRS = cpu fileio memory threads mutex ================================================ FILE: src/tests/cpu/Makefile.am ================================================ # Copyright (C) 2004 MySQL AB # Copyright (C) 2004-2008 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA noinst_LIBRARIES = libsbcpu.a libsbcpu_a_SOURCES = sb_cpu.c ../sb_cpu.h libsbcpu_a_CPPFLAGS = $(AM_CPPFLAGS) ================================================ FILE: src/tests/cpu/sb_cpu.c ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_MATH_H # include #endif #include #include "sysbench.h" /* CPU test arguments */ static sb_arg_t cpu_args[] = { SB_OPT("cpu-max-prime", "upper limit for primes generator", "10000", INT), SB_OPT_END }; /* CPU test operations */ static int cpu_init(void); static void cpu_print_mode(void); static sb_event_t cpu_next_event(int thread_id); static int cpu_execute_event(sb_event_t *, int); static void cpu_report_cumulative(sb_stat_t *); static int cpu_done(void); static sb_test_t cpu_test = { .sname = "cpu", .lname = "CPU performance test", .ops = { .init = cpu_init, .print_mode = cpu_print_mode, .next_event = cpu_next_event, .execute_event = cpu_execute_event, .report_cumulative = cpu_report_cumulative, .done = cpu_done }, .args = cpu_args }; /* Upper limit for primes */ static unsigned int max_prime; int register_test_cpu(sb_list_t * tests) { SB_LIST_ADD_TAIL(&cpu_test.listitem, tests); return 0; } int cpu_init(void) { int prime_option= sb_get_value_int("cpu-max-prime"); if (prime_option <= 0) { log_text(LOG_FATAL, "Invalid value of cpu-max-prime: %d.", prime_option); return 1; } max_prime= (unsigned int)prime_option; return 0; } sb_event_t cpu_next_event(int thread_id) { sb_event_t req; (void) thread_id; /* unused */ req.type = SB_REQ_TYPE_CPU; return req; } int cpu_execute_event(sb_event_t *r, int thread_id) { unsigned long long c; unsigned long long l; double t; unsigned long long n=0; (void)thread_id; /* unused */ (void)r; /* unused */ /* So far we're using very simple test prime number tests in 64bit */ for(c=3; c < max_prime; c++) { t = sqrt((double)c); for(l = 2; l <= t; l++) if (c % l == 0) break; if (l > t ) n++; } return 0; } void cpu_print_mode(void) { log_text(LOG_INFO, "Doing CPU performance benchmark\n"); log_text(LOG_NOTICE, "Prime numbers limit: %d\n", max_prime); } /* Print cumulative stats. */ void cpu_report_cumulative(sb_stat_t *stat) { log_text(LOG_NOTICE, "CPU speed:"); log_text(LOG_NOTICE, " events per second: %8.2f", stat->events / stat->time_interval); sb_report_cumulative(stat); } int cpu_done(void) { return 0; } ================================================ FILE: src/tests/fileio/Makefile.am ================================================ # Copyright (C) 2004 MySQL AB # Copyright (C) 2004-2008 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA noinst_LIBRARIES = libsbfileio.a libsbfileio_a_SOURCES = sb_fileio.c ../sb_fileio.h crc32.c crc32.h crc32tbl.h libsbfileio_a_CPPFLAGS = $(AM_CPPFLAGS) ================================================ FILE: src/tests/fileio/crc32.c ================================================ /* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2003 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown for his contribution of faster * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing * tables for updating the shift register in one step with three exclusive-ors * instead of four steps with four exclusive-ors. This results about a factor * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* @(#) $Id$ */ #ifdef MAKECRCH # include # ifndef DYNAMIC_CRC_TABLE # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ #define local static #define STDC #define FAR #define ZEXPORT #define Z_NULL 0 #define OF(args) args #include "crc32.h" #ifndef _WIN32 #define ptrdiff_t long #else #include #endif /* Find a four-byte integer type for crc32_little() and crc32_big(). */ #ifndef NOBYFOUR # ifdef STDC /* need ANSI C limits.h to determine sizes */ # include # define BYFOUR # if (UINT_MAX == 0xffffffffUL) typedef unsigned int u4; # else # if (ULONG_MAX == 0xffffffffUL) typedef unsigned long u4; # else # if (USHRT_MAX == 0xffffffffUL) typedef unsigned short u4; # else # undef BYFOUR /* can't find a four-byte integer type! */ # endif # endif # endif # endif /* STDC */ #endif /* !NOBYFOUR */ /* Definitions for doing the crc four data bytes at a time. */ #ifdef BYFOUR # define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ (((w)&0xff00)<<8)+(((w)&0xff)<<24)) local unsigned long crc32_little OF((unsigned long, const unsigned char FAR *, unsigned)); local unsigned long crc32_big OF((unsigned long, const unsigned char FAR *, unsigned)); # define TBLS 8 #else # define TBLS 1 #endif /* BYFOUR */ #ifdef DYNAMIC_CRC_TABLE local int crc_table_empty = 1; local unsigned long FAR crc_table[TBLS][256]; local void make_crc_table OF((void)); #ifdef MAKECRCH local void write_table OF((FILE *, const unsigned long FAR *)); #endif /* MAKECRCH */ /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x (which is shifting right by one and adding x^32 mod p if the bit shifted out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. The first table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. The remaining tables allow for word-at-a-time CRC calculation for both big-endian and little- endian machines, where a word is four bytes. */ local void make_crc_table() { unsigned long c; int n, k; unsigned long poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* make exclusive-or pattern from polynomial (0xedb88320UL) */ poly = 0UL; for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) poly |= 1UL << (31 - p[n]); /* generate a crc for every 8-bit value */ for (n = 0; n < 256; n++) { c = (unsigned long)n; for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1; crc_table[0][n] = c; } #ifdef BYFOUR /* generate crc for each value followed by one, two, and three zeros, and then the byte reversal of those as well as the first table */ for (n = 0; n < 256; n++) { c = crc_table[0][n]; crc_table[4][n] = REV(c); for (k = 1; k < 4; k++) { c = crc_table[0][c & 0xff] ^ (c >> 8); crc_table[k][n] = c; crc_table[k + 4][n] = REV(c); } } #endif /* BYFOUR */ crc_table_empty = 0; #ifdef MAKECRCH /* write out CRC tables to crc32.h */ { FILE *out; out = fopen("crc32.h", "w"); if (out == NULL) return; fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); fprintf(out, "local const unsigned long FAR "); fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); write_table(out, crc_table[0]); # ifdef BYFOUR fprintf(out, "#ifdef BYFOUR\n"); for (k = 1; k < 8; k++) { fprintf(out, " },\n {\n"); write_table(out, crc_table[k]); } fprintf(out, "#endif\n"); # endif /* BYFOUR */ fprintf(out, " }\n};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH local void write_table(out, table) FILE *out; const unsigned long FAR *table; { int n; for (n = 0; n < 256; n++) fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); } #endif /* MAKECRCH */ #else /* !DYNAMIC_CRC_TABLE */ /* ======================================================================== * Tables of CRC-32s of all single-byte values, made by make_crc_table(). */ #include "crc32tbl.h" #endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= */ #define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 /* ========================================================================= */ unsigned long ZEXPORT crc32(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; unsigned len; { if (buf == Z_NULL) return 0UL; #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ #ifdef BYFOUR if (sizeof(void *) == sizeof(ptrdiff_t)) { u4 endian; endian = 1; if (*((unsigned char *)(&endian))) return crc32_little(crc, buf, len); else return crc32_big(crc, buf, len); } #endif /* BYFOUR */ crc = crc ^ 0xffffffffUL; while (len >= 8) { DO8; len -= 8; } if (len) do { DO1; } while (--len); return crc ^ 0xffffffffUL; } #ifdef BYFOUR /* ========================================================================= */ #define DOLIT4 c ^= *buf4++; \ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 /* ========================================================================= */ local unsigned long crc32_little(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; unsigned len; { register u4 c; register const u4 FAR *buf4; c = (u4)crc; c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } buf4 = (const u4 FAR *)(void *)buf; while (len >= 32) { DOLIT32; len -= 32; } while (len >= 4) { DOLIT4; len -= 4; } buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); } while (--len); c = ~c; return (unsigned long)c; } /* ========================================================================= */ #define DOBIG4 c ^= *++buf4; \ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 /* ========================================================================= */ local unsigned long crc32_big(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; unsigned len; { register u4 c; register const u4 FAR *buf4; c = REV((u4)crc); c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } buf4 = (const u4 FAR *)(void *)buf; buf4--; while (len >= 32) { DOBIG32; len -= 32; } while (len >= 4) { DOBIG4; len -= 4; } buf4++; buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); } while (--len); c = ~c; return (unsigned long)(REV(c)); } #endif /* BYFOUR */ ================================================ FILE: src/tests/fileio/crc32.h ================================================ #ifndef CRC32_H #ifdef HAVE_CONFIG_H #include #endif #define CRC32_H extern unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned len); #endif ================================================ FILE: src/tests/fileio/crc32tbl.h ================================================ /* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ local const unsigned long FAR crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL #ifdef BYFOUR }, { 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, 0x9324fd72UL }, { 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, 0xbe9834edUL }, { 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, 0xde0506f1UL }, { 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, 0x8def022dUL }, { 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, 0x72fd2493UL }, { 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, 0xed3498beUL }, { 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, 0xf10605deUL #endif } }; ================================================ FILE: src/tests/fileio/sb_fileio.c ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef STDC_HEADERS # include # include # include #endif #ifdef HAVE_UNISTD_H # include # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_ERRNO_H # include #endif #ifdef HAVE_LIBAIO # include #endif #ifdef HAVE_SYS_MMAN_H # include #endif #include "sysbench.h" #include "crc32.h" #include "sb_histogram.h" #include "sb_rand.h" #include "sb_util.h" #include "sb_counter.h" /* Lengths of the checksum and the offset fields in a block */ #define FILE_CHECKSUM_LENGTH sizeof(int) #define FILE_OFFSET_LENGTH sizeof(long) typedef int FILE_DESCRIPTOR; #define VALID_FILE(fd) (fd >= 0) #define SB_INVALID_FILE (-1) #define FD_FMT "%d" /* Supported operations in request */ typedef enum { MODE_READ, MODE_WRITE, MODE_REWRITE, MODE_RND_READ, MODE_RND_WRITE, MODE_RND_RW, MODE_MIXED } file_test_mode_t; /* fsync modes */ typedef enum { FSYNC_ALL, FSYNC_DATA } file_fsync_mode_t; /* File I/O modes */ typedef enum { FILE_IO_MODE_SYNC, FILE_IO_MODE_ASYNC, FILE_IO_MODE_MMAP } file_io_mode_t; typedef enum { SB_FILE_FLAG_SYNC = 1, SB_FILE_FLAG_DSYNC = 2, SB_FILE_FLAG_DIRECTIO = 4 } file_flags_t; #ifdef HAVE_LIBAIO /* Per-thread async I/O context */ typedef struct { io_context_t io_ctxt; /* AIO context */ unsigned int nrequests; /* Current number of queued I/O requests */ struct io_event *events; /* Array of events */ } sb_aio_context_t; /* Async I/O operation */ typedef struct { struct iocb iocb; sb_file_op_t type; ssize_t len; } sb_aio_oper_t; static sb_aio_context_t *aio_ctxts; #endif typedef struct { void *buffer; unsigned int buffer_file_id; long long buffer_pos; } sb_per_thread_t; static sb_per_thread_t *per_thread; /* Test options */ static unsigned int num_files; static long long total_size; static long long file_size; static int file_block_size; static file_flags_t file_extra_flags; static int file_fsync_freq; static int file_fsync_all; static int file_fsync_end; static file_fsync_mode_t file_fsync_mode; static double file_rw_ratio; static int file_merged_requests; static long long file_request_size; static file_io_mode_t file_io_mode; #ifdef HAVE_LIBAIO static unsigned int file_async_backlog; #endif /* statistical and other "local" variables */ static long long position; /* current position in file */ static unsigned int current_file; /* current file */ static unsigned int fsynced_file; /* file number to be fsynced (periodic) */ static int is_dirty; /* any writes after last fsync series ? */ static unsigned int req_performed; /* number of requests done */ static const double mebibyte = 1024 * 1024; static const double megabyte = 1000 * 1000; #ifdef HAVE_MMAP /* Array of file mappings */ static void **mmaps; static unsigned long file_page_mask; #endif /* Array of file descriptors */ static FILE_DESCRIPTOR *files; /* test mode type */ static file_test_mode_t test_mode; /* Previous request needed for validation */ static sb_file_request_t prev_req; static sb_arg_t fileio_args[] = { SB_OPT("file-num", "number of files to create", "128", INT), SB_OPT("file-block-size", "block size to use in all IO operations", "16384", INT), SB_OPT("file-total-size", "total size of files to create", "2G", SIZE), SB_OPT("file-test-mode", "test mode {seqwr, seqrewr, seqrd, rndrd, rndwr, rndrw}", NULL, STRING), SB_OPT("file-io-mode", "file operations mode {sync,async,mmap}", "sync", STRING), #ifdef HAVE_LIBAIO SB_OPT("file-async-backlog", "number of asynchronous operatons to queue per thread", "128", INT), #endif SB_OPT("file-extra-flags", "list of additional flags to use to open files {sync,dsync,direct}", "", LIST), SB_OPT("file-fsync-freq", "do fsync() after this number of requests " "(0 - don't use fsync())", "100", INT), SB_OPT("file-fsync-all", "do fsync() after each write operation", "off", BOOL), SB_OPT("file-fsync-end", "do fsync() at the end of test", "on", BOOL), SB_OPT("file-fsync-mode", "which method to use for synchronization {fsync, fdatasync}", "fsync", STRING), SB_OPT("file-merged-requests", "merge at most this number of IO requests " "if possible (0 - don't merge)", "0", INT), SB_OPT("file-rw-ratio", "reads/writes ratio for combined test", "1.5", DOUBLE), SB_OPT_END }; /* fileio test commands */ static int file_cmd_prepare(void); static int file_cmd_cleanup(void); /* fileio test operations */ static int file_init(void); static void file_print_mode(void); static int file_prepare(void); static sb_event_t file_next_event(int thread_id); static int file_execute_event(sb_event_t *, int); static int file_thread_done(int); static int file_done(void); static void file_report_intermediate(sb_stat_t *); static void file_report_cumulative(sb_stat_t *); static sb_test_t fileio_test = { .sname = "fileio", .lname = "File I/O test", .ops = { .init = file_init, .prepare = file_prepare, .print_mode = file_print_mode, .next_event = file_next_event, .execute_event = file_execute_event, .report_intermediate = file_report_intermediate, .report_cumulative = file_report_cumulative, .thread_done = file_thread_done, .done = file_done }, .builtin_cmds = { .prepare = file_cmd_prepare, .cleanup = file_cmd_cleanup }, .args = fileio_args }; static int create_files(void); static int remove_files(void); static int parse_arguments(void); static void init_vars(void); static sb_event_t file_get_seq_request(void); static sb_event_t file_get_rnd_request(int thread_id); static void check_seq_req(sb_file_request_t *, sb_file_request_t *); static const char *get_io_mode_str(file_io_mode_t mode); static const char *get_test_mode_str(file_test_mode_t mode); static void file_fill_buffer(unsigned char *, unsigned int, size_t); static int file_validate_buffer(unsigned char *, unsigned int, size_t); /* File operation wrappers */ static int file_do_fsync(unsigned int, int); static int file_fsync(unsigned int, int); static ssize_t file_pread(unsigned int, void *, ssize_t, long long, int); static ssize_t file_pwrite(unsigned int, void *, ssize_t, long long, int); #ifdef HAVE_LIBAIO static int file_async_init(void); static int file_async_done(void); static int file_submit_or_wait(struct iocb *, sb_file_op_t, ssize_t, int); static int file_wait(int, long); #endif #ifdef HAVE_MMAP static int file_mmap_prepare(void); static int file_mmap_done(void); #endif /* Portability wrappers */ static size_t sb_get_allocation_granularity(void); static void sb_free_memaligned(void *buf); static FILE_DESCRIPTOR sb_open(const char *); static int sb_create(const char *); int register_test_fileio(sb_list_t *tests) { SB_LIST_ADD_TAIL(&fileio_test.listitem, tests); return 0; } int file_init(void) { if (parse_arguments()) return 1; files = (FILE_DESCRIPTOR *)malloc(num_files * sizeof(FILE_DESCRIPTOR)); if (files == NULL) { log_text(LOG_FATAL, "Memory allocation failure."); return 1; } #ifdef HAVE_LIBAIO if (file_async_init()) return 1; #endif init_vars(); return 0; } int file_prepare(void) { unsigned int i; char file_name[512]; for (i=0; i < num_files; i++) { snprintf(file_name, sizeof(file_name), "test_file.%d",i); /* remove test files for creation test if they exist */ if (test_mode == MODE_WRITE) { unlink(file_name); if (sb_create(file_name)) { log_errno(LOG_FATAL, "Cannot create file '%s'", file_name); return 1; } } log_text(LOG_DEBUG, "Opening file: %s", file_name); files[i] = sb_open(file_name); if (!VALID_FILE(files[i])) { log_errno(LOG_FATAL, "Cannot open file '%s'", file_name); log_text(LOG_WARNING, "Did you forget to run the prepare step?"); return 1; } if (test_mode == MODE_WRITE) continue; /* Validate file size */ struct stat buf; if (fstat(files[i], &buf)) { log_errno(LOG_FATAL, "fstat() failed on file '%s'", file_name); return 1; } if (buf.st_size < file_size) { char ss1[16], ss2[16]; log_text(LOG_FATAL, "Size of file '%s' is %sB, but at least %sB is expected.", file_name, sb_print_value_size(ss1, sizeof(ss1), buf.st_size), sb_print_value_size(ss2, sizeof(ss2), file_size)); log_text(LOG_WARNING, "Did you run 'prepare' with different --file-total-size or " "--file-num values?"); return 1; } } #ifdef HAVE_MMAP if (file_mmap_prepare()) return 1; #endif return 0; } int file_done(void) { unsigned int i; for (i = 0; i < num_files; i++) close(files[i]); #ifdef HAVE_LIBAIO if (file_async_done()) return 1; #endif #ifdef HAVE_MMAP if (file_mmap_done()) return 1; #endif for (i = 0; i < sb_globals.threads; i++) { if (per_thread[i].buffer != NULL) sb_free_memaligned(per_thread[i].buffer); } free(per_thread); return 0; } sb_event_t file_next_event(int thread_id) { if (test_mode == MODE_WRITE || test_mode == MODE_REWRITE || test_mode == MODE_READ) return file_get_seq_request(); return file_get_rnd_request(thread_id); } /* Get sequential read or write request */ sb_event_t file_get_seq_request(void) { sb_event_t sb_req; sb_file_request_t *file_req = &sb_req.u.file_request; sb_req.type = SB_REQ_TYPE_FILE; SB_THREAD_MUTEX_LOCK(); /* assume function is called with correct mode always */ if (test_mode == MODE_WRITE || test_mode == MODE_REWRITE) file_req->operation = FILE_OP_TYPE_WRITE; else file_req->operation = FILE_OP_TYPE_READ; /* See whether it's time to fsync file(s) */ if (file_fsync_freq != 0 && file_req->operation == FILE_OP_TYPE_WRITE && is_dirty && req_performed % file_fsync_freq == 0) { file_req->operation = FILE_OP_TYPE_FSYNC; file_req->file_id = fsynced_file; file_req->pos = 0; file_req->size = 0; fsynced_file++; if (fsynced_file == num_files) { fsynced_file = 0; is_dirty = 0; } SB_THREAD_MUTEX_UNLOCK(); return sb_req; } req_performed++; if (file_req->operation == FILE_OP_TYPE_WRITE) is_dirty = 1; /* Rewind to the first file if all files are processed */ if (current_file == num_files) { position= 0; current_file= 0; } file_req->file_id = current_file; file_req->pos = position; file_req->size = SB_MIN(file_request_size, file_size - position); position += file_req->size; /* scroll to the next file if not already out of bound */ if (position == file_size) { current_file++; position=0; } if (sb_globals.validate) { check_seq_req(&prev_req, file_req); prev_req = *file_req; } SB_THREAD_MUTEX_UNLOCK(); return sb_req; } /* Request generatior for random tests */ sb_event_t file_get_rnd_request(int thread_id) { sb_event_t sb_req; sb_file_request_t *file_req = &sb_req.u.file_request; unsigned long long tmppos; int mode = test_mode; unsigned int i; sb_req.type = SB_REQ_TYPE_FILE; if (test_mode == MODE_RND_RW) { mode = (sb_counter_val(thread_id, SB_CNT_READ) + 1.0) / (sb_counter_val(thread_id, SB_CNT_WRITE) + 1.0) < file_rw_ratio ? MODE_RND_READ : MODE_RND_WRITE; } /* is_dirty is only set if writes are done and cleared after all files are synced */ if (file_fsync_freq != 0 && is_dirty) { if (req_performed % file_fsync_freq == 0) { file_req->operation = FILE_OP_TYPE_FSYNC; file_req->file_id = fsynced_file; file_req->pos = 0; file_req->size = 0; fsynced_file++; if (fsynced_file == num_files) { fsynced_file = 0; is_dirty = 0; } SB_THREAD_MUTEX_UNLOCK(); return sb_req; } } if (mode==MODE_RND_WRITE) /* mode shall be WRITE or RND_WRITE only */ file_req->operation = FILE_OP_TYPE_WRITE; else file_req->operation = FILE_OP_TYPE_READ; retry: tmppos = (long long) (sb_rand_uniform_double() * total_size); tmppos = tmppos - (tmppos % (long long) file_block_size); file_req->file_id = (int) (tmppos / (long long) file_size); file_req->pos = (long long) (tmppos % (long long) file_size); file_req->size = SB_MIN(file_block_size, file_size - file_req->pos); if (sb_globals.validate) { /* For the multi-threaded validation test we have to make sure the block is not being used by another thread */ for (i = 0; i < sb_globals.threads; i++) { if (i != (unsigned) thread_id && per_thread[i].buffer_file_id == file_req->file_id && per_thread[i].buffer_pos == file_req->pos) goto retry; } } per_thread[thread_id].buffer_file_id = file_req->file_id; per_thread[thread_id].buffer_pos = file_req->pos; req_performed++; if (file_req->operation == FILE_OP_TYPE_WRITE) is_dirty = 1; SB_THREAD_MUTEX_UNLOCK(); return sb_req; } int file_execute_event(sb_event_t *sb_req, int thread_id) { FILE_DESCRIPTOR fd; sb_file_request_t *file_req = &sb_req->u.file_request; if (sb_globals.debug) { log_text(LOG_DEBUG, "Executing request, operation: %d, file_id: %d, pos: %d, " "size: %d", file_req->operation, file_req->file_id, (int)file_req->pos, (int)file_req->size); } /* Check request parameters */ if (file_req->file_id > num_files) { log_text(LOG_FATAL, "Incorrect file id in request: %u", file_req->file_id); return 1; } if (file_req->pos + file_req->size > file_size) { log_text(LOG_FATAL, "I/O request exceeds file size. " "file id: %d file size: %lld req offset: %lld req size: %lld", file_req->file_id, (long long) file_size, (long long) file_req->pos, (long long) file_req->size); return 1; } fd = files[file_req->file_id]; switch (file_req->operation) { case FILE_OP_TYPE_NULL: log_text(LOG_FATAL, "Execute of NULL request called !, aborting"); return 1; case FILE_OP_TYPE_WRITE: /* Store checksum and offset in a buffer when in validation mode */ if (sb_globals.validate) file_fill_buffer(per_thread[thread_id].buffer, file_req->size, file_req->pos); if(file_pwrite(file_req->file_id, per_thread[thread_id].buffer, file_req->size, file_req->pos, thread_id) != (ssize_t)file_req->size) { log_errno(LOG_FATAL, "Failed to write file! file: " FD_FMT " pos: %lld", fd, (long long)file_req->pos); return 1; } /* Check if we have to fsync each write operation */ if (file_fsync_all && file_fsync(file_req->file_id, thread_id)) return 1; /* In async mode stats will me updated on AIO requests completion */ if (file_io_mode != FILE_IO_MODE_ASYNC) { sb_counter_inc(thread_id, SB_CNT_WRITE); sb_counter_add(thread_id, SB_CNT_BYTES_WRITTEN, file_req->size); } break; case FILE_OP_TYPE_READ: if(file_pread(file_req->file_id, per_thread[thread_id].buffer, file_req->size, file_req->pos, thread_id) != (ssize_t)file_req->size) { log_errno(LOG_FATAL, "Failed to read file! file: " FD_FMT " pos: %lld", fd, (long long)file_req->pos); return 1; } /* Validate block if run with validation enabled */ if (sb_globals.validate && file_validate_buffer(per_thread[thread_id].buffer, file_req->size, file_req->pos)) { log_text(LOG_FATAL, "Validation failed on file " FD_FMT ", block offset %lld, exiting...", file_req->file_id, (long long) file_req->pos); return 1; } /* In async mode stats will me updated on AIO requests completion */ if(file_io_mode != FILE_IO_MODE_ASYNC) { sb_counter_inc(thread_id, SB_CNT_READ); sb_counter_add(thread_id, SB_CNT_BYTES_READ, file_req->size); } break; case FILE_OP_TYPE_FSYNC: /* Ignore fsync requests if we are already fsync'ing each operation */ if (file_fsync_all) break; if(file_fsync(file_req->file_id, thread_id)) return 1; break; default: log_text(LOG_FATAL, "Execute of UNKNOWN file request type called (%d)!, " "aborting", file_req->operation); return 1; } return 0; } static void print_file_extra_flags(void) { log_text(LOG_NOTICE, "Extra file open flags: %s%s%s%s", file_extra_flags == 0 ? "(none)" : "", file_extra_flags & SB_FILE_FLAG_SYNC ? "sync " : "", file_extra_flags & SB_FILE_FLAG_DSYNC ? "dsync ": "", file_extra_flags & SB_FILE_FLAG_DIRECTIO ? "directio" : "" ); } void file_print_mode(void) { char sizestr[16]; print_file_extra_flags(); log_text(LOG_NOTICE, "%d files, %sB each", num_files, sb_print_value_size(sizestr, sizeof(sizestr), file_size)); log_text(LOG_NOTICE, "%sB total file size", sb_print_value_size(sizestr, sizeof(sizestr), file_size * num_files)); log_text(LOG_NOTICE, "Block size %sB", sb_print_value_size(sizestr, sizeof(sizestr), file_block_size)); if (file_merged_requests > 0) log_text(LOG_NOTICE, "Merging requests up to %sB for sequential IO.", sb_print_value_size(sizestr, sizeof(sizestr), file_request_size)); switch (test_mode) { case MODE_RND_WRITE: case MODE_RND_READ: case MODE_RND_RW: log_text(LOG_NOTICE, "Number of IO requests: %" PRIu64, sb_globals.max_events); log_text(LOG_NOTICE, "Read/Write ratio for combined random IO test: %2.2f", file_rw_ratio); break; default: break; } if (file_fsync_freq > 0) log_text(LOG_NOTICE, "Periodic FSYNC enabled, calling fsync() each %d requests.", file_fsync_freq); if (file_fsync_end) log_text(LOG_NOTICE, "Calling fsync() at the end of test, Enabled."); if (file_fsync_all) log_text(LOG_NOTICE, "Calling fsync() after each write operation."); log_text(LOG_NOTICE, "Using %s I/O mode", get_io_mode_str(file_io_mode)); if (sb_globals.validate) log_text(LOG_NOTICE, "Using checksums validation."); log_text(LOG_NOTICE, "Doing %s test", get_test_mode_str(test_mode)); } /* Print intermediate test statistics. */ void file_report_intermediate(sb_stat_t *stat) { const double seconds = stat->time_interval; log_timestamp(LOG_NOTICE, stat->time_total, "reads: %4.2f MiB/s writes: %4.2f MiB/s fsyncs: %4.2f/s " "latency (ms,%u%%): %4.3f", stat->bytes_read / mebibyte / seconds, stat->bytes_written / mebibyte / seconds, stat->other / seconds, sb_globals.percentile, SEC2MS(stat->latency_pct)); } /* Print cumulative test statistics. */ void file_report_cumulative(sb_stat_t *stat) { const double seconds = stat->time_interval; log_text(LOG_NOTICE, "\n" "Throughput:\n" " read: IOPS=%4.2f %4.2f MiB/s (%4.2f MB/s)\n" " write: IOPS=%4.2f %4.2f MiB/s (%4.2f MB/s)\n" " fsync: IOPS=%4.2f", stat->reads / seconds, stat->bytes_read / mebibyte / seconds, stat->bytes_read / megabyte / seconds, stat->writes / seconds, stat->bytes_written / mebibyte / seconds, stat->bytes_written / megabyte / seconds, stat->other / seconds ); log_text(LOG_NOTICE, ""); log_text(LOG_NOTICE, "Latency (ms):"); log_text(LOG_NOTICE, " min: %10.2f", SEC2MS(stat->latency_min)); log_text(LOG_NOTICE, " avg: %10.2f", SEC2MS(stat->latency_avg)); log_text(LOG_NOTICE, " max: %10.2f", SEC2MS(stat->latency_max)); if (sb_globals.percentile > 0) log_text(LOG_NOTICE, " %3dth percentile: %10.2f", sb_globals.percentile, SEC2MS(stat->latency_pct)); else log_text(LOG_NOTICE, " percentile stats: disabled"); log_text(LOG_NOTICE, " sum: %10.2f", SEC2MS(stat->latency_sum)); log_text(LOG_NOTICE, ""); } /* Return name for I/O mode */ const char *get_io_mode_str(file_io_mode_t mode) { switch (mode) { case FILE_IO_MODE_SYNC: return "synchronous"; case FILE_IO_MODE_ASYNC: return "asynchronous"; case FILE_IO_MODE_MMAP: #if SIZEOF_SIZE_T == 4 return "slow mmaped"; #else return "fast mmaped"; #endif default: break; } return "(unknown)"; } /* Return name for test mode */ const char *get_test_mode_str(file_test_mode_t mode) { switch (mode) { case MODE_WRITE: return "sequential write (creation)"; case MODE_REWRITE: return "sequential rewrite"; case MODE_READ: return "sequential read"; case MODE_RND_READ: return "random read"; case MODE_RND_WRITE: return "random write"; case MODE_RND_RW: return "random r/w"; case MODE_MIXED: return "mixed"; default: break; } return "(unknown)"; } /* Converts the argument of --file-extra-flags to platform-specific open() flags. Returns 1 on error, 0 on success. */ static int convert_extra_flags(file_flags_t extra_flags, int *open_flags) { if (extra_flags) { *open_flags = 0; if (extra_flags & SB_FILE_FLAG_SYNC) { *open_flags |= O_SYNC; } if (extra_flags & SB_FILE_FLAG_DSYNC) { #ifdef O_DSYNC *open_flags |= O_DSYNC; #else log_text(LOG_FATAL, "--file-extra-flags=dsync is not supported on this platform."); return 1; #endif } if (extra_flags & SB_FILE_FLAG_DIRECTIO) { #ifdef HAVE_DIRECTIO /* Will call directio(3) later */ #elif defined(O_DIRECT) *open_flags |= O_DIRECT; #else log_text(LOG_FATAL, "--file-extra-flags=direct is not supported on this platform."); return 1; #endif } if (extra_flags > SB_FILE_FLAG_DIRECTIO) { log_text(LOG_FATAL, "Unknown extra flags value: %d", (int) extra_flags); return 1; } } return 0; } /* Create files of necessary size for test */ int create_files(void) { unsigned int i; int fd; char file_name[512]; long long offset; long long written = 0; sb_timer_t t; double seconds; int flags = 0; log_text(LOG_NOTICE, "%d files, %ldKb each, %ldMb total", num_files, (long)(file_size / 1024), (long)((file_size * num_files) / (1024 * 1024))); log_text(LOG_NOTICE, "Creating files for the test..."); print_file_extra_flags(); if (convert_extra_flags(file_extra_flags, &flags)) return 1; sb_timer_init(&t); sb_timer_start(&t); for (i=0; i < num_files; i++) { snprintf(file_name, sizeof(file_name), "test_file.%d",i); fd = open(file_name, O_CREAT | O_WRONLY | flags, S_IRUSR | S_IWUSR); if (fd < 0) { log_errno(LOG_FATAL, "Can't open file"); return 1; } offset = (long long) lseek(fd, 0, SEEK_END); if (offset >= file_size) log_text(LOG_NOTICE, "Reusing existing file %s", file_name); else if (offset > 0) log_text(LOG_NOTICE, "Extending existing file %s", file_name); else log_text(LOG_NOTICE, "Creating file %s", file_name); for (; offset < file_size; written += file_block_size, offset += file_block_size) { /* If in validation mode, fill buffer with random values and write checksum. Not called in parallel, so use per_thread[0]. */ if (sb_globals.validate) file_fill_buffer(per_thread[0].buffer, file_block_size, offset); if (write(fd, per_thread[0].buffer, file_block_size) < 0) goto error; } /* fsync files to prevent cache flush from affecting test results */ fsync(fd); close(fd); } seconds = NS2SEC(sb_timer_stop(&t)); if (written > 0) log_text(LOG_NOTICE, "%llu bytes written in %.2f seconds (%.2f MiB/sec).", written, seconds, (double) (written / mebibyte) / seconds); else log_text(LOG_NOTICE, "No bytes written."); return 0; error: log_errno(LOG_FATAL, "Failed to write file!"); close(fd); return 1; } /* Remove test files */ int remove_files(void) { unsigned int i; char file_name[512]; log_text(LOG_NOTICE, "Removing test files..."); for (i = 0; i < num_files; i++) { snprintf(file_name, sizeof(file_name), "test_file.%d",i); unlink(file_name); } return 0; } /* 'prepare' command for fileio test */ int file_cmd_prepare(void) { if (parse_arguments()) return 1; /* Make sure that files do not exist for 'sequential write' test mode, create test files for other test modes */ if (test_mode == MODE_WRITE) return remove_files(); return create_files(); } /* 'cleanup' command for fileio test */ int file_cmd_cleanup(void) { if (parse_arguments()) return 1; return remove_files(); } void init_vars(void) { position = 0; /* position in file */ current_file = 0; fsynced_file = 0; /* for counting file to be fsynced */ req_performed = 0; is_dirty = 0; if (sb_globals.validate) { prev_req.size = 0; prev_req.operation = FILE_OP_TYPE_NULL; prev_req.file_id = 0; prev_req.pos = 0; } } /* Before the benchmark is stopped, issue fsync() if --file-fsync-end is used, and wait for all async operations to complete. */ int file_thread_done(int thread_id) { if (file_fsync_end && test_mode != MODE_READ && test_mode != MODE_RND_READ) { for (unsigned i = 0; i < num_files; i++) { if(file_fsync(i, thread_id)) return 1; } } #ifdef HAVE_LIBAIO if (file_io_mode == FILE_IO_MODE_ASYNC && aio_ctxts[thread_id].nrequests > 0) return file_wait(thread_id, aio_ctxts[thread_id].nrequests); #endif return 0; } #ifdef HAVE_LIBAIO /* Allocate async contexts pool */ int file_async_init(void) { unsigned int i; if (file_io_mode != FILE_IO_MODE_ASYNC) return 0; file_async_backlog = sb_get_value_int("file-async-backlog"); if (file_async_backlog <= 0) { log_text(LOG_FATAL, "Invalid value of file-async-backlog: %d", file_async_backlog); return 1; } aio_ctxts = (sb_aio_context_t *)calloc(sb_globals.threads, sizeof(sb_aio_context_t)); for (i = 0; i < sb_globals.threads; i++) { if (io_queue_init(file_async_backlog, &aio_ctxts[i].io_ctxt)) { log_errno(LOG_FATAL, "io_queue_init() failed!"); return 1; } aio_ctxts[i].events = (struct io_event *)malloc(file_async_backlog * sizeof(struct io_event)); if (aio_ctxts[i].events == NULL) { log_errno(LOG_FATAL, "Failed to allocate async I/O context!"); return 1; } } return 0; } /* Destroy async contexts pool */ int file_async_done(void) { unsigned int i; if (file_io_mode != FILE_IO_MODE_ASYNC) return 0; for (i = 0; i < sb_globals.threads; i++) { io_queue_release(aio_ctxts[i].io_ctxt); free(aio_ctxts[i].events); } free(aio_ctxts); return 0; } /* Submit async I/O requests until the length of request queue exceeds the limit. Then wait for at least one request to complete and proceed. */ int file_submit_or_wait(struct iocb *iocb, sb_file_op_t type, ssize_t len, int thread_id) { sb_aio_oper_t *oper; struct iocb *iocbp; oper = (sb_aio_oper_t *)malloc(sizeof(sb_aio_oper_t)); if (oper == NULL) { log_text(LOG_FATAL, "Failed to allocate AIO operation!"); return 1; } memcpy(&oper->iocb, iocb, sizeof(*iocb)); oper->type = type; oper->len = len; iocbp = &oper->iocb; if (io_submit(aio_ctxts[thread_id].io_ctxt, 1, &iocbp) < 1) { log_errno(LOG_FATAL, "io_submit() failed!"); return 1; } aio_ctxts[thread_id].nrequests++; if (aio_ctxts[thread_id].nrequests < file_async_backlog) return 0; return file_wait(thread_id, 1); } /* Wait for at least nreq I/O requests to complete */ int file_wait(int thread_id, long nreq) { long i; long nr; struct io_event *event; sb_aio_oper_t *oper; struct iocb *iocbp; /* Try to read some events */ #ifdef HAVE_OLD_GETEVENTS (void)nreq; /* unused */ nr = io_getevents(aio_ctxts[thread_id].io_ctxt, file_async_backlog, aio_ctxts[thread_id].events, NULL); #else nr = io_getevents(aio_ctxts[thread_id].io_ctxt, nreq, file_async_backlog, aio_ctxts[thread_id].events, NULL); #endif if (nr < 1) { log_errno(LOG_FATAL, "io_getevents() failed!"); return 1; } /* Verify results */ for (i = 0; i < nr; i++) { event = (struct io_event *)aio_ctxts[thread_id].events + i; iocbp = (struct iocb *)(unsigned long)event->obj; oper = (sb_aio_oper_t *)iocbp; switch (oper->type) { case FILE_OP_TYPE_FSYNC: if (event->res != 0) { log_text(LOG_FATAL, "Asynchronous fsync failed!\n"); return 1; } sb_counter_inc(thread_id, SB_CNT_OTHER); break; case FILE_OP_TYPE_READ: if ((ssize_t)event->res != oper->len) { log_text(LOG_FATAL, "Asynchronous read failed!\n"); return 1; } sb_counter_inc(thread_id, SB_CNT_READ); sb_counter_add(thread_id, SB_CNT_BYTES_READ, oper->len); break; case FILE_OP_TYPE_WRITE: if ((ssize_t)event->res != oper->len) { log_text(LOG_FATAL, "Asynchronous write failed!\n"); return 1; } sb_counter_inc(thread_id, SB_CNT_WRITE); sb_counter_add(thread_id, SB_CNT_BYTES_WRITTEN, oper->len); break; default: break; } free(oper); aio_ctxts[thread_id].nrequests--; } return 0; } #endif /* HAVE_LIBAIO */ #ifdef HAVE_MMAP /* Initialize data structures required for mmap'ed I/O operations */ int file_mmap_prepare(void) { unsigned int i; if (file_io_mode != FILE_IO_MODE_MMAP) return 0; file_page_mask = ~(sb_get_allocation_granularity() - 1); /* Extend file sizes for sequential write test */ if (test_mode == MODE_WRITE) for (i = 0; i < num_files; i++) { if (ftruncate(files[i], file_size)) { log_errno(LOG_FATAL, "ftruncate() failed on file %d", i); return 1; } } #if SIZEOF_SIZE_T > 4 mmaps = (void **)malloc(num_files * sizeof(void *)); for (i = 0; i < num_files; i++) { mmaps[i] = mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, files[i], 0); if (mmaps[i] == MAP_FAILED) { log_errno(LOG_FATAL, "mmap() failed on file %d", i); return 1; } } #else (void)i; /* unused */ #endif return 0; } /* Destroy data structure used by mmap'ed I/O operations */ int file_mmap_done(void) { unsigned int i; if (file_io_mode != FILE_IO_MODE_MMAP) return 0; #if SIZEOF_SIZE_T > 4 for (i = 0; i < num_files; i++) munmap(mmaps[i], file_size); free(mmaps); #else (void)i; /* unused */ #endif return 0; } #endif /* HAVE_MMAP */ int file_do_fsync(unsigned int id, int thread_id) { FILE_DESCRIPTOR fd = files[id]; #ifdef HAVE_LIBAIO struct iocb iocb; #else (void)thread_id; /* unused */ #endif /* FIXME: asynchronous fsync support is missing in Linux kernel at the moment */ if (file_io_mode == FILE_IO_MODE_SYNC || file_io_mode == FILE_IO_MODE_ASYNC #if defined(HAVE_MMAP) && SIZEOF_SIZE_T == 4 /* Use fsync in mmaped mode on 32-bit architectures */ || file_io_mode == FILE_IO_MODE_MMAP #endif ) { if (file_fsync_mode == FSYNC_ALL) return fsync(fd); #ifdef F_FULLFSYNC return fcntl(fd, F_FULLFSYNC) != -1; #elif defined(HAVE_FDATASYNC) return fdatasync(fd); #else log_text(LOG_ALERT, "Unknown fsync mode: %d", file_fsync_mode); return -1; #endif } #ifdef HAVE_LIBAIO else if (file_io_mode == FILE_IO_MODE_ASYNC) { /* Use asynchronous fsync */ if (file_fsync_mode == FSYNC_ALL) io_prep_fsync(&iocb, fd); else io_prep_fdsync(&iocb, fd); return file_submit_or_wait(&iocb, FILE_OP_TYPE_FSYNC, 0, thread_id); } #endif #ifdef HAVE_MMAP /* Use msync on file on 64-bit architectures */ else if (file_io_mode == FILE_IO_MODE_MMAP) { return msync(mmaps[id], file_size, MS_SYNC | MS_INVALIDATE); } #endif return 1; /* Unknown I/O mode */ } int file_fsync(unsigned int id, int thread_id) { if (file_do_fsync(id, thread_id)) { log_errno(LOG_FATAL, "Failed to fsync file! file: " FD_FMT, files[id]); return 1; } sb_counter_inc(thread_id, SB_CNT_OTHER); return 0; } ssize_t file_pread(unsigned int file_id, void *buf, ssize_t count, long long offset, int thread_id) { FILE_DESCRIPTOR fd = files[file_id]; #ifdef HAVE_MMAP void *start; long long page_addr; long long page_offset; #endif #ifdef HAVE_LIBAIO struct iocb iocb; #else (void)thread_id; /* unused */ #endif if (file_io_mode == FILE_IO_MODE_SYNC) return pread(fd, buf, count, offset); #ifdef HAVE_LIBAIO else if (file_io_mode == FILE_IO_MODE_ASYNC) { /* Use asynchronous read */ io_prep_pread(&iocb, fd, buf, count, offset); if (file_submit_or_wait(&iocb, FILE_OP_TYPE_READ, count, thread_id)) return 0; return count; } #endif #ifdef HAVE_MMAP else if (file_io_mode == FILE_IO_MODE_MMAP) { # if SIZEOF_SIZE_T == 4 /* Create file mapping for each I/O operation on 32-bit platforms */ page_addr = offset & file_page_mask; page_offset = offset - page_addr; start = mmap(NULL, count + page_offset, PROT_READ, MAP_SHARED, fd, page_addr); if (start == MAP_FAILED) return 0; memcpy(buf, (char *)start + page_offset, count); munmap(start, count + page_offset); return count; # else (void)start; /* unused */ (void)page_addr; /* unused */ (void)page_offset; /* unused */ /* We already have all files mapped on 64-bit platforms */ memcpy(buf, (char *)mmaps[file_id] + offset, count); return count; # endif } #endif /* HAVE_MMAP */ return 1; /* Unknown I/O mode */ } ssize_t file_pwrite(unsigned int file_id, void *buf, ssize_t count, long long offset, int thread_id) { FILE_DESCRIPTOR fd = files[file_id]; #ifdef HAVE_MMAP void *start; size_t page_addr; size_t page_offset; #endif #ifdef HAVE_LIBAIO struct iocb iocb; #else (void)thread_id; /* unused */ #endif if (file_io_mode == FILE_IO_MODE_SYNC) return pwrite(fd, buf, count, offset); #ifdef HAVE_LIBAIO else if (file_io_mode == FILE_IO_MODE_ASYNC) { /* Use asynchronous write */ io_prep_pwrite(&iocb, fd, buf, count, offset); if (file_submit_or_wait(&iocb, FILE_OP_TYPE_WRITE, count, thread_id)) return 0; return count; } #endif #ifdef HAVE_MMAP else if (file_io_mode == FILE_IO_MODE_MMAP) { # if SIZEOF_SIZE_T == 4 /* Create file mapping for each I/O operation on 32-bit platforms */ page_addr = offset & file_page_mask; page_offset = offset - page_addr; start = mmap(NULL, count + page_offset, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_addr); if (start == MAP_FAILED) return 0; memcpy((char *)start + page_offset, buf, count); munmap(start, count + page_offset); return count; # else (void)start; /* unused */ (void)page_addr; /* unused */ (void)page_offset; /* unused */ /* We already have all files mapped on 64-bit platforms */ memcpy((char *)mmaps[file_id] + offset, buf, count); return count; # endif } #endif /* HAVE_MMAP */ return 0; /* Unknown I/O mode */ } /* Parse the command line arguments */ int parse_arguments(void) { char *mode; unsigned int i; num_files = sb_get_value_int("file-num"); if (num_files <= 0) { log_text(LOG_FATAL, "Invalid value for file-num: %d", num_files); return 1; } total_size = sb_get_value_size("file-total-size"); if (total_size <= 0) { log_text(LOG_FATAL, "Invalid value for file-total-size: %lld", (long long)total_size); return 1; } file_size = total_size / num_files; mode = sb_get_value_string("file-test-mode"); /* File test mode is necessary only for 'run' command */ if (!strcmp(sb_globals.cmdname, "run")) { if (mode == NULL) { log_text(LOG_FATAL, "Missing required argument: --file-test-mode\n"); log_text(LOG_NOTICE, "fileio options:"); sb_print_options(fileio_args); return 1; } if (!strcmp(mode, "seqwr")) test_mode = MODE_WRITE; else if (!strcmp(mode, "seqrewr")) test_mode = MODE_REWRITE; else if (!strcmp(mode, "seqrd")) test_mode = MODE_READ; else if (!strcmp(mode, "rndrd")) test_mode = MODE_RND_READ; else if (!strcmp(mode, "rndwr")) test_mode = MODE_RND_WRITE; else if (!strcmp(mode, "rndrw")) test_mode = MODE_RND_RW; else { log_text(LOG_FATAL, "Invalid IO operations mode: %s.", mode); return 1; } } mode = sb_get_value_string("file-io-mode"); if (mode == NULL) mode = "sync"; if (!strcmp(mode, "sync")) file_io_mode = FILE_IO_MODE_SYNC; else if (!strcmp(mode, "async")) { #ifdef HAVE_LIBAIO file_io_mode = FILE_IO_MODE_ASYNC; #else log_text(LOG_FATAL, "asynchronous I/O mode is unsupported on this platform."); return 1; #endif } else if (!strcmp(mode, "mmap")) { #ifdef HAVE_MMAP file_io_mode = FILE_IO_MODE_MMAP; #else log_text(LOG_FATAL, "mmap'ed I/O mode is unsupported on this platform."); return 1; #endif } else { log_text(LOG_FATAL, "unknown I/O mode: %s", mode); return 1; } file_merged_requests = sb_get_value_int("file-merged-requests"); if (file_merged_requests < 0) { log_text(LOG_FATAL, "Invalid value for file-merged-requests: %d.", file_merged_requests); return 1; } file_block_size = sb_get_value_size("file-block-size"); if (file_block_size <= 0) { log_text(LOG_FATAL, "Invalid value for file-block-size: %d.", file_block_size); return 1; } if (file_merged_requests > 0) file_request_size = file_block_size * file_merged_requests; else file_request_size = file_block_size; mode = sb_get_value_string("file-extra-flags"); sb_list_item_t *pos; SB_LIST_FOR_EACH(pos, sb_get_value_list("file-extra-flags")) { const char *val = SB_LIST_ENTRY(pos, value_t, listitem)->data; if (!strcmp(val, "sync")) file_extra_flags |= SB_FILE_FLAG_SYNC; else if (!strcmp(val, "dsync")) file_extra_flags |= SB_FILE_FLAG_DSYNC; else if (!strcmp(val, "direct")) file_extra_flags |= SB_FILE_FLAG_DIRECTIO; else { log_text(LOG_FATAL, "Invalid value for file-extra-flags: %s", mode); return 1; } } file_fsync_freq = sb_get_value_int("file-fsync-freq"); if (file_fsync_freq < 0) { log_text(LOG_FATAL, "Invalid value for file-fsync-freq: %d.", file_fsync_freq); return 1; } file_fsync_end = sb_get_value_flag("file-fsync-end"); file_fsync_all = sb_get_value_flag("file-fsync-all"); /* file-fsync-all overrides file-fsync-end and file-fsync-freq */ if (file_fsync_all) { file_fsync_end = 0; file_fsync_freq = 0; } mode = sb_get_value_string("file-fsync-mode"); if (!strcmp(mode, "fsync")) file_fsync_mode = FSYNC_ALL; else if (!strcmp(mode, "fdatasync")) { #ifdef HAVE_FDATASYNC file_fsync_mode = FSYNC_DATA; #else log_text(LOG_FATAL, "fdatasync() is unavailable on this platform"); return 1; #endif } else { log_text(LOG_FATAL, "Invalid fsync mode: %s.", mode); return 1; } file_rw_ratio = sb_get_value_double("file-rw-ratio"); if (file_rw_ratio < 0) { log_text(LOG_FATAL, "Invalid value for --file-rw-ratio: %f.", file_rw_ratio); return 1; } per_thread = malloc(sizeof(*per_thread) * sb_globals.threads); for (i = 0; i < sb_globals.threads; i++) { per_thread[i].buffer = sb_memalign(file_request_size, sb_getpagesize()); if (per_thread[i].buffer == NULL) { log_text(LOG_FATAL, "Failed to allocate a memory buffer"); return 1; } memset(per_thread[i].buffer, 0, file_request_size); } return 0; } /* check if two requests are sequential */ void check_seq_req(sb_file_request_t *prev_req, sb_file_request_t *r) { /* Do not check fsync operation at the moment */ if (r->operation == FILE_OP_TYPE_FSYNC || r->operation == FILE_OP_TYPE_NULL) return; /* if old request is NULL do not check against it */ if (prev_req->operation == FILE_OP_TYPE_NULL) return; /* check files */ if (r->file_id - prev_req->file_id>1 && !(r->file_id == 0 && prev_req->file_id == num_files-1)) { log_text(LOG_WARNING, "Discovered too large file difference in seq requests!"); return; } if (r->file_id == prev_req->file_id) { if(r->pos - prev_req->pos != prev_req->size) { log_text(LOG_WARNING, "Discovered too large position difference in seq request!"); return; } } else /* if file changed last request has to complete file and new start */ { if ((prev_req->pos + prev_req->size != file_size) || (r->pos != 0)) { log_text(LOG_WARNING, "Invalid file switch found!"); log_text(LOG_WARNING, "Old: file_id: %d, pos: %d size: %d", prev_req->file_id, (int)prev_req->pos, (int)prev_req->size); log_text(LOG_WARNING, "New: file_id: %d, pos: %d size: %d", r->file_id, (int)r->pos, (int)r->size); return; } } } /* Alignment requirement for mmap(). The same as page size, except on Windows (on Windows it has to be 64KB, even if pagesize is only 4 or 8KB) */ size_t sb_get_allocation_granularity(void) { return sb_getpagesize(); } static void sb_free_memaligned(void *buf) { free(buf); } static FILE_DESCRIPTOR sb_open(const char *name) { FILE_DESCRIPTOR file; int flags = 0; if (convert_extra_flags(file_extra_flags, &flags)) return SB_INVALID_FILE; file = open(name, O_RDWR | flags, S_IRUSR | S_IWUSR); #ifdef HAVE_DIRECTIO if (VALID_FILE(file) && file_extra_flags & SB_FILE_FLAG_DIRECTIO && directio(file, DIRECTIO_ON)) { log_errno(LOG_FATAL, "directio() failed"); return SB_INVALID_FILE; } #endif return file; } /* Create a file with a given path. Signal an error if the file already exists. Return a non-zero value on error. */ static int sb_create(const char *path) { FILE_DESCRIPTOR file; int res; file = open(path, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); res = !VALID_FILE(file); close(file); return res; } /* Fill buffer with random values and write checksum */ void file_fill_buffer(unsigned char *buf, unsigned int len, size_t offset) { unsigned int i; for (i = 0; i < len - (FILE_CHECKSUM_LENGTH + FILE_OFFSET_LENGTH); i++) buf[i] = sb_rand_uniform_uint64() & 0xFF; /* Store the checksum */ *(int *)(void *)(buf + i) = (int)crc32(0, (unsigned char *)buf, len - (FILE_CHECKSUM_LENGTH + FILE_OFFSET_LENGTH)); /* Store the offset */ *(long *)(void *)(buf + i + FILE_CHECKSUM_LENGTH) = offset; } /* Validate checksum and offset of block read from disk */ int file_validate_buffer(unsigned char *buf, unsigned int len, size_t offset) { unsigned int checksum; unsigned int cs_offset; cs_offset = len - (FILE_CHECKSUM_LENGTH + FILE_OFFSET_LENGTH); checksum = (unsigned int)crc32(0, (unsigned char *)buf, cs_offset); if (checksum != *(unsigned int *)(void *)(buf + cs_offset)) { log_text(LOG_FATAL, "Checksum mismatch in block with offset: %lld", (long long) offset); log_text(LOG_FATAL, " Calculated value: 0x%x Stored value: 0x%x", checksum, *(unsigned int *)(void *)(buf + cs_offset)); return 1; } if (offset != *(size_t *)(void *)(buf + cs_offset + FILE_CHECKSUM_LENGTH)) { log_text(LOG_FATAL, "Offset mismatch in block:"); log_text(LOG_FATAL, " Actual offset: %zu Stored offset: %zu", offset, *(size_t *)(void *)(buf + cs_offset + FILE_CHECKSUM_LENGTH)); return 1; } return 0; } ================================================ FILE: src/tests/memory/Makefile.am ================================================ # Copyright (C) 2004 MySQL AB # Copyright (C) 2004-2008 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA noinst_LIBRARIES = libsbmemory.a libsbmemory_a_SOURCES = sb_memory.c ../sb_memory.h libsbmemory_a_CPPFLAGS = $(AM_CPPFLAGS) ================================================ FILE: src/tests/memory/sb_memory.c ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "sysbench.h" #include "sb_rand.h" #ifdef HAVE_SYS_IPC_H # include #endif #ifdef HAVE_SYS_SHM_H # include #endif #include #define LARGE_PAGE_SIZE (4UL * 1024 * 1024) /* Memory test arguments */ static sb_arg_t memory_args[] = { SB_OPT("memory-block-size", "size of memory block for test", "1K", SIZE), SB_OPT("memory-total-size", "total size of data to transfer", "100G", SIZE), SB_OPT("memory-scope", "memory access scope {global,local}", "global", STRING), #ifdef HAVE_LARGE_PAGES SB_OPT("memory-hugetlb", "allocate memory from HugeTLB pool", "off", BOOL), #endif SB_OPT("memory-oper", "type of memory operations {read, write, none}", "write", STRING), SB_OPT("memory-access-mode", "memory access mode {seq,rnd}", "seq", STRING), SB_OPT_END }; /* Memory test operations */ static int memory_init(void); static void memory_print_mode(void); static sb_event_t memory_next_event(int); static int event_rnd_none(sb_event_t *, int); static int event_rnd_read(sb_event_t *, int); static int event_rnd_write(sb_event_t *, int); static int event_seq_none(sb_event_t *, int); static int event_seq_read(sb_event_t *, int); static int event_seq_write(sb_event_t *, int); static void memory_report_intermediate(sb_stat_t *); static void memory_report_cumulative(sb_stat_t *); static sb_test_t memory_test = { .sname = "memory", .lname = "Memory functions speed test", .ops = { .init = memory_init, .print_mode = memory_print_mode, .next_event = memory_next_event, .report_intermediate = memory_report_intermediate, .report_cumulative = memory_report_cumulative }, .args = memory_args }; /* Test arguments */ static ssize_t memory_block_size; static long long memory_total_size; static unsigned int memory_scope; static unsigned int memory_oper; static unsigned int memory_access_rnd; #ifdef HAVE_LARGE_PAGES static unsigned int memory_hugetlb; #endif static ssize_t max_offset; /* Arrays of per-thread buffers and event counters */ static size_t **buffers; static uint64_t *thread_counters; #ifdef HAVE_LARGE_PAGES static void * hugetlb_alloc(size_t size); #endif int register_test_memory(sb_list_t *tests) { SB_LIST_ADD_TAIL(&memory_test.listitem, tests); return 0; } int memory_init(void) { unsigned int i; char *s; size_t *buffer; memory_block_size = sb_get_value_size("memory-block-size"); if (memory_block_size < SIZEOF_SIZE_T || /* Must be a power of 2 */ (memory_block_size & (memory_block_size - 1)) != 0) { log_text(LOG_FATAL, "Invalid value for memory-block-size: %s", sb_get_value_string("memory-block-size")); return 1; } max_offset = memory_block_size / SIZEOF_SIZE_T - 1; memory_total_size = sb_get_value_size("memory-total-size"); s = sb_get_value_string("memory-scope"); if (!strcmp(s, "global")) memory_scope = SB_MEM_SCOPE_GLOBAL; else if (!strcmp(s, "local")) memory_scope = SB_MEM_SCOPE_LOCAL; else { log_text(LOG_FATAL, "Invalid value for memory-scope: %s", s); return 1; } #ifdef HAVE_LARGE_PAGES memory_hugetlb = sb_get_value_flag("memory-hugetlb"); #endif s = sb_get_value_string("memory-oper"); if (!strcmp(s, "write")) memory_oper = SB_MEM_OP_WRITE; else if (!strcmp(s, "read")) memory_oper = SB_MEM_OP_READ; else if (!strcmp(s, "none")) memory_oper = SB_MEM_OP_NONE; else { log_text(LOG_FATAL, "Invalid value for memory-oper: %s", s); return 1; } s = sb_get_value_string("memory-access-mode"); if (!strcmp(s, "seq")) memory_access_rnd = 0; else if (!strcmp(s, "rnd")) memory_access_rnd = 1; else { log_text(LOG_FATAL, "Invalid value for memory-access-mode: %s", s); return 1; } if (memory_scope == SB_MEM_SCOPE_GLOBAL) { #ifdef HAVE_LARGE_PAGES if (memory_hugetlb) buffer = hugetlb_alloc(memory_block_size); else #endif buffer = sb_memalign(memory_block_size, sb_getpagesize()); if (buffer == NULL) { log_text(LOG_FATAL, "Failed to allocate buffer!"); return 1; } memset(buffer, 0, memory_block_size); } thread_counters = malloc(sb_globals.threads * sizeof(uint64_t)); buffers = malloc(sb_globals.threads * sizeof(void *)); if (thread_counters == NULL || buffers == NULL) { log_text(LOG_FATAL, "Failed to allocate thread-local memory!"); return 1; } for (i = 0; i < sb_globals.threads; i++) { if (memory_scope == SB_MEM_SCOPE_GLOBAL) buffers[i] = buffer; else { #ifdef HAVE_LARGE_PAGES if (memory_hugetlb) buffers[i] = hugetlb_alloc(memory_block_size); else #endif buffers[i] = sb_memalign(memory_block_size, sb_getpagesize()); if (buffers[i] == NULL) { log_text(LOG_FATAL, "Failed to allocate buffer for thread #%d!", i); return 1; } memset(buffers[i], 0, memory_block_size); } thread_counters[i] = memory_total_size / memory_block_size / sb_globals.threads; } switch (memory_oper) { case SB_MEM_OP_NONE: memory_test.ops.execute_event = memory_access_rnd ? event_rnd_none : event_seq_none; break; case SB_MEM_OP_READ: memory_test.ops.execute_event = memory_access_rnd ? event_rnd_read : event_seq_read; break; case SB_MEM_OP_WRITE: memory_test.ops.execute_event = memory_access_rnd ? event_rnd_write : event_seq_write; break; default: log_text(LOG_FATAL, "Unknown memory request type: %d\n", memory_oper); return 1; } /* Use our own limit on the number of events */ sb_globals.max_events = 0; return 0; } sb_event_t memory_next_event(int tid) { sb_event_t req; if (memory_total_size > 0 && thread_counters[tid]-- == 0) { req.type = SB_REQ_TYPE_NULL; return req; } req.type = SB_REQ_TYPE_MEMORY; return req; } /* Use either 32- or 64-bit primitives depending on the native word size. ConcurrencyKit ensures the corresponding loads/stores are not optimized away by the compiler. */ #if SIZEOF_SIZE_T == 4 # define SIZE_T_LOAD(ptr) ck_pr_load_32((uint32_t *)(ptr)) # define SIZE_T_STORE(ptr,val) ck_pr_store_32((uint32_t *)(ptr),(uint32_t)(val)) #elif SIZEOF_SIZE_T == 8 # define SIZE_T_LOAD(ptr) ck_pr_load_64((uint64_t *)(ptr)) # define SIZE_T_STORE(ptr,val) ck_pr_store_64((uint64_t *)(ptr),(uint64_t)(val)) #else # error Unsupported platform. #endif int event_rnd_none(sb_event_t *req, int tid) { (void) req; /* unused */ (void) tid; /* unused */ for (ssize_t i = 0; i <= max_offset; i++) { size_t offset = (volatile size_t) sb_rand_default(0, max_offset); (void) offset; /* unused */ } return 0; } int event_rnd_read(sb_event_t *req, int tid) { (void) req; /* unused */ for (ssize_t i = 0; i <= max_offset; i++) { size_t offset = (size_t) sb_rand_default(0, max_offset); size_t val = SIZE_T_LOAD(buffers[tid] + offset); (void) val; /* unused */ } return 0; } int event_rnd_write(sb_event_t *req, int tid) { (void) req; /* unused */ for (ssize_t i = 0; i <= max_offset; i++) { size_t offset = (size_t) sb_rand_default(0, max_offset); SIZE_T_STORE(buffers[tid] + offset, i); } return 0; } int event_seq_none(sb_event_t *req, int tid) { (void) req; /* unused */ for (size_t *buf = buffers[tid], *end = buf + max_offset; buf <= end; buf++) { ck_pr_barrier(); /* nop */ } return 0; } int event_seq_read(sb_event_t *req, int tid) { (void) req; /* unused */ for (size_t *buf = buffers[tid], *end = buf + max_offset; buf < end; buf++) { size_t val = SIZE_T_LOAD(buf); (void) val; /* unused */ } return 0; } int event_seq_write(sb_event_t *req, int tid) { (void) req; /* unused */ for (size_t *buf = buffers[tid], *end = buf + max_offset; buf < end; buf++) { SIZE_T_STORE(buf, (size_t) tid); } return 0; } void memory_print_mode(void) { char *str; log_text(LOG_NOTICE, "Running memory speed test with the following options:"); log_text(LOG_NOTICE, " block size: %ldKiB", (long)(memory_block_size / 1024)); log_text(LOG_NOTICE, " total size: %ldMiB", (long)(memory_total_size / 1024 / 1024)); switch (memory_oper) { case SB_MEM_OP_READ: str = "read"; break; case SB_MEM_OP_WRITE: str = "write"; break; case SB_MEM_OP_NONE: str = "none"; break; default: str = "(unknown)"; break; } log_text(LOG_NOTICE, " operation: %s", str); switch (memory_scope) { case SB_MEM_SCOPE_GLOBAL: str = "global"; break; case SB_MEM_SCOPE_LOCAL: str = "local"; break; default: str = "(unknown)"; break; } log_text(LOG_NOTICE, " scope: %s", str); log_text(LOG_NOTICE, ""); } /* Print intermediate test statistics. */ void memory_report_intermediate(sb_stat_t *stat) { const double megabyte = 1024.0 * 1024.0; log_timestamp(LOG_NOTICE, stat->time_total, "%4.2f MiB/sec", stat->events * memory_block_size / megabyte / stat->time_interval); } /* Print cumulative test statistics. */ void memory_report_cumulative(sb_stat_t *stat) { const double megabyte = 1024.0 * 1024.0; log_text(LOG_NOTICE, "Total operations: %" PRIu64 " (%8.2f per second)\n", stat->events, stat->events / stat->time_interval); if (memory_oper != SB_MEM_OP_NONE) { const double mb = stat->events * memory_block_size / megabyte; log_text(LOG_NOTICE, "%4.2f MiB transferred (%4.2f MiB/sec)\n", mb, mb / stat->time_interval); } sb_report_cumulative(stat); } #ifdef HAVE_LARGE_PAGES /* Allocate memory from HugeTLB pool */ void * hugetlb_alloc(size_t size) { int shmid; void *ptr; struct shmid_ds buf; /* Align block size to my_large_page_size */ size = ((size - 1) & ~LARGE_PAGE_SIZE) + LARGE_PAGE_SIZE; shmid = shmget(IPC_PRIVATE, size, SHM_HUGETLB | SHM_R | SHM_W); if (shmid < 0) { log_errno(LOG_FATAL, "Failed to allocate %zd bytes from HugeTLB memory.", size); return NULL; } ptr = shmat(shmid, NULL, 0); if (ptr == (void *)-1) { log_errno(LOG_FATAL, "Failed to attach shared memory segment,"); shmctl(shmid, IPC_RMID, &buf); return NULL; } /* Remove the shared memory segment so that it will be automatically freed after memory is detached or process exits */ shmctl(shmid, IPC_RMID, &buf); return ptr; } #endif ================================================ FILE: src/tests/mutex/Makefile.am ================================================ # Copyright (C) 2004 MySQL AB # Copyright (C) 2004-2008 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA noinst_LIBRARIES = libsbmutex.a libsbmutex_a_SOURCES = sb_mutex.c ../sb_mutex.h libsbmutex_a_CPPFLAGS = $(AM_CPPFLAGS) ================================================ FILE: src/tests/mutex/sb_mutex.c ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_PTHREAD_H # include #endif #include "sysbench.h" #include "sb_ck_pr.h" #include "sb_rand.h" typedef struct { pthread_mutex_t mutex; char pad[256]; } thread_lock; /* Mutex test arguments */ static sb_arg_t mutex_args[] = { SB_OPT("mutex-num", "total size of mutex array", "4096", INT), SB_OPT("mutex-locks", "number of mutex locks to do per thread", "50000", INT), SB_OPT("mutex-loops", "number of empty loops to do outside mutex lock", "10000", INT), SB_OPT_END }; /* Mutex test operations */ static int mutex_init(void); static void mutex_print_mode(void); static sb_event_t mutex_next_event(int); static int mutex_execute_event(sb_event_t *, int); static int mutex_done(void); static sb_test_t mutex_test = { .sname = "mutex", .lname = "Mutex performance test", .ops = { .init = mutex_init, .print_mode = mutex_print_mode, .next_event = mutex_next_event, .execute_event = mutex_execute_event, .done = mutex_done }, .args = mutex_args }; static thread_lock *thread_locks; static unsigned int mutex_num; static unsigned int mutex_loops; static unsigned int mutex_locks; static unsigned int global_var; static TLS int tls_counter; int register_test_mutex(sb_list_t *tests) { SB_LIST_ADD_TAIL(&mutex_test.listitem, tests); return 0; } int mutex_init(void) { unsigned int i; mutex_num = sb_get_value_int("mutex-num"); mutex_loops = sb_get_value_int("mutex-loops"); mutex_locks = sb_get_value_int("mutex-locks"); thread_locks = (thread_lock *)malloc(mutex_num * sizeof(thread_lock)); if (thread_locks == NULL) { log_text(LOG_FATAL, "Memory allocation failure!"); return 1; } for (i = 0; i < mutex_num; i++) pthread_mutex_init(&thread_locks[i].mutex, NULL); return 0; } int mutex_done(void) { unsigned int i; for(i=0; i < mutex_num; i++) pthread_mutex_destroy(&thread_locks[i].mutex); free(thread_locks); return 0; } sb_event_t mutex_next_event(int thread_id) { sb_event_t sb_req; sb_mutex_request_t *mutex_req = &sb_req.u.mutex_request; (void) thread_id; /* unused */ /* Perform only one request per thread */ if (tls_counter++ > 0) sb_req.type = SB_REQ_TYPE_NULL; else { sb_req.type = SB_REQ_TYPE_MUTEX; mutex_req->nlocks = mutex_locks; mutex_req->nloops = mutex_loops; } return sb_req; } int mutex_execute_event(sb_event_t *sb_req, int thread_id) { unsigned int i; unsigned int current_lock; sb_mutex_request_t *mutex_req = &sb_req->u.mutex_request; (void) thread_id; /* unused */ do { current_lock = sb_rand_uniform(0, mutex_num - 1); for (i = 0; i < mutex_req->nloops; i++) ck_pr_barrier(); pthread_mutex_lock(&thread_locks[current_lock].mutex); global_var++; pthread_mutex_unlock(&thread_locks[current_lock].mutex); mutex_req->nlocks--; } while (mutex_req->nlocks > 0); return 0; } void mutex_print_mode(void) { log_text(LOG_INFO, "Doing mutex performance test"); } ================================================ FILE: src/tests/sb_cpu.h ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_CPU_H #define SB_CPU_H int register_test_cpu(sb_list_t *tests); #endif ================================================ FILE: src/tests/sb_fileio.h ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_FILEIO_H #define SB_FILEIO_H /* File operation types */ typedef enum { FILE_OP_TYPE_NULL, FILE_OP_TYPE_READ, FILE_OP_TYPE_WRITE, FILE_OP_TYPE_FSYNC } sb_file_op_t; /* File IO request definition */ typedef struct { unsigned int file_id; long long pos; ssize_t size; sb_file_op_t operation; } sb_file_request_t; int register_test_fileio(sb_list_t *tests); #endif ================================================ FILE: src/tests/sb_memory.h ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2008 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_MEMORY_H #define SB_MEMORY_H /* Memory request type definition */ typedef enum { SB_MEM_OP_NONE, SB_MEM_OP_READ, SB_MEM_OP_WRITE } sb_mem_op_t; /* Memory scope type definition */ typedef enum { SB_MEM_SCOPE_GLOBAL, SB_MEM_SCOPE_LOCAL } sb_mem_scope_t; int register_test_memory(sb_list_t *tests); #endif ================================================ FILE: src/tests/sb_mutex.h ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_MUTEX_H #define SB_MUTEX_H /* Threads request definition */ typedef struct { unsigned int nlocks; unsigned int nloops; } sb_mutex_request_t; int register_test_mutex(sb_list_t *tests); #endif ================================================ FILE: src/tests/sb_threads.h ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SB_THREADS_H #define SB_THREADS_H /* Threads request definition */ typedef struct { unsigned int lock_num; } sb_threads_request_t; int register_test_threads(sb_list_t *tests); #endif ================================================ FILE: src/tests/threads/Makefile.am ================================================ # Copyright (C) 2004 MySQL AB # Copyright (C) 2004-2008 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA noinst_LIBRARIES = libsbthreads.a libsbthreads_a_SOURCES = sb_threads.c ../sb_threads.h libsbthreads_a_CPPFLAGS = $(AM_CPPFLAGS) ================================================ FILE: src/tests/threads/sb_threads.c ================================================ /* Copyright (C) 2004 MySQL AB Copyright (C) 2004-2018 Alexey Kopytov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_PTHREAD_H # include #endif #include "sysbench.h" #include "sb_ck_pr.h" /* How to test scheduler pthread_yield or sched_yield */ #ifdef HAVE_PTHREAD_YIELD #define YIELD pthread_yield #else #define YIELD sched_yield #endif /* Threads test arguments */ static sb_arg_t threads_args[] = { SB_OPT("thread-yields", "number of yields to do per request", "1000", INT), SB_OPT("thread-locks", "number of locks per thread", "8", INT), SB_OPT_END }; /* Threads test operations */ static int threads_init(void); static int threads_prepare(void); static void threads_print_mode(void); static sb_event_t threads_next_event(int); static int threads_execute_event(sb_event_t *, int); static int threads_cleanup(void); static sb_test_t threads_test = { .sname = "threads", .lname = "Threads subsystem performance test", .ops = { .init = threads_init, .prepare = threads_prepare, .print_mode = threads_print_mode, .next_event = threads_next_event, .execute_event = threads_execute_event, .cleanup = threads_cleanup }, .args = threads_args }; static unsigned int thread_yields; static unsigned int thread_locks; static pthread_mutex_t *test_mutexes; static unsigned int req_performed; int register_test_threads(sb_list_t *tests) { SB_LIST_ADD_TAIL(&threads_test.listitem, tests); return 0; } int threads_init(void) { thread_yields = sb_get_value_int("thread-yields"); thread_locks = sb_get_value_int("thread-locks"); req_performed = 0; return 0; } int threads_prepare(void) { unsigned int i; test_mutexes = (pthread_mutex_t *)malloc(thread_locks * sizeof(pthread_mutex_t)); if (test_mutexes == NULL) { log_text(LOG_FATAL, "Memory allocation failure!"); return 1; } for(i = 0; i < thread_locks; i++) pthread_mutex_init(test_mutexes + i, NULL); return 0; } int threads_cleanup(void) { unsigned int i; for(i=0; i < thread_locks; i++) pthread_mutex_destroy(test_mutexes + i); free(test_mutexes); return 0; } sb_event_t threads_next_event(int thread_id) { sb_event_t sb_req; sb_threads_request_t *threads_req = &sb_req.u.threads_request; (void) thread_id; /* unused */ sb_req.type = SB_REQ_TYPE_THREADS; threads_req->lock_num = ck_pr_faa_uint(&req_performed, 1) % thread_locks; return sb_req; } int threads_execute_event(sb_event_t *sb_req, int thread_id) { unsigned int i; sb_threads_request_t *threads_req = &sb_req->u.threads_request; (void) thread_id; /* unused */ for(i = 0; i < thread_yields; i++) { pthread_mutex_lock(&test_mutexes[threads_req->lock_num]); YIELD(); pthread_mutex_unlock(&test_mutexes[threads_req->lock_num]); } return 0; } void threads_print_mode(void) { log_text(LOG_INFO, "Doing thread subsystem performance test"); log_text(LOG_INFO, "Thread yields per test: %d Locks used: %d", thread_yields, thread_locks); } ================================================ FILE: src/xoroshiro128plus.h ================================================ /* Code below is based on the original work with the following copyright notice: */ /* Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org) To the extent possible under law, the author has dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. See . */ #include /* This is the successor to xorshift128+. It is the fastest full-period generator passing BigCrush without systematic failures, but due to the relatively short period it is acceptable only for applications with a mild amount of parallelism; otherwise, use a xorshift1024* generator. Beside passing BigCrush, this generator passes the PractRand test suite up to (and included) 16TB, with the exception of binary rank tests, which fail due to the lowest bit being an LFSR; all other bits pass all tests. We suggest to use a sign test to extract a random Boolean value. Note that the generator uses a simulated rotate operation, which most C compilers will turn into a single instruction. In Java, you can use Long.rotateLeft(). In languages that do not make low-level rotation instructions accessible xorshift128+ could be faster. The state must be seeded so that it is not everywhere zero. If you have a 64-bit seed, we suggest to seed a splitmix64 generator and use its output to fill s. */ inline uint64_t xoroshiro_rotl(const uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } inline uint64_t xoroshiro_next(uint64_t s[2]) { const uint64_t s0 = s[0]; uint64_t s1 = s[1]; const uint64_t result = s0 + s1; s1 ^= s0; s[0] = xoroshiro_rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b s[1] = xoroshiro_rotl(s1, 36); // c return result; } /* This is the jump function for the generator. It is equivalent to 2^64 calls to next(); it can be used to generate 2^64 non-overlapping subsequences for parallel computations. */ static inline void xoroshiro_jump(uint64_t s[2]) { static const uint64_t JUMP[] = { 0xbeac0467eba5facb, 0xd86b048b86aa9922 }; uint64_t s0 = 0; uint64_t s1 = 0; int i, b; for(i = 0; i < (int) (sizeof JUMP / sizeof *JUMP); i++) for(b = 0; b < 64; b++) { if (JUMP[i] & 1ULL << b) { s0 ^= s[0]; s1 ^= s[1]; } xoroshiro_next(s); } s[0] = s0; s[1] = s1; } ================================================ FILE: tests/Makefile.am ================================================ # Copyright (C) 2016-2018 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA AM_TESTS_ENVIRONMENT = \ PATH="$(top_srcdir)/third_party/cram/scripts:$$PATH" \ PYTHONPATH="$(top_srcdir)/third_party/cram:$$PYTHONPATH" TESTS = test_run.sh test_SCRIPTS = test_run.sh EXTRA_DIST = $(test_SCRIPTS) \ README.md testroot = $(datadir) testdir = $(testroot)/sysbench/tests test_dirs= t include # Used by dist-hook and install-data-local to copy all # test files into either dist or install directory install_test_files: @if test -z "$(INSTALL_TO_DIR)"; then \ echo "Set INSTALL_TO_DIR!" && exit 1; \ fi @for dir in $(test_dirs); do \ from_dir="$(srcdir)/$$dir"; \ to_dir="$(INSTALL_TO_DIR)/$$dir"; \ $(mkinstalldirs) "$$to_dir"; \ for f in `(cd $$from_dir && ls *.t *.sh *.lua) 2>/dev/null`; do \ if test -f "$$from_dir/$$f"; then \ $(INSTALL_DATA) "$$from_dir/$$f" "$$to_dir/$$f" ; \ fi; \ done \ done dist-hook: $(MAKE) INSTALL_TO_DIR="$(distdir)" install_test_files install-data-local: $(MAKE) INSTALL_TO_DIR="$(DESTDIR)$(testdir)" install_test_files uninstall-local: rm -f -r $(DESTDIR)$(testdir) test: ./test_run.sh ================================================ FILE: tests/README.md ================================================ sysbench Test Suite =================== sysbench uses the [Cram](https://bitheap.org/cram/) framework for functional and regression testing. If your system has Python 2.7.9 or later, or Python 3.4 or later, installing Cram is as simple as executing `pip install cram`. If you use an older Python version, you may need to [install pip](https://pip.pypa.io/en/latest/installing/) first: ``` {.example} curl https://bootstrap.pypa.io/get-pip.py | python ``` To run the sysbench test suite, invoke the `test_run.sh` script in the `tests` directory as follows: ``` {.example} ./test_run.sh [test_name]... ``` Each `test_name` argument is a name of a test case file. Functional and regression tests are located in the `t` subdirectory in files with the `.t` suffix. If no tests are named on the `test_run.sh` command line, it will execute all files with the `.t` suffix in the `t` subdirectory. Some tests require external servers (MySQL, PostgreSQL, etc). One should use environment variables to specify connection related arguments that sysbench can use to connect to such external server(s). The currently recognized variables are: - `SBTEST_MYSQL_ARGS` -- MySQL connection options: `--mysql-host`, `--mysql-port`, `--mysql-socket` `--mysql-user`, `--mysql-password` and `--mysql-db`; - `SBTEST_PGSQL_ARGS` -- PostgreSQL connection options: `--pgsql-host`, `--pgsql-port`, `--pgsql-user`, `--pgsql-password` and `--pgsql-db`. For example: ``` {.example} export SBTEST_MYSQL_ARGS="--mysql-host=localhost --mysql-user=sbtest --mysql-password=secret --mysql-db=sbtest" export SBTEST_PGSQL_ARGS="--pgsql-host=localhost --pgsql-user=postgres --pgsql-password=secret --pgsql-db=sbtest" ./test_run.sh ``` sysbench assumes that server(s) are pre-configured so that the specified database exists and the user connecting with the specified credentials has all privileges on the database. In particular, sysbench must have enough privileges to create/drop/read/modify tables in that database. ================================================ FILE: tests/include/api_sql_common.sh ================================================ ######################################################################## # Common code for SQL API tests # # Expects the following variables and callback functions to be defined by the # caller: # # DB_DRIVER_ARGS -- extra driver-specific arguments to pass to sysbench # ######################################################################## set -eu SB_ARGS="--verbosity=1 --events=1 $DB_DRIVER_ARGS $CRAMTMP/api_sql.lua" cat >$CRAMTMP/api_sql.lua <$CRAMTMP/api_sql.lua <$CRAMTMP/api_sql.lua <$CRAMTMP/api_sql.lua <$CRAMTMP/api_sql.lua <$CRAMTMP/api_sql.lua <$CRAMTMP/api_sql.lua <$CRAMTMP/api_sql.lua < # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA export SBTEST_VERSION_STRING="sysbench @PACKAGE_VERSION@@SB_GIT_SHA@" export SBTEST_VERSION="@PACKAGE_VERSION@" export SBTEST_HAS_MYSQL=@USE_MYSQL@ export SBTEST_HAS_PGSQL=@USE_PGSQL@ ================================================ FILE: tests/include/drv_common.sh ================================================ #!/usr/bin/env bash # ######################################################################### # Common code for DB driver tests # Variables: # DB_DRIVER_ARGS -- extra driver-specific arguments to pass to sysbench ######################################################################### set -eu cat >test.lua < '\\a', \0 => '\\0', 31 => '\31' local shortControlCharEscapes = { ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v" } local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031 for i=0, 31 do local ch = string.char(i) if not shortControlCharEscapes[ch] then shortControlCharEscapes[ch] = "\\"..i longControlCharEscapes[ch] = string.format("\\%03d", i) end end local function escape(str) return (str:gsub("\\", "\\\\") :gsub("(%c)%f[0-9]", longControlCharEscapes) :gsub("%c", shortControlCharEscapes)) end local function isIdentifier(str) return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" ) end local function isSequenceKey(k, sequenceLength) return type(k) == 'number' and 1 <= k and k <= sequenceLength and math.floor(k) == k end local defaultTypeOrders = { ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, ['function'] = 5, ['userdata'] = 6, ['thread'] = 7 } local function sortKeys(a, b) local ta, tb = type(a), type(b) -- strings and numbers are sorted numerically/alphabetically if ta == tb and (ta == 'string' or ta == 'number') then return a < b end local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb] -- Two default types are compared according to the defaultTypeOrders table if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb] elseif dta then return true -- default types before custom ones elseif dtb then return false -- custom types after default ones end -- custom types are sorted out alphabetically return ta < tb end -- For implementation reasons, the behavior of rawlen & # is "undefined" when -- tables aren't pure sequences. So we implement our own # operator. local function getSequenceLength(t) local len = 1 local v = rawget(t,len) while v ~= nil do len = len + 1 v = rawget(t,len) end return len - 1 end local function getNonSequentialKeys(t) local keys = {} local sequenceLength = getSequenceLength(t) for k,_ in pairs(t) do if not isSequenceKey(k, sequenceLength) then table.insert(keys, k) end end table.sort(keys, sortKeys) return keys, sequenceLength end local function getToStringResultSafely(t, mt) local __tostring = type(mt) == 'table' and rawget(mt, '__tostring') local str, ok if type(__tostring) == 'function' then ok, str = pcall(__tostring, t) str = ok and str or 'error: ' .. tostring(str) end if type(str) == 'string' and #str > 0 then return str end end local function countTableAppearances(t, tableAppearances) tableAppearances = tableAppearances or {} if type(t) == 'table' then if not tableAppearances[t] then tableAppearances[t] = 1 for k,v in pairs(t) do countTableAppearances(k, tableAppearances) countTableAppearances(v, tableAppearances) end countTableAppearances(getmetatable(t), tableAppearances) else tableAppearances[t] = tableAppearances[t] + 1 end end return tableAppearances end local copySequence = function(s) local copy, len = {}, #s for i=1, len do copy[i] = s[i] end return copy, len end local function makePath(path, ...) local keys = {...} local newPath, len = copySequence(path) for i=1, #keys do newPath[len + i] = keys[i] end return newPath end local function processRecursive(process, item, path, visited) if item == nil then return nil end if visited[item] then return visited[item] end local processed = process(item, path) if type(processed) == 'table' then local processedCopy = {} visited[item] = processedCopy local processedKey for k,v in pairs(processed) do processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) if processedKey ~= nil then processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) end end local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) setmetatable(processedCopy, mt) processed = processedCopy end return processed end ------------------------------------------------------------------- local Inspector = {} local Inspector_mt = {__index = Inspector} function Inspector:puts(...) local args = {...} local buffer = self.buffer local len = #buffer for i=1, #args do len = len + 1 buffer[len] = args[i] end end function Inspector:down(f) self.level = self.level + 1 f() self.level = self.level - 1 end function Inspector:tabify() self:puts(self.newline, string.rep(self.indent, self.level)) end function Inspector:alreadyVisited(v) return self.ids[v] ~= nil end function Inspector:getId(v) local id = self.ids[v] if not id then local tv = type(v) id = (self.maxIds[tv] or 0) + 1 self.maxIds[tv] = id self.ids[v] = id end return tostring(id) end function Inspector:putKey(k) if isIdentifier(k) then return self:puts(k) end self:puts("[") self:putValue(k) self:puts("]") end function Inspector:putTable(t) if t == inspect.KEY or t == inspect.METATABLE then self:puts(tostring(t)) elseif self:alreadyVisited(t) then self:puts('') elseif self.level >= self.depth then self:puts('{...}') else if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end local nonSequentialKeys, sequenceLength = getNonSequentialKeys(t) local mt = getmetatable(t) local toStringResult = getToStringResultSafely(t, mt) self:puts('{') self:down(function() if toStringResult then self:puts(' -- ', escape(toStringResult)) if sequenceLength >= 1 then self:tabify() end end local count = 0 for i=1, sequenceLength do if count > 0 then self:puts(',') end self:puts(' ') self:putValue(t[i]) count = count + 1 end for _,k in ipairs(nonSequentialKeys) do if count > 0 then self:puts(',') end self:tabify() self:putKey(k) self:puts(' = ') self:putValue(t[k]) count = count + 1 end if mt then if count > 0 then self:puts(',') end self:tabify() self:puts(' = ') self:putValue(mt) end end) if #nonSequentialKeys > 0 or mt then -- result is multi-lined. Justify closing } self:tabify() elseif sequenceLength > 0 then -- array tables have one extra space before closing } self:puts(' ') end self:puts('}') end end function Inspector:putValue(v) local tv = type(v) if tv == 'string' then self:puts(smartQuote(escape(v))) elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or tv == 'cdata' or tv == 'ctype' then self:puts(tostring(v)) elseif tv == 'table' then self:putTable(v) else self:puts('<',tv,' ',self:getId(v),'>') end end ------------------------------------------------------------------- function inspect.inspect(root, options) options = options or {} local depth = options.depth or math.huge local newline = options.newline or '\n' local indent = options.indent or ' ' local process = options.process if process then root = processRecursive(process, root, {}, {}) end local inspector = setmetatable({ depth = depth, level = 0, buffer = {}, ids = {}, maxIds = {}, newline = newline, indent = indent, tableAppearances = countTableAppearances(root) }, Inspector_mt) inspector:putValue(root) return table.concat(inspector.buffer) end setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end }) return inspect ================================================ FILE: tests/include/mysql_common.sh ================================================ ######################################################################## # Common code for MySQL-specific tests ######################################################################## set -eu if [ -z "${SBTEST_MYSQL_ARGS:-}" ] then exit 80 fi function db_show_table() { mysql -uroot sbtest -Nse "SHOW CREATE TABLE $1\G" } DB_DRIVER_ARGS="--db-driver=mysql $SBTEST_MYSQL_ARGS" ================================================ FILE: tests/include/pgsql_common.sh ================================================ ######################################################################## # Common code for PostgreSQL-specific tests ######################################################################## set -eu if [ -z "${SBTEST_PGSQL_ARGS:-}" ] then exit 80 fi # Emulate "\d+" output since it is not portable across PostgreSQL major versions function db_show_table() { if ! psql -c "\d+ $1" sbtest > /dev/null then return fi echo " Table \"public.$1\"" psql -q sbtest < 0 EOF echo "Indexes:" psql -qt sbtest </dev/null db_show_table sbtest1 db_show_table sbtest2 db_show_table sbtest3 db_show_table sbtest4 db_show_table sbtest5 db_show_table sbtest6 db_show_table sbtest7 db_show_table sbtest8 db_show_table sbtest9 || true # Error on non-existing table sysbench $ARGS prewarm >/dev/null || true # MySQL only sysbench --events=100 $ARGS run sysbench $ARGS cleanup >/dev/null db_show_table sbtest1 || true # Error on non-existing table db_show_table sbtest2 || true # Error on non-existing table db_show_table sbtest3 || true # Error on non-existing table db_show_table sbtest4 || true # Error on non-existing table db_show_table sbtest5 || true # Error on non-existing table db_show_table sbtest6 || true # Error on non-existing table db_show_table sbtest7 || true # Error on non-existing table db_show_table sbtest8 || true # Error on non-existing table echo "# Test --create-secondary=off" ARGS="${OLTP_SCRIPT_PATH} ${DB_DRIVER_ARGS} ${SB_EXTRA_ARGS} --tables=1" sysbench --create-secondary=off $ARGS prepare db_show_table sbtest1 sysbench $ARGS cleanup echo "# Test --auto-inc=off" ARGS="$ARGS --auto-inc=off --verbosity=1" sysbench $ARGS prepare sysbench $ARGS run sysbench $ARGS cleanup echo "# Test --reconnect" ARGS="${OLTP_SCRIPT_PATH} ${DB_DRIVER_ARGS} ${SB_EXTRA_ARGS} --events=100 \ --reconnect=5" sysbench $ARGS prepare >/dev/null || true sysbench $ARGS run | grep reconnects: sysbench $ARGS cleanup >/dev/null || true ================================================ FILE: tests/include/script_select_random_common.sh ================================================ #!/usr/bin/env bash # ################################################################################ # Common code for select_random_* tests # # Expects the following variables and callback functions to be defined by the # caller: # # DB_DRIVER_ARGS -- extra driver-specific arguments to pass to sysbench # # db_show_table() -- called with a single argument to dump a specified table # schema ################################################################################ set -eu for test in select_random_points select_random_ranges do ARGS="${SBTEST_SCRIPTDIR}/${test}.lua $DB_DRIVER_ARGS --tables=1" sysbench $ARGS prepare db_show_table sbtest1 for i in $(seq 2 8) do db_show_table sbtest${i} || true # Error on non-existing table done sysbench $ARGS --events=100 run sysbench $ARGS cleanup for i in $(seq 1 8) do db_show_table sbtest${i} || true # Error on non-existing table done ARGS="${SBTEST_SCRIPTDIR}/select_random_points.lua $DB_DRIVER_ARGS --tables=8" done ================================================ FILE: tests/t/1st.t ================================================ # Ensure the sysbench binary exists in PATH and is executable $ sysbench --help >/dev/null 2>&1 ================================================ FILE: tests/t/api_basic.t ================================================ ######################################################################## Basic Lua API tests ######################################################################## $ SB_ARGS="--verbosity=0 --events=2 --db-driver=mysql $SBTEST_MYSQL_ARGS $CRAMTMP/api_basic.lua" $ cat >$CRAMTMP/api_basic.lua < function init(thread_id) > print("tid:" .. (thread_id or "(nil)") .. " init()") > end > > function prepare(thread_id) > print("tid:" .. (thread_id or "(nil)") .. " prepare()") > end > > function run(thread_id) > print("tid:" .. (thread_id or "(nil)") .. " run()") > end > > function cleanup(thread_id) > print("tid:" .. (thread_id or "(nil)") .. " cleanup()") > end > > function help(thread_id) > print("tid:" .. (thread_id or "(nil)") .. " help()") > end > > function thread_init(thread_id) > print(string.format("tid:%d thread_init()", thread_id)) > end > > function event(thread_id) > print(string.format("tid:%d event()", thread_id)) > end > > function thread_done(thread_id) > print(string.format("tid:%d thread_done()", thread_id)) > end > > function done(thread_id) > print("tid:" .. (thread_id or "(nil)") .. " done()") > end > > EOF $ sysbench $SB_ARGS prepare tid:(nil) prepare() $ sysbench $SB_ARGS run tid:(nil) init() tid:0 thread_init() tid:0 event() tid:0 event() tid:0 thread_done() tid:(nil) done() $ sysbench $SB_ARGS cleanup tid:(nil) cleanup() $ sysbench $SB_ARGS help tid:(nil) help() $ cat >$CRAMTMP/api_basic.lua < function event() > print(sysbench.version) > print(sysbench.version_string) > end > EOF $ sysbench $SB_ARGS --events=1 run | > sed -e "s/$SBTEST_VERSION_STRING/VERSION_STRING/" \ > -e "s/$SBTEST_VERSION/VERSION/" VERSION VERSION_STRING $ cat >$CRAMTMP/api_basic.lua < function event() > print(string.format("sysbench.cmdline.script_path = %s", sysbench.cmdline.script_path)) > end > EOF $ sysbench $SB_ARGS --events=1 run sysbench.cmdline.script_path = */api_basic.lua (glob) ######################################################################## Error handling ######################################################################## # Syntax errors in the script $ cat >$CRAMTMP/api_basic.lua < foo > EOF $ sysbench $SB_ARGS run FATAL: */api_basic.lua:2: '=' expected near '' (glob) [1] # Missing event function $ cat >$CRAMTMP/api_basic.lua < function foo() > end > EOF $ sysbench $SB_ARGS run FATAL: cannot find the event() function in *api_basic.lua (glob) [1] ######################################################################## event() return values ######################################################################## $ cat >$CRAMTMP/api_basic.lua < sysbench.cmdline.options = { param = {"param", 0} } > function event() > i = (i or 0) + 1 > local param = sysbench.opt.param > print(i) > if param == 1 then > return 0 > elseif param == 2 then > return 1 > elseif param == 3 then > return true > elseif param == 4 then > return {} > elseif param == 5 then > return false > elseif param == 6 then > return nil > else > error("Unknown param value") > end > end > EOF $ sysbench $SB_ARGS run --param=1 1 $ sysbench $SB_ARGS run --param=2 1 $ sysbench $SB_ARGS run --param=3 1 $ sysbench $SB_ARGS run --param=4 1 $ sysbench $SB_ARGS run --param=5 1 2 $ sysbench $SB_ARGS run --param=6 1 2 ================================================ FILE: tests/t/api_histogram.t ================================================ ######################################################################## Tests for histogram API ######################################################################## $ sysbench < h = sysbench.histogram.new(1000, 1, 10) > h:update(1) > h:update(2) > h:update(0) > h:update(10) > h:update(100) > h:update(5.001) > h:print() > EOF sysbench * (glob) value ------------- distribution ------------- count 1.000 |**************************************** 2 2.001 |******************** 1 4.997 |******************** 1 10.000 |**************************************** 2 ================================================ FILE: tests/t/api_rand.t ================================================ ######################################################################## PRNG Lua API tests ######################################################################## $ SB_ARGS="--verbosity=0 --events=1" $ cat >$CRAMTMP/api_rand.lua < ffi.cdef[[int printf(const char *fmt, ...);]] > function init() > -- Ensure a consistent sort order... > mod_funcs = {} > for f in pairs(sysbench.rand) do > table.insert(mod_funcs, f) > end > table.sort(mod_funcs) > for i, f in ipairs(mod_funcs) do > print(string.format("sysbench.rand.%s", f)) > end > end > function event() > print("sysbench.rand.default(0, 99) = " .. sysbench.rand.default(0, 99)) > print("sysbench.rand.unique(0, 4294967295) = " .. sysbench.rand.unique(0, 4294967295)) > ffi.C.printf("sysbench.rand.uniform_uint64() = %llu\n", sysbench.rand.uniform_uint64()) > print([[sysbench.rand.string("abc-###-@@@-xyz") = ]] .. sysbench.rand.string("abc-###-@@@-xyz")) > print([[sysbench.rand.varstring(1, 23) = ]] .. sysbench.rand.varstring(1, 23)) > print("sysbench.rand.uniform(0, 99) = " .. sysbench.rand.uniform(0, 99)) > print("sysbench.rand.gaussian(0, 99) = " .. sysbench.rand.gaussian(0, 99)) > print("sysbench.rand.pareto(0, 99) = " .. sysbench.rand.pareto(0, 99)) > print("sysbench.rand.zipfian(0, 99) = " .. sysbench.rand.zipfian(0, 99)) > end > EOF $ sysbench $SB_ARGS $CRAMTMP/api_rand.lua run sysbench.rand.default sysbench.rand.gaussian sysbench.rand.pareto sysbench.rand.string sysbench.rand.uniform sysbench.rand.uniform_double sysbench.rand.uniform_uint64 sysbench.rand.unique sysbench.rand.varstring sysbench.rand.zipfian sysbench.rand.default\(0, 99\) = [0-9]{1,2} (re) sysbench.rand.unique\(0, 4294967295\) = [0-9]{1,10} (re) sysbench.rand.uniform_uint64\(\) = [0-9]+ (re) sysbench.rand.string\(".*"\) = abc-[0-9]{3}-[a-z]{3}-xyz (re) sysbench.rand.varstring\(1, 23\) = [0-z]{1,23} (re) sysbench.rand.uniform\(0, 99\) = [0-9]{1,2} (re) sysbench.rand.gaussian\(0, 99\) = [0-9]{1,2} (re) sysbench.rand.pareto\(0, 99\) = [0-9]{1,2} (re) sysbench.rand.zipfian\(0, 99\) = [0-9]{1,2} (re) ######################################################################## GH-96: sb_rand_uniq(1, oltp_table_size) generate duplicate value ######################################################################## $ cat >$CRAMTMP/api_rand_uniq.lua < function event() > print(sysbench.rand.unique()) > end > EOF $ sysbench $SB_ARGS --events=100000 $CRAMTMP/api_rand_uniq.lua run | > sort -n | uniq | wc -l | sed -e 's/ //g' 100000 ================================================ FILE: tests/t/api_reports.t ================================================ ######################################################################## Tests for custom report hooks ######################################################################## # Trigger one intermediate and one cumulative report $ SB_ARGS="api_reports.lua --time=5 --report-interval=2 --verbosity=1" ######################################################################## # Default human-readable format via a custom hook ######################################################################## $ cat >api_reports.lua < ffi.cdef[[int usleep(unsigned int);]] > > function event() > ffi.C.usleep(1000) > end > > sysbench.hooks.report_intermediate = sysbench.report_default > sysbench.hooks.report_cumulative = sysbench.report_default > EOF $ sysbench $SB_ARGS run \[ 2s \] thds: 1 tps: [0-9]*\.[0-9]* qps: 0\.00 \(r\/w\/o: 0\.00\/0\.00\/0\.00\) lat \(ms,95%\): [1-9][0-9]*\.[0-9]* err\/s 0\.00 reconn\/s: 0\.00 (re) \[ 4s \] thds: 1 tps: [0-9]*\.[0-9]* qps: 0\.00 \(r\/w\/o: 0\.00\/0\.00\/0\.00\) lat \(ms,95%\): [1-9][0-9]*\.[0-9]* err\/s 0\.00 reconn\/s: 0\.00 (re) \[ 5s \] thds: 0 tps: [0-9]*\.[0-9]* qps: 0\.00 \(r\/w\/o: 0\.00\/0\.00\/0\.00\) lat \(ms,95%\): [1-9][0-9]*\.[0-9]* err\/s 0\.00 reconn\/s: 0\.00 (re) ######################################################################## # CSV format via a custom hook ######################################################################## $ cat >api_reports.lua < ffi.cdef[[int usleep(unsigned int);]] > > function event() > ffi.C.usleep(1000) > end > > sysbench.hooks.report_intermediate = sysbench.report_csv > sysbench.hooks.report_cumulative = sysbench.report_csv > EOF $ sysbench $SB_ARGS run 2,1,[0-9]*\.[0-9]*,0\.00,0\.00,0\.00,0\.00,[1-9][0-9]*\.[0-9]*,0\.00,0\.00 (re) 4,1,[0-9]*\.[0-9]*,0\.00,0\.00,0\.00,0\.00,[1-9][0-9]*\.[0-9]*,0\.00,0\.00 (re) 5,0,[0-9]*\.[0-9]*,0\.00,0\.00,0\.00,0\.00,[1-9][0-9]*\.[0-9]*,0\.00,0\.00 (re) ######################################################################## # JSON format via a custom hook ######################################################################## $ cat >api_reports.lua < ffi.cdef[[int usleep(unsigned int);]] > > function event() > ffi.C.usleep(1000) > end > > sysbench.hooks.report_intermediate = sysbench.report_json > sysbench.hooks.report_cumulative = sysbench.report_json > EOF $ sysbench $SB_ARGS run [ { "time": 2, "threads": 1, "tps": *.*, (glob) "qps": { "total": 0.00, "reads": 0.00, "writes": 0.00, "other": 0.00 }, "latency": [1-9][0-9]*\.[0-9]*, (re) "errors": 0.00, "reconnects": 0.00 }, { "time": 4, "threads": 1, "tps": *.*, (glob) "qps": { "total": 0.00, "reads": 0.00, "writes": 0.00, "other": 0.00 }, "latency": [1-9][0-9]*\.[0-9]*, (re) "errors": 0.00, "reconnects": 0.00 } ] [ { "time": 5, "threads": 0, "tps": *.*, (glob) "qps": { "total": 0.00, "reads": 0.00, "writes": 0.00, "other": 0.00 }, "latency": [1-9][0-9]*\.[0-9]*, (re) "errors": 0.00, "reconnects": 0.00 } ] ================================================ FILE: tests/t/api_sql_mysql.t ================================================ ######################################################################## SQL Lua API + MySQL tests ######################################################################## $ . ${SBTEST_INCDIR}/mysql_common.sh $ . ${SBTEST_INCDIR}/api_sql_common.sh drv:name() = mysql SQL types: { BIGINT = 4, CHAR = 11, DATE = 8, DATETIME = 9, DOUBLE = 6, FLOAT = 5, INT = 3, NONE = 0, SMALLINT = 2, TIME = 7, TIMESTAMP = 10, TINYINT = 1, VARCHAR = 12 } -- SQL error codes: { FATAL = 2, IGNORABLE = 1, NONE = 0 } -- FATAL: invalid database driver name: 'non-existing' failed to initialize the DB driver 100 -- -- nil bar 0.2 nil nil 0.1 1 foo 0.4 2 nil 0.3 -- nil 2 -- FATAL: mysql_stmt_prepare() failed FATAL: MySQL error: 1146 "Table 'sbtest.nonexisting' doesn't exist" SQL API error -- Unsupported argument type: 8 nil ALERT: attempt to free an invalid result set db_free_results() failed db_free_results() failed db_free_results() failed 601\t0987654321\t0.9 (esc) -- (last message repeated 2 times) ALERT: attempt to use an already closed connection */api_sql.lua:*: SQL API error (glob) ALERT: attempt to close an already closed connection -- 4 601 700 0987654321 0987654321 -- 1 2 -- reconnects = 1 FATAL: unable to connect to MySQL server on host 'non-existing', port 3306, aborting... FATAL: error 2005: Unknown MySQL server host 'non-existing' (0) connection creation failed -- FATAL: mysql_drv_query() returned error 1048 (Column 'a' cannot be null) for query 'INSERT INTO t VALUES (NULL)' Got an error descriptor: { connection = , query = "INSERT INTO t VALUES (NULL)", sql_errmsg = "Column 'a' cannot be null", sql_errno = 1048, sql_state = "23000" } */api_sql.lua:*: SQL error, errno = 1048, state = '23000': Column 'a' cannot be null (glob) FATAL: mysql_drv_query() returned error 1406 (Data too long for column 'a' at row 1) for query 'INSERT INTO t VALUES ('test')' Got an error descriptor: { connection = , query = "INSERT INTO t VALUES ('test')", sql_errmsg = "Data too long for column 'a' at row 1", sql_errno = 1406, sql_state = "22001" } */api_sql.lua:*: SQL error, errno = 1406, state = '22001': Data too long for column 'a' at row 1 (glob) FATAL: mysql_drv_query() returned error 1051 (Unknown table '*t') for query 'DROP TABLE t' (glob) Got an error descriptor: { connection = , query = "DROP TABLE t", sql_errmsg = "Unknown table 'sbtest.t'", sql_errno = 1051, sql_state = "42S02" } */api_sql.lua:*: SQL error, errno = 1051, state = '42S02': Unknown table '*t' (glob) -- ######################################################################## # Multiple connections test ######################################################################## 1 2 3 4 5 6 7 8 9 10 ######################################################################## # Incorrect bulk API usage ######################################################################## ALERT: attempt to call bulk_insert_next() before bulk_insert_init() */api_sql.lua:*: db_bulk_insert_next() failed (glob) ######################################################################## # query_row() with an empty result set ######################################################################## nil ######################################################################## # GH-282: Mysql's fetch_row() is broken ######################################################################## 1 2 ######################################################################## # GH-304: Benchmark Stored Procedure with sysbench ######################################################################## $ cat >api_sql.lua < con = sysbench.sql.driver():connect() > > con:query([[ > CREATE PROCEDURE p1 (IN txt VARCHAR(255)) > BEGIN > SELECT 'begin:', txt; > INSERT INTO t1 VALUES(1); > SELECT * FROM t1; > DELETE FROM t1 WHERE a = 1; > SELECT 'done'; > END > ]]) > > con:query("CREATE TABLE t1(a INT)") > > stmt = con:prepare("CALL p1(?)") > param = stmt:bind_create(sysbench.sql.type.CHAR, 10) > stmt:bind_param(param) > > function print_rs(rs) > if rs == nil then return end > print(rs.nrows) > print(rs.nfields) > for i = 1, rs.nrows do > print(unpack(rs:fetch_row(), 1, rs.nfields)) > end > end > > local rs = con:query([[CALL p1("foo")]]) > while rs ~= nil do > print_rs(rs) > rs = con:next_result() > end > > param:set("bar") > rs = stmt:execute() > while rs ~= nil do > rs = stmt:next_result() > end > > con:query("DROP PROCEDURE IF EXISTS p1"); > con:query("DROP TABLE IF EXISTS t1"); > EOF $ sysbench $DB_DRIVER_ARGS --verbosity=1 api_sql.lua 1 2 begin:\tfoo (esc) 1 1 1 1 1 done ================================================ FILE: tests/t/api_sql_pgsql.t ================================================ ######################################################################## SQL Lua API + PostgreSQL tests ######################################################################## $ . ${SBTEST_INCDIR}/pgsql_common.sh $ . ${SBTEST_INCDIR}/api_sql_common.sh drv:name() = pgsql SQL types: { BIGINT = 4, CHAR = 11, DATE = 8, DATETIME = 9, DOUBLE = 6, FLOAT = 5, INT = 3, NONE = 0, SMALLINT = 2, TIME = 7, TIMESTAMP = 10, TINYINT = 1, VARCHAR = 12 } -- SQL error codes: { FATAL = 2, IGNORABLE = 1, NONE = 0 } -- FATAL: invalid database driver name: 'non-existing' failed to initialize the DB driver 100 -- -- 1 foo 0.4 2 nil 0.3 nil bar 0.2 nil nil 0.1 -- bar nil -- FATAL: PQprepare() failed: ERROR: relation "nonexisting" does not exist LINE 1: SELECT * FROM nonexisting ^ SQL API error -- Unsupported argument type: 8 nil ALERT: attempt to free an invalid result set db_free_results() failed db_free_results() failed db_free_results() failed 601\t0987654321\t0.9 (esc) -- (last message repeated 2 times) ALERT: attempt to use an already closed connection */api_sql.lua:*: SQL API error (glob) ALERT: attempt to close an already closed connection -- 4 601 700 0987654321 0987654321 -- 1 2 -- reconnects = 1 FATAL: Connection to database failed: could not translate host name "non-existing" to address: * (glob) connection creation failed -- FATAL: PQexec() failed: 7 null value in column "a" *violates not-null constraint (glob) FATAL: failed query was: INSERT INTO t VALUES (NULL) Got an error descriptor: { connection = , query = "INSERT INTO t VALUES (NULL)", sql_errmsg = 'null value in column "a" *violates not-null constraint', (glob) sql_errno = 0, sql_state = "23502" } */api_sql.lua:*: SQL error, errno = 0, state = '23502': null value in column "a" *violates not-null constraint (glob) FATAL: PQexec() failed: 7 value too long for type character(1) FATAL: failed query was: INSERT INTO t VALUES ('test') Got an error descriptor: { connection = , query = "INSERT INTO t VALUES ('test')", sql_errmsg = "value too long for type character(1)", sql_errno = 0, sql_state = "22001" } */api_sql.lua:*: SQL error, errno = 0, state = '22001': value too long for type character(1) (glob) FATAL: PQexec() failed: 7 table "t" does not exist FATAL: failed query was: DROP TABLE t Got an error descriptor: { connection = , query = "DROP TABLE t", sql_errmsg = 'table "t" does not exist', sql_errno = 0, sql_state = "42P01" } */api_sql.lua:*: SQL error, errno = 0, state = '42P01': table "t" does not exist (glob) -- ######################################################################## # Multiple connections test ######################################################################## 1 2 3 4 5 6 7 8 9 10 ######################################################################## # Incorrect bulk API usage ######################################################################## ALERT: attempt to call bulk_insert_next() before bulk_insert_init() */api_sql.lua:*: db_bulk_insert_next() failed (glob) ######################################################################## # query_row() with an empty result set ######################################################################## nil ######################################################################## # GH-282: Mysql's fetch_row() is broken ######################################################################## 1 2 ================================================ FILE: tests/t/cmd_cleanup.t ================================================ $ sysbench cleanup sysbench * (glob) FATAL: Cannot find benchmark 'cleanup': no such built-in test, file or module [1] $ cat >cmd_cleanup.lua < function cleanup() > print('function cleanup()') > end > EOF $ sysbench cmd_cleanup.lua cleanup sysbench * (glob) function cleanup() ================================================ FILE: tests/t/cmd_help.t ================================================ $ sysbench help sysbench * (glob) FATAL: Cannot find benchmark 'help': no such built-in test, file or module [1] $ cat >cmd_help.lua < function help() > print('function help()') > end > EOF $ sysbench cmd_help.lua help sysbench * (glob) function help() ================================================ FILE: tests/t/cmd_prepare.t ================================================ $ sysbench prepare sysbench * (glob) FATAL: Cannot find benchmark 'prepare': no such built-in test, file or module [1] $ cat >cmd_prepare.lua < function prepare() > print('function prepare()') > end > EOF $ sysbench cmd_prepare.lua prepare sysbench * (glob) function prepare() ================================================ FILE: tests/t/cmd_run.t ================================================ $ sysbench run sysbench * (glob) FATAL: Cannot find benchmark 'run': no such built-in test, file or module [1] $ cat >cmd_run.lua < function thread_run() > print('function thread_run()') > end > function event() > end > EOF $ sysbench --verbosity=0 cmd_run.lua run function thread_run() ================================================ FILE: tests/t/cmdline.t ================================================ ######################################################################## # Command line syntax tests ######################################################################## $ sysbench foo bar sysbench * (glob) FATAL: Cannot find benchmark 'foo': no such built-in test, file or module [1] $ sysbench foo bar baz Unrecognized command line argument: baz [1] $ sysbench --unknown < EOF sysbench * (glob) $ sysbench fileio sysbench * (glob) The 'fileio' test requires a command argument. See 'sysbench fileio help' [1] $ sysbench --help foo | grep Usage: Usage: $ sysbench < print('test') > EOF sysbench * (glob) test $ sysbench run < print('script body') > function event() > print('event function') > end > EOF sysbench * (glob) FATAL: Cannot find benchmark 'run': no such built-in test, file or module [1] $ cat >$CRAMTMP/cmdline.lua < #!/usr/bin/env sysbench > print('script body') > function event() > print('event function') > end > EOF $ sysbench --events=1 $CRAMTMP/cmdline.lua sysbench * (glob) script body $ sysbench --events=1 $CRAMTMP/cmdline.lua run sysbench * (glob) script body Running the test with following options: Number of threads: 1 Initializing random number generator from current time Initializing worker threads... script body Threads started! event function Throughput: events/s (eps): *.* (glob) time elapsed:*s (glob) total number of events: 1 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): 1.0000/0.00 execution time (avg/stddev): *.*/0.00 (glob) ######################################################################## Command line options tests ######################################################################## $ cat >cmdline.lua < sysbench.cmdline.options = { > str_opt1 = {"str_opt1 description"}, > str_opt2 = {"str_opt2 description", "opt2"}, > str_opt3 = {"str_opt3 description", "opt3", sysbench.cmdline.ARG_STRING}, > bool_opt1 = {"bool_opt1 description", false}, > bool_opt2 = {"bool_opt2 description", true}, > bool_opt3 = {"bool_opt3 description", nil, sysbench.cmdline.ARG_BOOL}, > int_opt1 = {"int_opt1 description", 10}, > int_opt2 = {"int_opt2 description", nil, sysbench.cmdline.ARG_INT}, > int_opt3 = {"int_opt3 description", 20, sysbench.cmdline.ARG_INT}, > float_opt1 = {"float_opt1 description", 3.14, sysbench.cmdline.ARG_DOUBLE}, > float_opt2 = {"float_opt2 description", 0.2}, > list_opt1 = {"list_opt1 description", {"foo", "bar"}}, > list_opt2 = {"list_opt2 description", nil, sysbench.cmdline.ARG_LIST}, > ["dash-opt"] = {"dash-opt desc", "dash-opt val"} > } > > function print_opt_table() > local o = sysbench.opt > print(o.str_opt1) > print(o.str_opt2) > print(o.str_opt3) > print(o.bool_opt1) > print(o.bool_opt2) > print(o.bool_opt3) > print(o.int_opt1) > print(o.int_opt2) > print(o.float_opt1) > print(o.float_opt2) > print(o.list_opt1) > print(o.list_opt2) > print(o.dash_opt) > print() > end > > function help() > print("function help()") > print("Available options:") > sysbench.cmdline.print_test_options() > print_opt_table() > end > > function init() > print("function init()") > print_opt_table() > end > > function thread_init() > print("function thread_init()") > print_opt_table() > end > > function event() > print("function event()") > print_opt_table() > end > > function thread_done() > print("function thread_done()") > print_opt_table() > end > > function done() > print("function done()") > print_opt_table() > end > EOF $ sysbench cmdline.lua sysbench * (glob) $ sysbench cmdline.lua help sysbench * (glob) function help() Available options: --bool_opt1[=on|off] bool_opt1 description [off] --bool_opt2[=on|off] bool_opt2 description [on] --bool_opt3[=on|off] bool_opt3 description --dash-opt=STRING dash-opt desc [dash-opt val] --float_opt1=N float_opt1 description [3.14] --float_opt2=N float_opt2 description [0.2] --int_opt1=N int_opt1 description [10] --int_opt2=N int_opt2 description --int_opt3=N int_opt3 description [20] --list_opt1=[LIST,...] list_opt1 description [foo,bar] --list_opt2=[LIST,...] list_opt2 description --str_opt1=STRING str_opt1 description --str_opt2=STRING str_opt2 description [opt2] --str_opt3=STRING str_opt3 description [opt3] opt2 opt3 false true true 10 0 3.14 0.2 table: 0x* (glob) table: 0x* (glob) dash-opt val $ sysbench cmdline.lua prepare sysbench * (glob) 'cmdline.lua' test does not implement the 'prepare' command. [1] $ sysbench --non-existing-option=3 cmdline.lua prepare sysbench * (glob) invalid option: --non-existing-option=3 [1] $ sysbench cmdline.lua --events=1 run sysbench * (glob) function init() opt2 opt3 false true true 10 0 3.14 0.2 table: 0x* (glob) table: 0x* (glob) dash-opt val Running the test with following options: Number of threads: 1 Initializing random number generator from current time Initializing worker threads... function thread_init() opt2 opt3 false true true 10 0 3.14 0.2 table: 0x* (glob) table: 0x* (glob) dash-opt val Threads started! function event() opt2 opt3 false true true 10 0 3.14 0.2 table: 0x* (glob) table: 0x* (glob) dash-opt val function thread_done() opt2 opt3 false true true 10 0 3.14 0.2 table: 0x* (glob) table: 0x* (glob) dash-opt val Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 1 Latency (ms): min: * (glob) avg: * (glob) max: * (glob) 95th percentile: * (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): 1.0000/0.00 execution time (avg/stddev): */0.00 (glob) function done() opt2 opt3 false true true 10 0 3.14 0.2 table: 0x* (glob) table: 0x* (glob) dash-opt val $ sysbench cmdline.lua cleanup sysbench * (glob) 'cmdline.lua' test does not implement the 'cleanup' command. [1] $ cat >cmdline.lua < > EOF $ sysbench cmdline.lua help sysbench * (glob) 'cmdline.lua' test does not implement the 'help' command. [1] $ cat >cmdline.lua < sysbench.cmdline.options = { > {}, > } > > function help() > end > EOF $ sysbench cmdline.lua help sysbench * (glob) FATAL: `sysbench.cmdline.read_cmdline_options' function failed: [string "sysbench.cmdline.lua"]:*: wrong table structure in sysbench.cmdline.options (glob) [1] $ sysbench fileio --invalid-option prepare sysbench * (glob) invalid option: --invalid-option [1] # Custom commands $ sysbench < sysbench.cmdline.commands = { > cmd1 = "wrong structure" > } > EOF sysbench * (glob) $ sysbench < sysbench.cmdline.commands = { > cmd1 = { non_existing_func } > } > EOF sysbench * (glob) $ cat >cmdline.lua < ffi.cdef "unsigned int sleep(unsigned int);" > function cmd1_func() > print("cmd1, sysbench.tid = " .. sysbench.tid) > end > function cmd2_func() > ffi.C.sleep(sysbench.tid % 2) > print("cmd2, sysbench.tid = " .. sysbench.tid) > end > function prepare_func() > ffi.C.sleep(sysbench.tid % 2) > print("prepare_func, sysbench.tid = " .. sysbench.tid) > end > sysbench.cmdline.commands = { > cmd1 = { cmd1_func }, > cmd2 = { cmd2_func, sysbench.cmdline.PARALLEL_COMMAND }, > prepare = { prepare_func, sysbench.cmdline.PARALLEL_COMMAND } > } > EOF $ sysbench --threads=2 cmdline.lua cmd1 sysbench * (glob) cmd1, sysbench.tid = 0 $ sysbench --threads=2 cmdline.lua cmd2 sysbench * (glob) Initializing worker threads... cmd2, sysbench.tid = [01] (re) cmd2, sysbench.tid = [01] (re) $ sysbench --threads=2 cmdline.lua prepare sysbench * (glob) Initializing worker threads... prepare_func, sysbench.tid = [01] (re) prepare_func, sysbench.tid = [01] (re) $ sysbench --threads=2 cmdline.lua cmd3 sysbench * (glob) Unknown command: cmd3 [1] $ cat >cmdline.lua < sysbench.cmdline.options = { opt1 = {"opt1"}, opt2 = {"opt2"} } > function print_cmd() > print("argv = " .. require("inspect")(sysbench.cmdline.argv)) > print(string.format("sysbench.cmdline.command = %s",sysbench.cmdline.command)) > end > function prepare() > print_cmd() > end > print_cmd() > EOF $ sysbench --opt1 --opt2=val cmdline.lua sysbench * (glob) argv = { "--opt1", "--opt2=val", "cmdline.lua", [0] = "sysbench" } sysbench.cmdline.command = nil $ sysbench --opt1 --opt2=val cmdline.lua prepare sysbench * (glob) argv = { "--opt1", "--opt2=val", "cmdline.lua", "prepare", [0] = "sysbench" } sysbench.cmdline.command = prepare argv = { "--opt1", "--opt2=val", "cmdline.lua", "prepare", [0] = "sysbench" } sysbench.cmdline.command = prepare $ sysbench - < print("hello") > EOF sysbench * (glob) hello $ sysbench - prepare < function prepare() > print("prepare") > end > print("global") > EOF sysbench * (glob) global # Test benchmark specification as a module $ cat > cmdline_module.lua < print("cmdline_module loaded") > function event() > print("cmdline_module event") > end > EOF $ LUA_PATH="$PWD/?.lua;$LUA_PATH" sysbench cmdline_module --verbosity=0 cmdline_module loaded $ LUA_PATH="$PWD/?.lua;$LUA_PATH" sysbench cmdline_module --events=1 --verbosity=0 run cmdline_module loaded cmdline_module loaded cmdline_module event # Test that errors thrown by the script itself are reported properly $ cat >> cmdline_module.lua < error("test error") > EOF $ LUA_PATH="$PWD/?.lua;$LUA_PATH" sysbench cmdline_module --verbosity=0 cmdline_module loaded FATAL: */cmdline_module.lua:5: test error (glob) [1] $ LUA_PATH="$PWD/?.lua;$LUA_PATH" sysbench cmdline_module --events=1 --verbosity=0 run cmdline_module loaded FATAL: */cmdline_module.lua:5: test error (glob) [1] ########################################################################## # Test boolean option validation ########################################################################## $ cat > cmdline.lua < sysbench.cmdline.options = { > bool_opt = {"Flag", false} > } > > function prepare() > print("bool_opt = " .. tostring(sysbench.opt.bool_opt)) > end > EOF $ SB_ARGS=--verbosity=0 $ sysbench $SB_ARGS cmdline.lua --bool-opt=on prepare bool_opt = true $ sysbench $SB_ARGS cmdline.lua --bool-opt=off prepare bool_opt = false $ sysbench $SB_ARGS cmdline.lua --bool-opt=true prepare bool_opt = true $ sysbench $SB_ARGS cmdline.lua --bool-opt=false prepare bool_opt = false $ sysbench $SB_ARGS cmdline.lua --bool-opt=1 prepare bool_opt = true $ sysbench $SB_ARGS cmdline.lua --bool-opt=0 prepare bool_opt = false $ sysbench $SB_ARGS cmdline.lua --bool-opt=5 prepare invalid option: --bool-opt=5 [1] $ sysbench $SB_ARGS cmdline.lua --bool-opt=foo prepare invalid option: --bool-opt=foo [1] ================================================ FILE: tests/t/commands.t ================================================ $ commands=$(sysbench --help | grep 'Commands' | cut -d ' ' -f 6-) $ for cmd in $commands; do > if [ ! -r ${SBTEST_SUITEDIR}/cmd_${cmd}.t ] > then > echo "Cannot find test(s) for 'sysbench $cmd'!" > exit 1 > fi > done ================================================ FILE: tests/t/drivers.t ================================================ ######################################################################## Make sure all available DB drivers are covered ######################################################################## $ drivers=$(sysbench --help | sed -n '/Compiled-in database drivers:/,/^$/p' | tail -n +2 | cut -d ' ' -f 3) $ for drv in $drivers > do > if [ ! -r ${SBTEST_SUITEDIR}/drv_${drv}.t ] > then > echo "Cannot find test(s) for the $drv driver!" > exit 1 > fi > done # Try using a non-existing driver $ sysbench --db-driver=nonexisting ${SBTEST_SCRIPTDIR}/oltp_read_write.lua cleanup sysbench * (glob) (FATAL: invalid database driver name: 'nonexisting'|FATAL: No DB drivers available) (re) FATAL: `cleanup' function failed: * failed to initialize the DB driver (glob) [1] ================================================ FILE: tests/t/drv_mysql.t ================================================ ######################################################################## MySQL driver tests ######################################################################## $ . $SBTEST_INCDIR/mysql_common.sh $ . $SBTEST_INCDIR/drv_common.sh sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 10 write: 0 other: 0 total: 10 transactions: 10 (*.* per sec.) (glob) queries: 10 (*.* per sec.) (glob) ignored errors: 0 (0.00 per sec.) reconnects: 0 (0.00 per sec.) Throughput: events/s (eps): *.* (glob) time elapsed: *.*s (glob) total number of events: 10 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): *.*/*.* (glob) execution time (avg/stddev): *.*/*.* (glob) ================================================ FILE: tests/t/drv_pgsql.t ================================================ ######################################################################## PostgreSQL driver tests ######################################################################## $ . $SBTEST_INCDIR/pgsql_common.sh $ . $SBTEST_INCDIR/drv_common.sh sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 10 write: 0 other: 0 total: 10 transactions: 10 (*.* per sec.) (glob) queries: 10 (*.* per sec.) (glob) ignored errors: 0 (0.00 per sec.) reconnects: 0 (0.00 per sec.) Throughput: events/s (eps): *.* (glob) time elapsed: *.*s (glob) total number of events: 10 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): *.*/*.* (glob) execution time (avg/stddev): *.*/*.* (glob) ================================================ FILE: tests/t/help_drv_mysql.t ================================================ Skip test if the MySQL driver is not available. $ if [ -z "$SBTEST_HAS_MYSQL" ] > then > exit 80 > fi $ sysbench --help | grep -- '--db-driver' --db-driver=STRING specifies database driver to use ('help' to get list of available drivers) [mysql] $ sysbench --help | sed -n '/mysql options:/,/^$/p' | grep -v 'mysql-ssl[=\[]' mysql options: --mysql-host=[LIST,...] MySQL server host [localhost] --mysql-port=[LIST,...] MySQL server port [3306] --mysql-socket=[LIST,...] MySQL socket --mysql-user=STRING MySQL user [sbtest] --mysql-password=STRING MySQL password [] --mysql-db=STRING MySQL database name [sbtest] --mysql-ssl-key=STRING path name of the client private key file --mysql-ssl-ca=STRING path name of the CA file --mysql-ssl-cert=STRING path name of the client public key certificate file --mysql-ssl-cipher=STRING use specific cipher for SSL connections [] --mysql-compression[=on|off] use compression, if available in the client library [off] --mysql-compression-algorithms=STRING compression algorithms to use [zlib] --mysql-debug[=on|off] trace all client library calls [off] --mysql-ignore-errors=[LIST,...] list of errors to ignore, or "all" [1213,1020,1205] --mysql-dry-run[=on|off] Dry run, pretend that all MySQL client API calls are successful without executing them [off] ================================================ FILE: tests/t/help_drv_pgsql.t ================================================ Skip test if the PostgreSQL driver is not available. $ if [ -z "$SBTEST_HAS_PGSQL" ] > then > exit 80 > fi $ sysbench --help | sed -n '/pgsql options:/,/^$/p' pgsql options: --pgsql-host=STRING PostgreSQL server host [localhost] --pgsql-port=N PostgreSQL server port [5432] --pgsql-user=STRING PostgreSQL user [sbtest] --pgsql-password=STRING PostgreSQL password [] --pgsql-db=STRING PostgreSQL database name [sbtest] --pgsql-sslmode=STRING PostgreSQL SSL mode (disable, allow, prefer, require, verify-ca, verify-full) [prefer] ================================================ FILE: tests/t/opt_help.t ================================================ ######################################################################## Skip everything between "Compiled-in database drivers:" and "Compiled-in tests:" as that part depends on available database drivers and thus, build options. Driver-specific options are tested separately. ######################################################################## $ sysbench --help | sed '/Compiled-in database drivers:/,/Compiled-in tests:/d' Usage: sysbench [options]... [testname] [command] Commands implemented by most tests: prepare run cleanup help General options: --threads=N number of threads to use [1] --events=N limit for total number of events [0] --time=N limit for total execution time in seconds [10] --warmup-time=N execute events for this many seconds with statistics disabled before the actual benchmark run with statistics enabled [0] --forced-shutdown=STRING number of seconds to wait after the --time limit before forcing shutdown, or 'off' to disable [off] --thread-stack-size=SIZE size of stack per thread [64K] --thread-init-timeout=N wait time in seconds for worker threads to initialize [30] --rate=N average transactions rate. 0 for unlimited rate [0] --report-interval=N periodically report intermediate statistics with a specified interval in seconds. 0 disables intermediate reports [0] --report-checkpoints=[LIST,...] dump full statistics and reset all counters at specified points in time. The argument is a list of comma-separated values representing the amount of time in seconds elapsed from start of test when report checkpoint(s) must be performed. Report checkpoints are off by default. [] --debug[=on|off] print more debugging info [off] --validate[=on|off] perform validation checks where possible [off] --help[=on|off] print help and exit [off] --version[=on|off] print version and exit [off] --config-file=FILENAME File containing command line options --luajit-cmd=STRING perform LuaJIT control command. This option is equivalent to 'luajit -j'. See LuaJIT documentation for more information Pseudo-Random Numbers Generator options: --rand-type=STRING random numbers distribution {uniform, gaussian, pareto, zipfian} to use by default [uniform] --rand-seed=N seed for random number generator. When 0, the current time is used as an RNG seed. [0] --rand-pareto-h=N shape parameter for the Pareto distribution [0.2] --rand-zipfian-exp=N shape parameter (exponent, theta) for the Zipfian distribution [0.8] Log options: --verbosity=N verbosity level {5 - debug, 0 - only critical messages} [3] --percentile=N percentile to calculate in latency statistics (1-100). Use the special value of 0 to disable percentile calculations [95] --histogram[=on|off] print latency histogram in report [off] General database options: --db-driver=STRING specifies database driver to use \('help' to get list of available drivers\)( \[mysql\])? (re) --db-ps-mode=STRING prepared statements usage mode {auto, disable} [auto] --db-debug[=on|off] print database-specific debug information [off] fileio - File I/O test cpu - CPU performance test memory - Memory functions speed test threads - Threads subsystem performance test mutex - Mutex performance test See 'sysbench help' for a list of options for each test. ######################################################################## Test driver-specific options ######################################################################## $ drivers=$(sysbench --help | sed -n '/Compiled-in database drivers:/,/^$/p' | tail -n +2 | cut -d ' ' -f 3) $ for drv in $drivers > do > if [ ! -r ${SBTEST_SUITEDIR}/help_drv_${drv}.t ] > then > echo "Cannot find test(s) for $drv driver options!" > exit 1 > fi > done ================================================ FILE: tests/t/opt_histogram.t ================================================ ######################################################################## --histogram tests ######################################################################## $ cat >$CRAMTMP/histogram.lua < local ffi = require("ffi") > ffi.cdef[[ > int usleep(unsigned int); > ]] > function event() > if (sysbench.tid == 0) then > ffi.C.usleep(1000000) > else > ffi.C.usleep(2000000) > end > end > EOF $ sysbench --histogram $CRAMTMP/histogram.lua --events=2 --threads=2 run sysbench * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! Latency histogram (values are in milliseconds) value ------------- distribution ------------- count * |\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 1 (glob) * |\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 1 (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 2 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): 1.0000/0.00 execution time (avg/stddev): */* (glob) ================================================ FILE: tests/t/opt_luajit_cmd.t ================================================ ######################################################################## --luajit-cmd tests ######################################################################## $ cat >opt_luajit_cmd.lua < print("JIT status: " .. (jit.status() and "on" or "off")) > EOF $ sysbench --luajit-cmd opt_luajit_cmd.lua sysbench * (glob) JIT status: on $ sysbench --luajit-cmd=off opt_luajit_cmd.lua sysbench * (glob) JIT status: off $ sysbench --luajit-cmd=on opt_luajit_cmd.lua sysbench * (glob) JIT status: on ================================================ FILE: tests/t/opt_rate.t ================================================ ######################################################################## Tests for the --rate option (aka the limited rate mode) ######################################################################## # Failing to deliver the requested rate should result in a non-zero exit code $ sysbench --rate=2000000000 cpu run --verbosity=1 FATAL: The event queue is full. This means the worker threads are unable to keep up with the specified event generation rate [1] ================================================ FILE: tests/t/opt_report_checkpoints.t ================================================ ######################################################################## # --report-checkpoints tests ######################################################################## $ if [ -z "$SBTEST_HAS_MYSQL" ] > then > exit 80 > fi $ sysbench ${SBTEST_SCRIPTDIR}/oltp_read_write.lua --db-driver=mysql --mysql-dry-run --time=3 --events=0 --report-checkpoints=1,2 run | grep -E '(Checkpoint report|SQL statistics)' [ 1s ] Checkpoint report: SQL statistics: [ 2s ] Checkpoint report: SQL statistics: SQL statistics: # Run a test that does not support checkpoint reports $ sysbench cpu --report-checkpoints=1 --time=2 run | grep 'Checkpoint report' [ 1s ] Checkpoint report: ================================================ FILE: tests/t/opt_report_interval.t ================================================ ######################################################################## # --report-interval tests ######################################################################## $ if [ -z "$SBTEST_HAS_MYSQL" ] > then > exit 80 > fi $ sysbench ${SBTEST_SCRIPTDIR}/oltp_read_write.lua --db-driver=mysql --mysql-dry-run --time=3 --events=0 --report-interval=1 run | grep '\[ 2s \]' [ 2s ] thds: 1 tps: * qps: * (r/w/o: */*/*) lat (ms,95%): *.* err/s: 0.00 reconn/s: 0.00 (glob) # Run a test that does not support intermediate reports $ sysbench cpu --report-interval=1 --time=2 run | grep '\[ 1s \]' [ 1s ] thds: 1 eps: * lat (ms,95%): * (glob) ================================================ FILE: tests/t/opt_version.t ================================================ ######################################################################## Test for the --version option ######################################################################## $ sysbench --version sysbench [.0-9]+(-[a-f0-9]+)? (re) $ version=$(sysbench --version | cut -d ' ' -f 1,2) $ test "$version" = "$SBTEST_VERSION_STRING" ================================================ FILE: tests/t/opt_warmup_time.t ================================================ ######################################################################## --warmup-time tests ######################################################################## $ cat >$CRAMTMP/warmup_time.lua < local ffi = require("ffi") > ffi.cdef[[ > int usleep(unsigned int); > ]] > function event() > if (sysbench.tid == 0) then > ffi.C.usleep(2000000) > else > ffi.C.usleep(3000000) > end > end > EOF $ sysbench --warmup-time=-1 $CRAMTMP/warmup_time.lua --threads=2 run FATAL: Invalid value for --warmup-time: -1. [1] $ sysbench --warmup-time=1 $CRAMTMP/warmup_time.lua --threads=2 --time=1 run sysbench * (glob) Running the test with following options: Number of threads: 2 Warmup time: 1s Initializing random number generator from current time Initializing worker threads... Threads started! Warming up for 1 seconds... Throughput: events/s (eps): *.* (glob) time elapsed: 2.*s (glob) total number of events: 2 Latency (ms): min: * (glob) avg: * (glob) max: * (glob) 95th percentile: * (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) $ sysbench --warmup-time=1 $CRAMTMP/warmup_time.lua --threads=2 --time=0 --events=3 run sysbench * (glob) Running the test with following options: Number of threads: 2 Warmup time: 1s Initializing random number generator from current time Initializing worker threads... Threads started! Warming up for 1 seconds... Throughput: events/s (eps): *.* (glob) time elapsed: 5.*s (glob) total number of events: 5 Latency (ms): min: * (glob) avg: * (glob) max: * (glob) 95th percentile: * (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) ================================================ FILE: tests/t/script_bulk_insert_mysql.t ================================================ ######################################################################## bulk_insert.lua + MySQL tests ######################################################################## $ . $SBTEST_INCDIR/mysql_common.sh $ . $SBTEST_INCDIR/script_bulk_insert_common.sh Creating table 'sbtest1'... Creating table 'sbtest2'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL, (glob) `k` int* NOT NULL DEFAULT '0', (glob) PRIMARY KEY (`id`) ) ENGINE=InnoDB * (glob) *************************** 1. row *************************** sbtest2 CREATE TABLE `sbtest2` ( `id` int* NOT NULL, (glob) `k` int* NOT NULL DEFAULT '0', (glob) PRIMARY KEY (`id`) ) ENGINE=InnoDB * (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest3' doesn't exist sysbench * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 0 write: [12] (re) other: 0 total: [12] (re) transactions: 100 (* per sec.) (glob) queries: [12] \(.* per sec.\) (re) ignored errors: 0 (0.00 per sec.) reconnects: 0 (0.00 per sec.) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev):* (glob) execution time (avg/stddev):* (glob) Dropping table 'sbtest1'... Dropping table 'sbtest2'... ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest1' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest2' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest3' doesn't exist ================================================ FILE: tests/t/script_bulk_insert_pgsql.t ================================================ ######################################################################## bulk_insert.lua + PostgreSQL tests ######################################################################## $ . $SBTEST_INCDIR/pgsql_common.sh $ . $SBTEST_INCDIR/script_bulk_insert_common.sh Creating table 'sbtest1'... Creating table 'sbtest2'... Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+--------------------+---------+--------------+------------- id | integer | not null | plain | | k | integer | not null default 0 | plain | | Indexes: CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) Table "public.sbtest2" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+--------------------+---------+--------------+------------- id | integer | not null | plain | | k | integer | not null default 0 | plain | | Indexes: CREATE UNIQUE INDEX sbtest2_pkey ON sbtest2 USING btree (id) Did not find any relation named "sbtest3". sysbench * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 0 write: [12] (re) other: 0 total: [12] (re) transactions: 100 (* per sec.) (glob) queries: [12] \(.* per sec.\) (re) ignored errors: 0 (0.00 per sec.) reconnects: 0 (0.00 per sec.) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev):* (glob) execution time (avg/stddev):* (glob) Dropping table 'sbtest1'... Dropping table 'sbtest2'... Did not find any relation named "sbtest1". Did not find any relation named "sbtest2". Did not find any relation named "sbtest3". ================================================ FILE: tests/t/script_oltp_delete_mysql.t ================================================ ######################################################################## oltp_delete.lua + MySQL tests ######################################################################## $ . $SBTEST_INCDIR/mysql_common.sh $ OLTP_SCRIPT_PATH=${SBTEST_SCRIPTDIR}/oltp_delete.lua $ . $SBTEST_INCDIR/script_oltp_common.sh sysbench *.* * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Creating table 'sbtest2'... Inserting 10000 records into 'sbtest2' Creating a secondary index on 'sbtest2'... Creating table 'sbtest3'... Inserting 10000 records into 'sbtest3' Creating a secondary index on 'sbtest3'... Creating table 'sbtest4'... Inserting 10000 records into 'sbtest4' Creating a secondary index on 'sbtest4'... Creating table 'sbtest5'... Inserting 10000 records into 'sbtest5' Creating a secondary index on 'sbtest5'... Creating table 'sbtest6'... Inserting 10000 records into 'sbtest6' Creating a secondary index on 'sbtest6'... Creating table 'sbtest7'... Inserting 10000 records into 'sbtest7' Creating a secondary index on 'sbtest7'... Creating table 'sbtest8'... Inserting 10000 records into 'sbtest8' Creating a secondary index on 'sbtest8'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest2 CREATE TABLE `sbtest2` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_2` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest3 CREATE TABLE `sbtest3` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_3` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest4 CREATE TABLE `sbtest4` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_4` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest5 CREATE TABLE `sbtest5` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_5` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest6 CREATE TABLE `sbtest6` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_6` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest7 CREATE TABLE `sbtest7` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_7` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest8 CREATE TABLE `sbtest8` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_8` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest9' doesn't exist sysbench * (glob) Preloading table sbtest1 Preloading table sbtest2 Preloading table sbtest3 Preloading table sbtest4 Preloading table sbtest5 Preloading table sbtest6 Preloading table sbtest7 Preloading table sbtest8 sysbench *.* * (glob) Dropping table 'sbtest1'... Dropping table 'sbtest2'... Dropping table 'sbtest3'... Dropping table 'sbtest4'... Dropping table 'sbtest5'... Dropping table 'sbtest6'... Dropping table 'sbtest7'... Dropping table 'sbtest8'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest2 CREATE TABLE `sbtest2` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_2` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest3 CREATE TABLE `sbtest3` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_3` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest4 CREATE TABLE `sbtest4` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_4` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest5 CREATE TABLE `sbtest5` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_5` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest6 CREATE TABLE `sbtest6` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_6` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest7 CREATE TABLE `sbtest7` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_7` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest8 CREATE TABLE `sbtest8` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_8` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest9' doesn't exist sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 0 write: * (glob) other: * (glob) total: 100 transactions: 100 (* per sec.) (glob) queries: 100 (* per sec.) (glob) ignored errors: 0 (* per sec.) (glob) reconnects: 0 (* per sec.) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest1' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest2' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest3' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest4' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest5' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest6' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest7' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest8' doesn't exist # Test --create-secondary=off sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) sysbench * (glob) Dropping table 'sbtest1'... # Test --auto-inc=off Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Dropping table 'sbtest1'... # Test --reconnect reconnects: 20 (* per sec.) (glob) ================================================ FILE: tests/t/script_oltp_delete_pgsql.t ================================================ ######################################################################## oltp_delete.lua + PostgreSQL tests ######################################################################## $ . $SBTEST_INCDIR/pgsql_common.sh $ OLTP_SCRIPT_PATH=${SBTEST_SCRIPTDIR}/oltp_delete.lua $ . $SBTEST_INCDIR/script_oltp_common.sh sysbench *.* * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Creating table 'sbtest2'... Inserting 10000 records into 'sbtest2' Creating a secondary index on 'sbtest2'... Creating table 'sbtest3'... Inserting 10000 records into 'sbtest3' Creating a secondary index on 'sbtest3'... Creating table 'sbtest4'... Inserting 10000 records into 'sbtest4' Creating a secondary index on 'sbtest4'... Creating table 'sbtest5'... Inserting 10000 records into 'sbtest5' Creating a secondary index on 'sbtest5'... Creating table 'sbtest6'... Inserting 10000 records into 'sbtest6' Creating a secondary index on 'sbtest6'... Creating table 'sbtest7'... Inserting 10000 records into 'sbtest7' Creating a secondary index on 'sbtest7'... Creating table 'sbtest8'... Inserting 10000 records into 'sbtest8' Creating a secondary index on 'sbtest8'... Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_1 ON sbtest1 USING btree (k) CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) Table "public.sbtest2" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest2_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_2 ON sbtest2 USING btree (k) CREATE UNIQUE INDEX sbtest2_pkey ON sbtest2 USING btree (id) Table "public.sbtest3" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest3_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_3 ON sbtest3 USING btree (k) CREATE UNIQUE INDEX sbtest3_pkey ON sbtest3 USING btree (id) Table "public.sbtest4" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest4_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_4 ON sbtest4 USING btree (k) CREATE UNIQUE INDEX sbtest4_pkey ON sbtest4 USING btree (id) Table "public.sbtest5" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest5_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_5 ON sbtest5 USING btree (k) CREATE UNIQUE INDEX sbtest5_pkey ON sbtest5 USING btree (id) Table "public.sbtest6" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest6_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_6 ON sbtest6 USING btree (k) CREATE UNIQUE INDEX sbtest6_pkey ON sbtest6 USING btree (id) Table "public.sbtest7" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest7_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_7 ON sbtest7 USING btree (k) CREATE UNIQUE INDEX sbtest7_pkey ON sbtest7 USING btree (id) Table "public.sbtest8" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest8_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_8 ON sbtest8 USING btree (k) CREATE UNIQUE INDEX sbtest8_pkey ON sbtest8 USING btree (id) Did not find any relation named "sbtest9". sysbench *.* * (glob) FATAL: *: warmup is currently MySQL only (glob) sysbench *.* * (glob) Dropping table 'sbtest1'... Dropping table 'sbtest2'... Dropping table 'sbtest3'... Dropping table 'sbtest4'... Dropping table 'sbtest5'... Dropping table 'sbtest6'... Dropping table 'sbtest7'... Dropping table 'sbtest8'... Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_1 ON sbtest1 USING btree (k) CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) Table "public.sbtest2" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest2_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_2 ON sbtest2 USING btree (k) CREATE UNIQUE INDEX sbtest2_pkey ON sbtest2 USING btree (id) Table "public.sbtest3" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest3_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_3 ON sbtest3 USING btree (k) CREATE UNIQUE INDEX sbtest3_pkey ON sbtest3 USING btree (id) Table "public.sbtest4" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest4_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_4 ON sbtest4 USING btree (k) CREATE UNIQUE INDEX sbtest4_pkey ON sbtest4 USING btree (id) Table "public.sbtest5" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest5_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_5 ON sbtest5 USING btree (k) CREATE UNIQUE INDEX sbtest5_pkey ON sbtest5 USING btree (id) Table "public.sbtest6" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest6_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_6 ON sbtest6 USING btree (k) CREATE UNIQUE INDEX sbtest6_pkey ON sbtest6 USING btree (id) Table "public.sbtest7" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest7_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_7 ON sbtest7 USING btree (k) CREATE UNIQUE INDEX sbtest7_pkey ON sbtest7 USING btree (id) Table "public.sbtest8" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest8_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_8 ON sbtest8 USING btree (k) CREATE UNIQUE INDEX sbtest8_pkey ON sbtest8 USING btree (id) Did not find any relation named "sbtest9". sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 0 write: * (glob) other: * (glob) total: 100 transactions: 100 (* per sec.) (glob) queries: 100 (* per sec.) (glob) ignored errors: 0 (* per sec.) (glob) reconnects: 0 (* per sec.) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) Did not find any relation named "sbtest1". Did not find any relation named "sbtest2". Did not find any relation named "sbtest3". Did not find any relation named "sbtest4". Did not find any relation named "sbtest5". Did not find any relation named "sbtest6". Did not find any relation named "sbtest7". Did not find any relation named "sbtest8". # Test --create-secondary=off sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) sysbench * (glob) Dropping table 'sbtest1'... # Test --auto-inc=off Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Dropping table 'sbtest1'... # Test --reconnect reconnects: 20 (* per sec.) (glob) ================================================ FILE: tests/t/script_oltp_general_mysql.t ================================================ $ . $SBTEST_INCDIR/mysql_common.sh $ SB_EXTRA_ARGS=${SB_EXTRA_ARGS:-} $ ARGS="oltp_read_write ${DB_DRIVER_ARGS} --verbosity=1 ${SB_EXTRA_ARGS}" $ sysbench $ARGS --create-table-options="COMMENT='foo'" prepare Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... $ db_show_table sbtest1 *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB * COMMENT='foo' (glob) $ sysbench $ARGS cleanup Dropping table 'sbtest1'... ================================================ FILE: tests/t/script_oltp_help.t ================================================ ######################################################################## OLTP usage information test ######################################################################## $ sysbench $SBTEST_SCRIPTDIR/oltp_read_write.lua help sysbench * (glob) oltp_read_write.lua options: --auto_inc[=on|off] Use AUTO_INCREMENT column as Primary Key (for MySQL), or its alternatives in other DBMS. When disabled, use client-generated IDs [on] --create_secondary[=on|off] Create a secondary index in addition to the PRIMARY KEY [on] --create_table_options=STRING Extra CREATE TABLE options [] --delete_inserts=N Number of DELETE/INSERT combinations per transaction [1] --distinct_ranges=N Number of SELECT DISTINCT queries per transaction [1] --index_updates=N Number of UPDATE index queries per transaction [1] --mysql_storage_engine=STRING Storage engine, if MySQL is used [innodb] --non_index_updates=N Number of UPDATE non-index queries per transaction [1] --order_ranges=N Number of SELECT ORDER BY queries per transaction [1] --pgsql_variant=STRING Use this PostgreSQL variant when running with the PostgreSQL driver. The only currently supported variant is 'redshift'. When enabled, create_secondary is automatically disabled, and delete_inserts is set to 0 --point_selects=N Number of point SELECT queries per transaction [10] --range_selects[=on|off] Enable/disable all range SELECT queries [on] --range_size=N Range size for range SELECT queries [100] --reconnect=N Reconnect after every N events. The default (0) is to not reconnect [0] --secondary[=on|off] Use a secondary index in place of the PRIMARY KEY [off] --simple_ranges=N Number of simple range SELECT queries per transaction [1] --skip_trx[=on|off] Don't start explicit transactions and execute all queries in the AUTOCOMMIT mode [off] --sum_ranges=N Number of SELECT SUM() queries per transaction [1] --table_size=N Number of rows per table [10000] --tables=N Number of tables [1] ================================================ FILE: tests/t/script_oltp_insert_mysql.t ================================================ ######################################################################## oltp_insert.lua + MySQL tests ######################################################################## $ . $SBTEST_INCDIR/mysql_common.sh $ OLTP_SCRIPT_PATH=${SBTEST_SCRIPTDIR}/oltp_insert.lua $ . $SBTEST_INCDIR/script_oltp_common.sh sysbench *.* * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Creating table 'sbtest2'... Inserting 10000 records into 'sbtest2' Creating a secondary index on 'sbtest2'... Creating table 'sbtest3'... Inserting 10000 records into 'sbtest3' Creating a secondary index on 'sbtest3'... Creating table 'sbtest4'... Inserting 10000 records into 'sbtest4' Creating a secondary index on 'sbtest4'... Creating table 'sbtest5'... Inserting 10000 records into 'sbtest5' Creating a secondary index on 'sbtest5'... Creating table 'sbtest6'... Inserting 10000 records into 'sbtest6' Creating a secondary index on 'sbtest6'... Creating table 'sbtest7'... Inserting 10000 records into 'sbtest7' Creating a secondary index on 'sbtest7'... Creating table 'sbtest8'... Inserting 10000 records into 'sbtest8' Creating a secondary index on 'sbtest8'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest2 CREATE TABLE `sbtest2` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_2` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest3 CREATE TABLE `sbtest3` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_3` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest4 CREATE TABLE `sbtest4` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_4` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest5 CREATE TABLE `sbtest5` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_5` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest6 CREATE TABLE `sbtest6` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_6` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest7 CREATE TABLE `sbtest7` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_7` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest8 CREATE TABLE `sbtest8` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_8` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest9' doesn't exist sysbench * (glob) Preloading table sbtest1 Preloading table sbtest2 Preloading table sbtest3 Preloading table sbtest4 Preloading table sbtest5 Preloading table sbtest6 Preloading table sbtest7 Preloading table sbtest8 sysbench *.* * (glob) Dropping table 'sbtest1'... Dropping table 'sbtest2'... Dropping table 'sbtest3'... Dropping table 'sbtest4'... Dropping table 'sbtest5'... Dropping table 'sbtest6'... Dropping table 'sbtest7'... Dropping table 'sbtest8'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest2 CREATE TABLE `sbtest2` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_2` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest3 CREATE TABLE `sbtest3` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_3` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest4 CREATE TABLE `sbtest4` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_4` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest5 CREATE TABLE `sbtest5` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_5` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest6 CREATE TABLE `sbtest6` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_6` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest7 CREATE TABLE `sbtest7` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_7` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest8 CREATE TABLE `sbtest8` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_8` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest9' doesn't exist sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 0 write: 100 other: 0 total: 100 transactions: 100 (* per sec.) (glob) queries: 100 (* per sec.) (glob) ignored errors: 0 (* per sec.) (glob) reconnects: 0 (* per sec.) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest1' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest2' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest3' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest4' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest5' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest6' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest7' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest8' doesn't exist # Test --create-secondary=off sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) sysbench * (glob) Dropping table 'sbtest1'... # Test --auto-inc=off Creating table 'sbtest1'... Creating a secondary index on 'sbtest1'... Dropping table 'sbtest1'... # Test --reconnect reconnects: 20 (* per sec.) (glob) ================================================ FILE: tests/t/script_oltp_insert_pgsql.t ================================================ ######################################################################## oltp_insert.lua + PostgreSQL tests ######################################################################## $ . $SBTEST_INCDIR/pgsql_common.sh $ OLTP_SCRIPT_PATH=${SBTEST_SCRIPTDIR}/oltp_insert.lua $ . $SBTEST_INCDIR/script_oltp_common.sh sysbench *.* * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Creating table 'sbtest2'... Inserting 10000 records into 'sbtest2' Creating a secondary index on 'sbtest2'... Creating table 'sbtest3'... Inserting 10000 records into 'sbtest3' Creating a secondary index on 'sbtest3'... Creating table 'sbtest4'... Inserting 10000 records into 'sbtest4' Creating a secondary index on 'sbtest4'... Creating table 'sbtest5'... Inserting 10000 records into 'sbtest5' Creating a secondary index on 'sbtest5'... Creating table 'sbtest6'... Inserting 10000 records into 'sbtest6' Creating a secondary index on 'sbtest6'... Creating table 'sbtest7'... Inserting 10000 records into 'sbtest7' Creating a secondary index on 'sbtest7'... Creating table 'sbtest8'... Inserting 10000 records into 'sbtest8' Creating a secondary index on 'sbtest8'... Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_1 ON sbtest1 USING btree (k) CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) Table "public.sbtest2" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest2_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_2 ON sbtest2 USING btree (k) CREATE UNIQUE INDEX sbtest2_pkey ON sbtest2 USING btree (id) Table "public.sbtest3" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest3_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_3 ON sbtest3 USING btree (k) CREATE UNIQUE INDEX sbtest3_pkey ON sbtest3 USING btree (id) Table "public.sbtest4" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest4_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_4 ON sbtest4 USING btree (k) CREATE UNIQUE INDEX sbtest4_pkey ON sbtest4 USING btree (id) Table "public.sbtest5" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest5_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_5 ON sbtest5 USING btree (k) CREATE UNIQUE INDEX sbtest5_pkey ON sbtest5 USING btree (id) Table "public.sbtest6" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest6_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_6 ON sbtest6 USING btree (k) CREATE UNIQUE INDEX sbtest6_pkey ON sbtest6 USING btree (id) Table "public.sbtest7" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest7_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_7 ON sbtest7 USING btree (k) CREATE UNIQUE INDEX sbtest7_pkey ON sbtest7 USING btree (id) Table "public.sbtest8" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest8_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_8 ON sbtest8 USING btree (k) CREATE UNIQUE INDEX sbtest8_pkey ON sbtest8 USING btree (id) Did not find any relation named "sbtest9". sysbench *.* * (glob) FATAL: *: warmup is currently MySQL only (glob) sysbench *.* * (glob) Dropping table 'sbtest1'... Dropping table 'sbtest2'... Dropping table 'sbtest3'... Dropping table 'sbtest4'... Dropping table 'sbtest5'... Dropping table 'sbtest6'... Dropping table 'sbtest7'... Dropping table 'sbtest8'... Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_1 ON sbtest1 USING btree (k) CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) Table "public.sbtest2" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest2_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_2 ON sbtest2 USING btree (k) CREATE UNIQUE INDEX sbtest2_pkey ON sbtest2 USING btree (id) Table "public.sbtest3" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest3_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_3 ON sbtest3 USING btree (k) CREATE UNIQUE INDEX sbtest3_pkey ON sbtest3 USING btree (id) Table "public.sbtest4" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest4_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_4 ON sbtest4 USING btree (k) CREATE UNIQUE INDEX sbtest4_pkey ON sbtest4 USING btree (id) Table "public.sbtest5" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest5_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_5 ON sbtest5 USING btree (k) CREATE UNIQUE INDEX sbtest5_pkey ON sbtest5 USING btree (id) Table "public.sbtest6" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest6_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_6 ON sbtest6 USING btree (k) CREATE UNIQUE INDEX sbtest6_pkey ON sbtest6 USING btree (id) Table "public.sbtest7" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest7_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_7 ON sbtest7 USING btree (k) CREATE UNIQUE INDEX sbtest7_pkey ON sbtest7 USING btree (id) Table "public.sbtest8" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest8_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_8 ON sbtest8 USING btree (k) CREATE UNIQUE INDEX sbtest8_pkey ON sbtest8 USING btree (id) Did not find any relation named "sbtest9". sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 0 write: 100 other: 0 total: 100 transactions: 100 (* per sec.) (glob) queries: 100 (* per sec.) (glob) ignored errors: 0 (* per sec.) (glob) reconnects: 0 (* per sec.) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) Did not find any relation named "sbtest1". Did not find any relation named "sbtest2". Did not find any relation named "sbtest3". Did not find any relation named "sbtest4". Did not find any relation named "sbtest5". Did not find any relation named "sbtest6". Did not find any relation named "sbtest7". Did not find any relation named "sbtest8". # Test --create-secondary=off sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) sysbench * (glob) Dropping table 'sbtest1'... # Test --auto-inc=off Creating table 'sbtest1'... Creating a secondary index on 'sbtest1'... Dropping table 'sbtest1'... # Test --reconnect reconnects: 20 (* per sec.) (glob) ================================================ FILE: tests/t/script_oltp_point_select_mysql.t ================================================ ######################################################################## oltp_point_select.lua + MySQL tests ######################################################################## $ . $SBTEST_INCDIR/mysql_common.sh $ OLTP_SCRIPT_PATH=${SBTEST_SCRIPTDIR}/oltp_point_select.lua $ . $SBTEST_INCDIR/script_oltp_common.sh sysbench *.* * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Creating table 'sbtest2'... Inserting 10000 records into 'sbtest2' Creating a secondary index on 'sbtest2'... Creating table 'sbtest3'... Inserting 10000 records into 'sbtest3' Creating a secondary index on 'sbtest3'... Creating table 'sbtest4'... Inserting 10000 records into 'sbtest4' Creating a secondary index on 'sbtest4'... Creating table 'sbtest5'... Inserting 10000 records into 'sbtest5' Creating a secondary index on 'sbtest5'... Creating table 'sbtest6'... Inserting 10000 records into 'sbtest6' Creating a secondary index on 'sbtest6'... Creating table 'sbtest7'... Inserting 10000 records into 'sbtest7' Creating a secondary index on 'sbtest7'... Creating table 'sbtest8'... Inserting 10000 records into 'sbtest8' Creating a secondary index on 'sbtest8'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest2 CREATE TABLE `sbtest2` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_2` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest3 CREATE TABLE `sbtest3` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_3` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest4 CREATE TABLE `sbtest4` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_4` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest5 CREATE TABLE `sbtest5` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_5` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest6 CREATE TABLE `sbtest6` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_6` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest7 CREATE TABLE `sbtest7` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_7` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest8 CREATE TABLE `sbtest8` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_8` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest9' doesn't exist sysbench * (glob) Preloading table sbtest1 Preloading table sbtest2 Preloading table sbtest3 Preloading table sbtest4 Preloading table sbtest5 Preloading table sbtest6 Preloading table sbtest7 Preloading table sbtest8 sysbench *.* * (glob) Dropping table 'sbtest1'... Dropping table 'sbtest2'... Dropping table 'sbtest3'... Dropping table 'sbtest4'... Dropping table 'sbtest5'... Dropping table 'sbtest6'... Dropping table 'sbtest7'... Dropping table 'sbtest8'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest2 CREATE TABLE `sbtest2` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_2` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest3 CREATE TABLE `sbtest3` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_3` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest4 CREATE TABLE `sbtest4` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_4` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest5 CREATE TABLE `sbtest5` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_5` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest6 CREATE TABLE `sbtest6` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_6` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest7 CREATE TABLE `sbtest7` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_7` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest8 CREATE TABLE `sbtest8` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_8` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest9' doesn't exist sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 100 write: 0 other: 0 total: 100 transactions: 100 (* per sec.) (glob) queries: 100 (* per sec.) (glob) ignored errors: 0 (* per sec.) (glob) reconnects: 0 (* per sec.) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest1' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest2' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest3' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest4' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest5' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest6' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest7' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest8' doesn't exist # Test --create-secondary=off sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) sysbench * (glob) Dropping table 'sbtest1'... # Test --auto-inc=off Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Dropping table 'sbtest1'... # Test --reconnect reconnects: 20 (* per sec.) (glob) ================================================ FILE: tests/t/script_oltp_point_select_pgsql.t ================================================ ######################################################################## oltp_point_select.lua + PostgreSQL tests ######################################################################## $ . $SBTEST_INCDIR/pgsql_common.sh $ OLTP_SCRIPT_PATH=${SBTEST_SCRIPTDIR}/oltp_point_select.lua $ . $SBTEST_INCDIR/script_oltp_common.sh sysbench *.* * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Creating table 'sbtest2'... Inserting 10000 records into 'sbtest2' Creating a secondary index on 'sbtest2'... Creating table 'sbtest3'... Inserting 10000 records into 'sbtest3' Creating a secondary index on 'sbtest3'... Creating table 'sbtest4'... Inserting 10000 records into 'sbtest4' Creating a secondary index on 'sbtest4'... Creating table 'sbtest5'... Inserting 10000 records into 'sbtest5' Creating a secondary index on 'sbtest5'... Creating table 'sbtest6'... Inserting 10000 records into 'sbtest6' Creating a secondary index on 'sbtest6'... Creating table 'sbtest7'... Inserting 10000 records into 'sbtest7' Creating a secondary index on 'sbtest7'... Creating table 'sbtest8'... Inserting 10000 records into 'sbtest8' Creating a secondary index on 'sbtest8'... Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_1 ON sbtest1 USING btree (k) CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) Table "public.sbtest2" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest2_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_2 ON sbtest2 USING btree (k) CREATE UNIQUE INDEX sbtest2_pkey ON sbtest2 USING btree (id) Table "public.sbtest3" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest3_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_3 ON sbtest3 USING btree (k) CREATE UNIQUE INDEX sbtest3_pkey ON sbtest3 USING btree (id) Table "public.sbtest4" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest4_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_4 ON sbtest4 USING btree (k) CREATE UNIQUE INDEX sbtest4_pkey ON sbtest4 USING btree (id) Table "public.sbtest5" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest5_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_5 ON sbtest5 USING btree (k) CREATE UNIQUE INDEX sbtest5_pkey ON sbtest5 USING btree (id) Table "public.sbtest6" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest6_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_6 ON sbtest6 USING btree (k) CREATE UNIQUE INDEX sbtest6_pkey ON sbtest6 USING btree (id) Table "public.sbtest7" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest7_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_7 ON sbtest7 USING btree (k) CREATE UNIQUE INDEX sbtest7_pkey ON sbtest7 USING btree (id) Table "public.sbtest8" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest8_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_8 ON sbtest8 USING btree (k) CREATE UNIQUE INDEX sbtest8_pkey ON sbtest8 USING btree (id) Did not find any relation named "sbtest9". sysbench *.* * (glob) FATAL: *: warmup is currently MySQL only (glob) sysbench *.* * (glob) Dropping table 'sbtest1'... Dropping table 'sbtest2'... Dropping table 'sbtest3'... Dropping table 'sbtest4'... Dropping table 'sbtest5'... Dropping table 'sbtest6'... Dropping table 'sbtest7'... Dropping table 'sbtest8'... Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_1 ON sbtest1 USING btree (k) CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) Table "public.sbtest2" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest2_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_2 ON sbtest2 USING btree (k) CREATE UNIQUE INDEX sbtest2_pkey ON sbtest2 USING btree (id) Table "public.sbtest3" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest3_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_3 ON sbtest3 USING btree (k) CREATE UNIQUE INDEX sbtest3_pkey ON sbtest3 USING btree (id) Table "public.sbtest4" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest4_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_4 ON sbtest4 USING btree (k) CREATE UNIQUE INDEX sbtest4_pkey ON sbtest4 USING btree (id) Table "public.sbtest5" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest5_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_5 ON sbtest5 USING btree (k) CREATE UNIQUE INDEX sbtest5_pkey ON sbtest5 USING btree (id) Table "public.sbtest6" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest6_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_6 ON sbtest6 USING btree (k) CREATE UNIQUE INDEX sbtest6_pkey ON sbtest6 USING btree (id) Table "public.sbtest7" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest7_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_7 ON sbtest7 USING btree (k) CREATE UNIQUE INDEX sbtest7_pkey ON sbtest7 USING btree (id) Table "public.sbtest8" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest8_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_8 ON sbtest8 USING btree (k) CREATE UNIQUE INDEX sbtest8_pkey ON sbtest8 USING btree (id) Did not find any relation named "sbtest9". sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 100 write: 0 other: 0 total: 100 transactions: 100 (* per sec.) (glob) queries: 100 (* per sec.) (glob) ignored errors: 0 (* per sec.) (glob) reconnects: 0 (* per sec.) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) Did not find any relation named "sbtest1". Did not find any relation named "sbtest2". Did not find any relation named "sbtest3". Did not find any relation named "sbtest4". Did not find any relation named "sbtest5". Did not find any relation named "sbtest6". Did not find any relation named "sbtest7". Did not find any relation named "sbtest8". # Test --create-secondary=off sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) sysbench * (glob) Dropping table 'sbtest1'... # Test --auto-inc=off Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Dropping table 'sbtest1'... # Test --reconnect reconnects: 20 (* per sec.) (glob) ================================================ FILE: tests/t/script_oltp_read_write_mysql.t ================================================ ######################################################################## oltp_read_write.lua + MySQL tests ######################################################################## $ . $SBTEST_INCDIR/mysql_common.sh $ DB_DRIVER_ARGS="--db-driver=mysql --mysql-storage-engine=myisam $SBTEST_MYSQL_ARGS" $ OLTP_SCRIPT_PATH=${SBTEST_SCRIPTDIR}/oltp_read_write.lua # Override --threads to run read/write tests with a single thread for # deterministic results $ SB_EXTRA_ARGS="--threads=1" $ . $SBTEST_INCDIR/script_oltp_common.sh sysbench *.* * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Creating table 'sbtest2'... Inserting 10000 records into 'sbtest2' Creating a secondary index on 'sbtest2'... Creating table 'sbtest3'... Inserting 10000 records into 'sbtest3' Creating a secondary index on 'sbtest3'... Creating table 'sbtest4'... Inserting 10000 records into 'sbtest4' Creating a secondary index on 'sbtest4'... Creating table 'sbtest5'... Inserting 10000 records into 'sbtest5' Creating a secondary index on 'sbtest5'... Creating table 'sbtest6'... Inserting 10000 records into 'sbtest6' Creating a secondary index on 'sbtest6'... Creating table 'sbtest7'... Inserting 10000 records into 'sbtest7' Creating a secondary index on 'sbtest7'... Creating table 'sbtest8'... Inserting 10000 records into 'sbtest8' Creating a secondary index on 'sbtest8'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest2 CREATE TABLE `sbtest2` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_2` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest3 CREATE TABLE `sbtest3` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_3` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest4 CREATE TABLE `sbtest4` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_4` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest5 CREATE TABLE `sbtest5` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_5` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest6 CREATE TABLE `sbtest6` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_6` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest7 CREATE TABLE `sbtest7` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_7` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest8 CREATE TABLE `sbtest8` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_8` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest9' doesn't exist sysbench * (glob) Preloading table sbtest1 Preloading table sbtest2 Preloading table sbtest3 Preloading table sbtest4 Preloading table sbtest5 Preloading table sbtest6 Preloading table sbtest7 Preloading table sbtest8 sysbench *.* * (glob) Dropping table 'sbtest1'... Dropping table 'sbtest2'... Dropping table 'sbtest3'... Dropping table 'sbtest4'... Dropping table 'sbtest5'... Dropping table 'sbtest6'... Dropping table 'sbtest7'... Dropping table 'sbtest8'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest2 CREATE TABLE `sbtest2` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_2` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest3 CREATE TABLE `sbtest3` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_3` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest4 CREATE TABLE `sbtest4` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_4` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest5 CREATE TABLE `sbtest5` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_5` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest6 CREATE TABLE `sbtest6` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_6` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest7 CREATE TABLE `sbtest7` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_7` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest8 CREATE TABLE `sbtest8` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_8` (`k`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest9' doesn't exist sysbench *.* * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 1400 write: 400 other: 200 total: 2000 transactions: 100 (* per sec.) (glob) queries: 2000 (* per sec.) (glob) ignored errors: 0 (* per sec.) (glob) reconnects: 0 (* per sec.) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest1' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest2' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest3' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest4' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest5' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest6' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest7' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest8' doesn't exist # Test --create-secondary=off sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) sysbench * (glob) Dropping table 'sbtest1'... # Test --auto-inc=off Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Dropping table 'sbtest1'... # Test --reconnect reconnects: 20 (* per sec.) (glob) $ DB_DRIVER_ARGS="--db-driver=mysql --mysql-storage-engine=innodb $SBTEST_MYSQL_ARGS" $ . $SBTEST_INCDIR/script_oltp_common.sh sysbench *.* * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Creating table 'sbtest2'... Inserting 10000 records into 'sbtest2' Creating a secondary index on 'sbtest2'... Creating table 'sbtest3'... Inserting 10000 records into 'sbtest3' Creating a secondary index on 'sbtest3'... Creating table 'sbtest4'... Inserting 10000 records into 'sbtest4' Creating a secondary index on 'sbtest4'... Creating table 'sbtest5'... Inserting 10000 records into 'sbtest5' Creating a secondary index on 'sbtest5'... Creating table 'sbtest6'... Inserting 10000 records into 'sbtest6' Creating a secondary index on 'sbtest6'... Creating table 'sbtest7'... Inserting 10000 records into 'sbtest7' Creating a secondary index on 'sbtest7'... Creating table 'sbtest8'... Inserting 10000 records into 'sbtest8' Creating a secondary index on 'sbtest8'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest2 CREATE TABLE `sbtest2` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_2` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest3 CREATE TABLE `sbtest3` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_3` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest4 CREATE TABLE `sbtest4` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_4` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest5 CREATE TABLE `sbtest5` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_5` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest6 CREATE TABLE `sbtest6` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_6` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest7 CREATE TABLE `sbtest7` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_7` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest8 CREATE TABLE `sbtest8` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_8` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest9' doesn't exist sysbench * (glob) Preloading table sbtest1 Preloading table sbtest2 Preloading table sbtest3 Preloading table sbtest4 Preloading table sbtest5 Preloading table sbtest6 Preloading table sbtest7 Preloading table sbtest8 sysbench *.* * (glob) Dropping table 'sbtest1'... Dropping table 'sbtest2'... Dropping table 'sbtest3'... Dropping table 'sbtest4'... Dropping table 'sbtest5'... Dropping table 'sbtest6'... Dropping table 'sbtest7'... Dropping table 'sbtest8'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest2 CREATE TABLE `sbtest2` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_2` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest3 CREATE TABLE `sbtest3` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_3` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest4 CREATE TABLE `sbtest4` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_4` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest5 CREATE TABLE `sbtest5` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_5` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest6 CREATE TABLE `sbtest6` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_6` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest7 CREATE TABLE `sbtest7` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_7` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) *************************** 1. row *************************** sbtest8 CREATE TABLE `sbtest8` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_8` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest9' doesn't exist sysbench *.* * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 1400 write: 400 other: 200 total: 2000 transactions: 100 (* per sec.) (glob) queries: 2000 (* per sec.) (glob) ignored errors: 0 (* per sec.) (glob) reconnects: 0 (* per sec.) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest1' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest2' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest3' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest4' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest5' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest6' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest7' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest8' doesn't exist # Test --create-secondary=off sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) sysbench * (glob) Dropping table 'sbtest1'... # Test --auto-inc=off Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Dropping table 'sbtest1'... # Test --reconnect reconnects: 20 (* per sec.) (glob) ================================================ FILE: tests/t/script_oltp_read_write_pgsql.t ================================================ ######################################################################## oltp_read_write.lua + PostgreSQL tests ######################################################################## $ . $SBTEST_INCDIR/pgsql_common.sh $ OLTP_SCRIPT_PATH=${SBTEST_SCRIPTDIR}/oltp_read_write.lua # Override --threads to run read/write tests with a single thread for # deterministic results $ SB_EXTRA_ARGS="--threads=1" $ . $SBTEST_INCDIR/script_oltp_common.sh sysbench *.* * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Creating table 'sbtest2'... Inserting 10000 records into 'sbtest2' Creating a secondary index on 'sbtest2'... Creating table 'sbtest3'... Inserting 10000 records into 'sbtest3' Creating a secondary index on 'sbtest3'... Creating table 'sbtest4'... Inserting 10000 records into 'sbtest4' Creating a secondary index on 'sbtest4'... Creating table 'sbtest5'... Inserting 10000 records into 'sbtest5' Creating a secondary index on 'sbtest5'... Creating table 'sbtest6'... Inserting 10000 records into 'sbtest6' Creating a secondary index on 'sbtest6'... Creating table 'sbtest7'... Inserting 10000 records into 'sbtest7' Creating a secondary index on 'sbtest7'... Creating table 'sbtest8'... Inserting 10000 records into 'sbtest8' Creating a secondary index on 'sbtest8'... Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_1 ON sbtest1 USING btree (k) CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) Table "public.sbtest2" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest2_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_2 ON sbtest2 USING btree (k) CREATE UNIQUE INDEX sbtest2_pkey ON sbtest2 USING btree (id) Table "public.sbtest3" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest3_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_3 ON sbtest3 USING btree (k) CREATE UNIQUE INDEX sbtest3_pkey ON sbtest3 USING btree (id) Table "public.sbtest4" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest4_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_4 ON sbtest4 USING btree (k) CREATE UNIQUE INDEX sbtest4_pkey ON sbtest4 USING btree (id) Table "public.sbtest5" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest5_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_5 ON sbtest5 USING btree (k) CREATE UNIQUE INDEX sbtest5_pkey ON sbtest5 USING btree (id) Table "public.sbtest6" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest6_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_6 ON sbtest6 USING btree (k) CREATE UNIQUE INDEX sbtest6_pkey ON sbtest6 USING btree (id) Table "public.sbtest7" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest7_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_7 ON sbtest7 USING btree (k) CREATE UNIQUE INDEX sbtest7_pkey ON sbtest7 USING btree (id) Table "public.sbtest8" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest8_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_8 ON sbtest8 USING btree (k) CREATE UNIQUE INDEX sbtest8_pkey ON sbtest8 USING btree (id) Did not find any relation named "sbtest9". sysbench *.* * (glob) FATAL: *: warmup is currently MySQL only (glob) sysbench *.* * (glob) Dropping table 'sbtest1'... Dropping table 'sbtest2'... Dropping table 'sbtest3'... Dropping table 'sbtest4'... Dropping table 'sbtest5'... Dropping table 'sbtest6'... Dropping table 'sbtest7'... Dropping table 'sbtest8'... Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_1 ON sbtest1 USING btree (k) CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) Table "public.sbtest2" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest2_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_2 ON sbtest2 USING btree (k) CREATE UNIQUE INDEX sbtest2_pkey ON sbtest2 USING btree (id) Table "public.sbtest3" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest3_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_3 ON sbtest3 USING btree (k) CREATE UNIQUE INDEX sbtest3_pkey ON sbtest3 USING btree (id) Table "public.sbtest4" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest4_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_4 ON sbtest4 USING btree (k) CREATE UNIQUE INDEX sbtest4_pkey ON sbtest4 USING btree (id) Table "public.sbtest5" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest5_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_5 ON sbtest5 USING btree (k) CREATE UNIQUE INDEX sbtest5_pkey ON sbtest5 USING btree (id) Table "public.sbtest6" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest6_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_6 ON sbtest6 USING btree (k) CREATE UNIQUE INDEX sbtest6_pkey ON sbtest6 USING btree (id) Table "public.sbtest7" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest7_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_7 ON sbtest7 USING btree (k) CREATE UNIQUE INDEX sbtest7_pkey ON sbtest7 USING btree (id) Table "public.sbtest8" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest8_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_8 ON sbtest8 USING btree (k) CREATE UNIQUE INDEX sbtest8_pkey ON sbtest8 USING btree (id) Did not find any relation named "sbtest9". sysbench *.* * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 1400 write: 400 other: 200 total: 2000 transactions: 100 (* per sec.) (glob) queries: 2000 (* per sec.) (glob) ignored errors: 0 (* per sec.) (glob) reconnects: 0 (* per sec.) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) Did not find any relation named "sbtest1". Did not find any relation named "sbtest2". Did not find any relation named "sbtest3". Did not find any relation named "sbtest4". Did not find any relation named "sbtest5". Did not find any relation named "sbtest6". Did not find any relation named "sbtest7". Did not find any relation named "sbtest8". # Test --create-secondary=off sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) sysbench * (glob) Dropping table 'sbtest1'... # Test --auto-inc=off Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Dropping table 'sbtest1'... # Test --reconnect reconnects: 20 (* per sec.) (glob) ================================================ FILE: tests/t/script_select_random_mysql.t ================================================ ######################################################################## select_random_*.lua + MySQL tests ######################################################################## $ . $SBTEST_INCDIR/mysql_common.sh $ . $SBTEST_INCDIR/script_select_random_common.sh sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest2' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest3' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest4' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest5' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest6' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest7' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest8' doesn't exist sysbench * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 100 write: 0 other: 0 total: 100 transactions: 100 (* per sec.) (glob) queries: 100 (* per sec.) (glob) ignored errors: 0 (0.00 per sec.) reconnects: 0 (0.00 per sec.) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev):* (glob) execution time (avg/stddev):* (glob) sysbench * (glob) Dropping table 'sbtest1'... ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest1' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest2' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest3' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest4' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest5' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest6' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest7' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest8' doesn't exist sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... *************************** 1. row *************************** sbtest1 CREATE TABLE `sbtest1` ( `id` int* NOT NULL AUTO_INCREMENT, (glob) `k` int* NOT NULL DEFAULT '0', (glob) `c` char(120)* NOT NULL DEFAULT '', (glob) `pad` char(60)* NOT NULL DEFAULT '', (glob) PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=* (glob) ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest2' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest3' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest4' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest5' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest6' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest7' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest8' doesn't exist sysbench * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 100 write: 0 other: 0 total: 100 transactions: 100 (* per sec.) (glob) queries: 100 (* per sec.) (glob) ignored errors: 0 (0.00 per sec.) reconnects: 0 (0.00 per sec.) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev):* (glob) execution time (avg/stddev):* (glob) sysbench * (glob) Dropping table 'sbtest1'... ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest1' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest2' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest3' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest4' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest5' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest6' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest7' doesn't exist ERROR 1146 (42S02) at line 1: Table 'sbtest.sbtest8' doesn't exist ================================================ FILE: tests/t/script_select_random_pgsql.t ================================================ ######################################################################## select_random_*.lua + PostgreSQL tests ######################################################################## $ . $SBTEST_INCDIR/pgsql_common.sh $ . $SBTEST_INCDIR/script_select_random_common.sh sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_1 ON sbtest1 USING btree (k) CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) Did not find any relation named "sbtest2". Did not find any relation named "sbtest3". Did not find any relation named "sbtest4". Did not find any relation named "sbtest5". Did not find any relation named "sbtest6". Did not find any relation named "sbtest7". Did not find any relation named "sbtest8". sysbench * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 100 write: 0 other: 0 total: 100 transactions: 100 (* per sec.) (glob) queries: 100 (* per sec.) (glob) ignored errors: 0 (0.00 per sec.) reconnects: 0 (0.00 per sec.) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev):* (glob) execution time (avg/stddev):* (glob) sysbench * (glob) Dropping table 'sbtest1'... Did not find any relation named "sbtest1". Did not find any relation named "sbtest2". Did not find any relation named "sbtest3". Did not find any relation named "sbtest4". Did not find any relation named "sbtest5". Did not find any relation named "sbtest6". Did not find any relation named "sbtest7". Did not find any relation named "sbtest8". sysbench * (glob) Creating table 'sbtest1'... Inserting 10000 records into 'sbtest1' Creating a secondary index on 'sbtest1'... Table "public.sbtest1" Column | Type | Modifiers | Storage | Stats target | Description --------+----------------+------------------------------------------------------+----------+--------------+------------- id | integer | not null default nextval('sbtest1_id_seq'::regclass) | plain | | k | integer | not null default 0 | plain | | c | character(120) | not null default ''::bpchar | extended | | pad | character(60) | not null default ''::bpchar | extended | | Indexes: CREATE INDEX k_1 ON sbtest1 USING btree (k) CREATE UNIQUE INDEX sbtest1_pkey ON sbtest1 USING btree (id) Did not find any relation named "sbtest2". Did not find any relation named "sbtest3". Did not find any relation named "sbtest4". Did not find any relation named "sbtest5". Did not find any relation named "sbtest6". Did not find any relation named "sbtest7". Did not find any relation named "sbtest8". sysbench * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Initializing worker threads... Threads started! SQL statistics: queries performed: read: 100 write: 0 other: 0 total: 100 transactions: 100 (* per sec.) (glob) queries: 100 (* per sec.) (glob) ignored errors: 0 (0.00 per sec.) reconnects: 0 (0.00 per sec.) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev):* (glob) execution time (avg/stddev):* (glob) sysbench * (glob) Dropping table 'sbtest1'... Did not find any relation named "sbtest1". Did not find any relation named "sbtest2". Did not find any relation named "sbtest3". Did not find any relation named "sbtest4". Did not find any relation named "sbtest5". Did not find any relation named "sbtest6". Did not find any relation named "sbtest7". Did not find any relation named "sbtest8". ================================================ FILE: tests/t/test_cpu.t ================================================ ######################################################################## cpu benchmark tests ######################################################################## $ args="cpu --cpu-max-prime=1000 --events=100 --threads=2" $ sysbench $args help sysbench *.* * (glob) cpu options: --cpu-max-prime=N upper limit for primes generator [10000] $ sysbench $args prepare sysbench *.* * (glob) 'cpu' test does not implement the 'prepare' command. [1] $ sysbench $args run sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Prime numbers limit: 1000 Initializing worker threads... Threads started! CPU speed: events per second: *.* (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): 50.0000/* (glob) execution time (avg/stddev): */* (glob) $ sysbench $args cleanup sysbench *.* * (glob) 'cpu' test does not implement the 'cleanup' command. [1] ================================================ FILE: tests/t/test_fileio.t ================================================ ######################################################################## fileio benchmark tests ######################################################################## $ fileio_args="fileio --file-num=4 --file-total-size=32M" $ sysbench $fileio_args prepare sysbench *.* * (glob) 4 files, 8192Kb each, 32Mb total Creating files for the test... Extra file open flags: (none) Creating file test_file.0 Creating file test_file.1 Creating file test_file.2 Creating file test_file.3 33554432 bytes written in * seconds (*.* MiB/sec). (glob) $ ls test_file.* test_file.0 test_file.1 test_file.2 test_file.3 $ for i in $(seq 0 3) > do > echo -n "test_file.$i: " > echo $(wc -c < test_file.$i) > done test_file.0: 8388608 test_file.1: 8388608 test_file.2: 8388608 test_file.3: 8388608 $ sysbench $fileio_args run | grep FATAL FATAL: Missing required argument: --file-test-mode $ sysbench $fileio_args --events=150 --file-test-mode=rndrw run sysbench *.* * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Extra file open flags: (none) 4 files, 8MiB each 32MiB total file size Block size 16KiB Number of IO requests: 150 Read/Write ratio for combined random IO test: 1.50 Periodic FSYNC enabled, calling fsync() each 100 requests. Calling fsync() at the end of test, Enabled. Using synchronous I/O mode Doing random r/w test Initializing worker threads... Threads started! Throughput: read: IOPS=*.* *.* MiB/s (*.* MB/s) (glob) write: IOPS=*.* *.* MiB/s (*.* MB/s) (glob) fsync: IOPS=*.* (glob) Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) $ sysbench $fileio_args --events=150 --file-test-mode=rndrd run sysbench *.* * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Extra file open flags: (none) 4 files, 8MiB each 32MiB total file size Block size 16KiB Number of IO requests: 150 Read/Write ratio for combined random IO test: 1.50 Periodic FSYNC enabled, calling fsync() each 100 requests. Calling fsync() at the end of test, Enabled. Using synchronous I/O mode Doing random read test Initializing worker threads... Threads started! Throughput: read: IOPS=*.* *.* MiB/s (*.* MB/s) (glob) write: IOPS=*.* *.* MiB/s (*.* MB/s) (glob) fsync: IOPS=*.* (glob) Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) $ sysbench $fileio_args --events=150 --file-test-mode=seqrd run sysbench *.* * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Extra file open flags: (none) 4 files, 8MiB each 32MiB total file size Block size 16KiB Periodic FSYNC enabled, calling fsync() each 100 requests. Calling fsync() at the end of test, Enabled. Using synchronous I/O mode Doing sequential read test Initializing worker threads... Threads started! Throughput: read: IOPS=*.* *.* MiB/s (*.* MB/s) (glob) write: IOPS=*.* *.* MiB/s (*.* MB/s) (glob) fsync: IOPS=*.* (glob) Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) $ sysbench $fileio_args --events=150 --file-test-mode=rndwr run sysbench *.* * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Extra file open flags: (none) 4 files, 8MiB each 32MiB total file size Block size 16KiB Number of IO requests: 150 Read/Write ratio for combined random IO test: 1.50 Periodic FSYNC enabled, calling fsync() each 100 requests. Calling fsync() at the end of test, Enabled. Using synchronous I/O mode Doing random write test Initializing worker threads... Threads started! Throughput: read: IOPS=*.* *.* MiB/s (*.* MB/s) (glob) write: IOPS=*.* *.* MiB/s (*.* MB/s) (glob) fsync: IOPS=*.* (glob) Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) $ sysbench $fileio_args --events=150 --file-test-mode=rndwr --validate run | grep Validation Validation checks: on. $ sysbench $fileio_args --events=150 --file-test-mode=foo run sysbench *.* * (glob) FATAL: Invalid IO operations mode: foo. [1] $ sysbench $fileio_args cleanup sysbench *.* * (glob) Removing test files... $ ls $ sysbench $fileio_args --file-test-mode=rndrw --verbosity=2 run FATAL: Cannot open file 'test_file.0' errno = 2 (No such file or directory) WARNING: Did you forget to run the prepare step? [1] ######################################################################## GH-196: fileio: validate file sizes on startup ######################################################################## $ args="$fileio_args --verbosity=2" $ sysbench $args --file-total-size=1M prepare $ sysbench $args --file-test-mode=rndwr --events=1 run FATAL: Size of file 'test_file.0' is 256KiB, but at least 8MiB is expected. WARNING: Did you run 'prepare' with different --file-total-size or --file-num values? [1] $ sysbench $args cleanup $ sysbench $args --file-num=8 prepare $ sysbench $args --file-test-mode=rndwr --events=1 run FATAL: Size of file 'test_file.0' is 4MiB, but at least 8MiB is expected. WARNING: Did you run 'prepare' with different --file-total-size or --file-num values? [1] $ sysbench $args --file-num=8 cleanup $ sysbench $args --file-total-size=1M prepare $ sysbench $args --file-test-mode=seqwr --events=1 run $ sysbench $args cleanup $ unset args ######################################################################## GH-198: Tolerate misaligned test_files. ######################################################################## $ args="$fileio_args --verbosity=2 --file-total-size=1M --file-num=128 --file-block-size=4097 --events=2" $ sysbench $args --file-total-size=1M prepare $ sysbench $args --file-test-mode=seqrd run $ sysbench $args --file-test-mode=rndrd run $ sysbench $args cleanup $ unset args ######################################################################## Extra file flags. Not testing 'direct' as that is not supported on all tested platforms ######################################################################## $ args="$fileio_args --file-total-size=16K --file-num=1" $ sysbench $args --file-extra-flags= prepare sysbench * (glob) 1 files, 16Kb each, 0Mb total Creating files for the test... Extra file open flags: (none) Creating file test_file.0 16384 bytes written in * seconds (* MiB/sec). (glob) $ sysbench $args --file-extra-flags=sync prepare sysbench * (glob) 1 files, 16Kb each, 0Mb total Creating files for the test... Extra file open flags: sync Reusing existing file test_file.0 No bytes written. $ sysbench $args --file-extra-flags=dsync prepare sysbench * (glob) 1 files, 16Kb each, 0Mb total Creating files for the test... Extra file open flags: dsync Reusing existing file test_file.0 No bytes written. $ sysbench $args --file-extra-flags=dsync,sync prepare sysbench * (glob) 1 files, 16Kb each, 0Mb total Creating files for the test... Extra file open flags: sync dsync Reusing existing file test_file.0 No bytes written. $ sysbench $args --file-extra-flags= cleanup sysbench * (glob) Removing test files... ######################################################################## GH-229: "--file-fsync-freq=0" seems to prevent fsync() at end of test ######################################################################## $ args="fileio --file-total-size=160K --file-num=10 --file-test-mode=seqwr" $ args="$args --file-fsync-freq=0 --file-fsync-end=1" $ args="$args --events=0 --time=1" $ sysbench $args prepare sysbench * (glob) 10 files, 16Kb each, 0Mb total Creating files for the test... Extra file open flags: (none) Creating file test_file.0 Creating file test_file.1 Creating file test_file.2 Creating file test_file.3 Creating file test_file.4 Creating file test_file.5 Creating file test_file.6 Creating file test_file.7 Creating file test_file.8 Creating file test_file.9 163840 bytes written in * seconds (* MiB/sec). (glob) $ sysbench $args run sysbench * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Extra file open flags: (none) 10 files, 16KiB each 160KiB total file size Block size 16KiB Calling fsync() at the end of test, Enabled. Using synchronous I/O mode Doing sequential write (creation) test Initializing worker threads... Threads started! Throughput: read: IOPS=0.00 0.00 MiB/s (0.00 MB/s) write: IOPS=[^0].* [^0].* MiB/s \([^0].* MB/s\) (re) fsync: IOPS=[^0].* (re) Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) $ sysbench $args --file-fsync-end=off run sysbench * (glob) Running the test with following options: Number of threads: 1 Initializing random number generator from current time Extra file open flags: (none) 10 files, 16KiB each 160KiB total file size Block size 16KiB Using synchronous I/O mode Doing sequential write (creation) test Initializing worker threads... Threads started! Throughput: read: IOPS=0.00 0.00 MiB/s (0.00 MB/s) write: IOPS=[^0].* [^0].* MiB/s \([^0].* MB/s\) (re) fsync: IOPS=0.00 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) ================================================ FILE: tests/t/test_memory.t ================================================ ######################################################################## memory benchmark tests ######################################################################## $ args="memory --memory-block-size=4K --memory-total-size=1G --events=1 --time=0 --threads=2" The --memory-hugetlb option is supported and printed by 'sysbench help' only on Linux. $ if [ "$(uname -s)" = "Linux" ] > then > sysbench $args help | grep hugetlb > else > echo " --memory-hugetlb[=on|off] allocate memory from HugeTLB pool [off]" > fi --memory-hugetlb[=on|off] allocate memory from HugeTLB pool [off] $ sysbench $args help | grep -v hugetlb sysbench * (glob) memory options: --memory-block-size=SIZE size of memory block for test [1K] --memory-total-size=SIZE total size of data to transfer [100G] --memory-scope=STRING memory access scope {global,local} [global] --memory-oper=STRING type of memory operations {read, write, none} [write] --memory-access-mode=STRING memory access mode {seq,rnd} [seq] $ sysbench $args prepare sysbench *.* * (glob) 'memory' test does not implement the 'prepare' command. [1] $ sysbench $args --memory-block-size=-1 run sysbench * (glob) FATAL: Invalid value for memory-block-size: -1 [1] $ sysbench $args --memory-block-size=0 run sysbench * (glob) FATAL: Invalid value for memory-block-size: 0 [1] $ sysbench $args --memory-block-size=3 run sysbench * (glob) FATAL: Invalid value for memory-block-size: 3 [1] $ sysbench $args --memory-block-size=9 run sysbench * (glob) FATAL: Invalid value for memory-block-size: 9 [1] ######################################################################## # Global reads ######################################################################## $ sysbench $args --memory-oper=read run sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Running memory speed test with the following options: block size: 4KiB total size: 1024MiB operation: read scope: global Initializing worker threads... Threads started! Total operations: 262144 (* per second) (glob) 1024.00 MiB transferred (* MiB/sec) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 262144 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) ######################################################################## # Global writes ######################################################################## $ sysbench $args --memory-oper=write run sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Running memory speed test with the following options: block size: 4KiB total size: 1024MiB operation: write scope: global Initializing worker threads... Threads started! Total operations: 262144 (* per second) (glob) 1024.00 MiB transferred (* MiB/sec) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 262144 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) ######################################################################## # Local reads ######################################################################## $ sysbench $args --memory-scope=local --memory-oper=read run sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Running memory speed test with the following options: block size: 4KiB total size: 1024MiB operation: read scope: local Initializing worker threads... Threads started! Total operations: 262144 (* per second) (glob) 1024.00 MiB transferred (* MiB/sec) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 262144 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) ######################################################################## # Local writes ######################################################################## $ sysbench $args --memory-scope=local --memory-oper=write run sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Running memory speed test with the following options: block size: 4KiB total size: 1024MiB operation: write scope: local Initializing worker threads... Threads started! Total operations: 262144 (* per second) (glob) 1024.00 MiB transferred (* MiB/sec) (glob) Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 262144 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) $ sysbench $args cleanup sysbench *.* * (glob) 'memory' test does not implement the 'cleanup' command. [1] ================================================ FILE: tests/t/test_mutex.t ================================================ ######################################################################## mutex benchmark tests ######################################################################## $ args="mutex --events=10 --threads=2" $ sysbench $args help sysbench *.* * (glob) mutex options: --mutex-num=N total size of mutex array [4096] --mutex-locks=N number of mutex locks to do per thread [50000] --mutex-loops=N number of empty loops to do outside mutex lock [10000] $ sysbench $args prepare sysbench *.* * (glob) 'mutex' test does not implement the 'prepare' command. [1] $ sysbench $args run sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 2 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) $ sysbench $args cleanup sysbench *.* * (glob) 'mutex' test does not implement the 'cleanup' command. [1] ================================================ FILE: tests/t/test_threads.t ================================================ ######################################################################## threads benchmark tests ######################################################################## $ args="threads --events=100 --threads=2" $ sysbench $args help sysbench *.* * (glob) threads options: --thread-yields=N number of yields to do per request [1000] --thread-locks=N number of locks per thread [8] $ sysbench $args prepare sysbench *.* * (glob) 'threads' test does not implement the 'prepare' command. [1] $ sysbench $args run sysbench *.* * (glob) Running the test with following options: Number of threads: 2 Initializing random number generator from current time Initializing worker threads... Threads started! Throughput: events/s (eps): *.* (glob) time elapsed: *s (glob) total number of events: 100 Latency (ms): min: *.* (glob) avg: *.* (glob) max: *.* (glob) 95th percentile: *.* (glob) sum: *.* (glob) Threads fairness: events (avg/stddev): */* (glob) execution time (avg/stddev): */* (glob) $ sysbench $args cleanup sysbench *.* * (glob) 'threads' test does not implement the 'cleanup' command. [1] ================================================ FILE: tests/t/tests.t ================================================ ######################################################################## Make sure all built-in tests are covered ######################################################################## $ tests=$(sysbench --help | sed -n '/Compiled-in tests:/,/^$/p' | tail -n +2 | cut -d ' ' -f 3) $ for t in $tests > do > if [ ! -r ${SBTEST_SUITEDIR}/test_${t}.t ] > then > echo "Cannot find regression test(s) for 'sysbench $t'!" > exit 1 > fi > done ================================================ FILE: tests/test_run.sh ================================================ #!/usr/bin/env bash # Copyright (C) 2016-2017 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA set -eu testroot=$(cd $(dirname "$0"); echo $PWD) # Find the sysbench binary to use dirlist=( "$testroot/../src" # source directory "$testroot/../bin" # standalone install root directory "$testroot/../../../bin" # system-wide install (e.g. /usr/local/share/sysbench/tests) "$PWD/../src" ) # build directory by 'make distcheck' for dir in ${dirlist[@]} do if [ -x "$dir/sysbench" ] then sysbench_dir="$dir" break fi done if [ -z ${sysbench_dir+x} ] then echo "Cannot find sysbench in the following list of directories: \ ${dirlist[@]}" exit 1 fi if [ -z ${srcdir+x} ] then SBTEST_INCDIR="$PWD/include" SBTEST_CONFIG="$SBTEST_INCDIR/config.sh" if [ $# -lt 1 ] then tests="t/*.t" fi else # SBTEST_INCDIR must be an absolute path, because cram changes CWD to a # temporary directory when executing tests. That's why we can just use # $srcdir here SBTEST_INCDIR="$(cd $srcdir; echo $PWD)/include" SBTEST_CONFIG="$PWD/include/config.sh" if [ $# -lt 1 ] then tests="$srcdir/t/*.t" fi fi if [ -z ${tests+x} ] then tests="$*" fi export SBTEST_ROOTDIR="$testroot" export SBTEST_SCRIPTDIR="$testroot/../src/lua" export SBTEST_SUITEDIR="$testroot/t" export SBTEST_CONFIG export SBTEST_INCDIR # Add directories containing sysbench and cram to PATH export PATH="${sysbench_dir}:${SBTEST_ROOTDIR}/../third_party/cram/scripts:$PATH" export PYTHONPATH="${SBTEST_ROOTDIR}/../third_party/cram:${PYTHONPATH:-}" LUA_PATH="$SBTEST_SCRIPTDIR/?;$SBTEST_SCRIPTDIR/?.lua" LUA_PATH="$LUA_PATH;$SBTEST_INCDIR/?;$SBTEST_INCDIR/?.lua" export LUA_PATH . $SBTEST_CONFIG if $(command -v python >/dev/null 2>&1) then PYTHON=python elif $(command -v python3 >/dev/null 2>&1) then PYTHON=python3 elif $(command -v python2 >/dev/null 2>&1) then PYTHON=python2 else echo "Cannot find python interpreter in PATH" exit 1 fi $PYTHON $(command -v cram) --shell=/bin/bash --verbose $tests ================================================ FILE: third_party/concurrency_kit/Makefile.am ================================================ # Copyright (C) 2016 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA EXTRA_DIST = ck all-local: $(builddir)/lib/libck.a # Concurrency Kit does not support VPATH builds $(builddir)/lib/libck.a: rm -rf tmp mkdir tmp tar -C $(srcdir) -cf - ck | tar -xf - -C tmp/ chmod -R u+w tmp cd tmp/ck && \ CC="$(CC)" \ CFLAGS="$(CFLAGS) $(CPPFLAGS)" \ LDFLAGS="$(LDFLAGS)" \ ./configure ${CK_CONFIGURE_FLAGS} \ --prefix=$(abs_top_builddir)/third_party/concurrency_kit && \ $(MAKE) && \ $(MAKE) install clean-local: rm -rf tmp include lib share ================================================ FILE: third_party/concurrency_kit/ck/.gitignore ================================================ /Makefile build/ck.build build/ck.pc build/regressions.build build/ck.spec include/ck_md.h src/Makefile doc/Makefile doc/*.3 build/Makefile .DS_Store LOG *.log *.html *.gz *.o *.a *.so *.dSYM .*.sw[op] GPATH GRTAGS GTAGS ID regressions/ck_array/validate/serial regressions/ck_backoff/validate/validate regressions/ck_bag/validate/order regressions/ck_barrier/benchmark/throughput regressions/ck_barrier/validate/barrier_centralized regressions/ck_barrier/validate/barrier_combining regressions/ck_barrier/validate/barrier_dissemination regressions/ck_barrier/validate/barrier_mcs regressions/ck_barrier/validate/barrier_tournament regressions/ck_bitmap/validate/serial regressions/ck_brlock/benchmark/latency regressions/ck_brlock/benchmark/throughput regressions/ck_brlock/validate/validate regressions/ck_bytelock/benchmark/latency regressions/ck_bytelock/validate/validate regressions/ck_cohort/benchmark/ck_cohort.LATENCY regressions/ck_cohort/benchmark/ck_cohort.THROUGHPUT regressions/ck_cohort/validate/validate regressions/ck_epoch/validate/ck_epoch_call regressions/ck_epoch/validate/ck_epoch_poll regressions/ck_epoch/validate/ck_epoch_section regressions/ck_epoch/validate/ck_epoch_section_2 regressions/ck_epoch/validate/torture regressions/ck_epoch/validate/ck_epoch_synchronize regressions/ck_epoch/validate/ck_stack regressions/ck_epoch/validate/ck_stack_read regressions/ck_fifo/benchmark/latency regressions/ck_fifo/validate/ck_fifo_mpmc regressions/ck_fifo/validate/ck_fifo_mpmc_iterator regressions/ck_fifo/validate/ck_fifo_spsc regressions/ck_fifo/validate/ck_fifo_spsc_iterator regressions/ck_hp/benchmark/fifo_latency regressions/ck_hp/benchmark/stack_latency regressions/ck_hp/validate/ck_hp_fifo regressions/ck_hp/validate/ck_hp_fifo_donner regressions/ck_hp/validate/ck_hp_stack regressions/ck_hp/validate/nbds_haz_test regressions/ck_hp/validate/serial regressions/ck_hs/benchmark/apply regressions/ck_hs/benchmark/parallel_bytestring regressions/ck_hs/benchmark/parallel_bytestring.delete regressions/ck_hs/benchmark/serial regressions/ck_hs/validate/serial regressions/ck_ht/benchmark/parallel_bytestring regressions/ck_ht/benchmark/parallel_bytestring.delete regressions/ck_ht/benchmark/parallel_direct regressions/ck_ht/benchmark/serial regressions/ck_ht/benchmark/serial.delete regressions/ck_ht/validate/serial regressions/ck_ht/validate/serial.delete regressions/ck_pflock/benchmark/latency regressions/ck_pflock/benchmark/throughput regressions/ck_pflock/validate/validate regressions/ck_pr/benchmark/ck_pr_cas_64 regressions/ck_pr/benchmark/ck_pr_cas_64_2 regressions/ck_pr/benchmark/ck_pr_fas_64 regressions/ck_pr/benchmark/fp regressions/ck_pr/validate/ck_pr_add regressions/ck_pr/validate/ck_pr_and regressions/ck_pr/validate/ck_pr_bin regressions/ck_pr/validate/ck_pr_btc regressions/ck_pr/validate/ck_pr_btr regressions/ck_pr/validate/ck_pr_bts regressions/ck_pr/validate/ck_pr_btx regressions/ck_pr/validate/ck_pr_cas regressions/ck_pr/validate/ck_pr_dec regressions/ck_pr/validate/ck_pr_faa regressions/ck_pr/validate/ck_pr_fas regressions/ck_pr/validate/ck_pr_fax regressions/ck_pr/validate/ck_pr_inc regressions/ck_pr/validate/ck_pr_load regressions/ck_pr/validate/ck_pr_n regressions/ck_pr/validate/ck_pr_or regressions/ck_pr/validate/ck_pr_store regressions/ck_pr/validate/ck_pr_sub regressions/ck_pr/validate/ck_pr_unary regressions/ck_pr/validate/ck_pr_xor regressions/ck_queue/validate/ck_list regressions/ck_queue/validate/ck_slist regressions/ck_queue/validate/ck_stailq regressions/ck_rhs/benchmark/parallel_bytestring regressions/ck_rhs/benchmark/serial regressions/ck_rhs/validate/serial regressions/ck_ring/benchmark/latency regressions/ck_ring/validate/ck_ring_spmc regressions/ck_ring/validate/ck_ring_spmc_template regressions/ck_ring/validate/ck_ring_spsc regressions/ck_ring/validate/ck_ring_spsc_template regressions/ck_ring/validate/ck_ring_mpmc regressions/ck_ring/validate/ck_ring_mpmc_template regressions/ck_rwcohort/benchmark/ck_neutral.LATENCY regressions/ck_rwcohort/benchmark/ck_neutral.THROUGHPUT regressions/ck_rwcohort/benchmark/ck_rp.LATENCY regressions/ck_rwcohort/benchmark/ck_rp.THROUGHPUT regressions/ck_rwcohort/benchmark/ck_wp.LATENCY regressions/ck_rwcohort/benchmark/ck_wp.THROUGHPUT regressions/ck_rwcohort/validate/ck_neutral regressions/ck_rwcohort/validate/ck_rp regressions/ck_rwcohort/validate/ck_wp regressions/ck_rwlock/benchmark/latency regressions/ck_rwlock/benchmark/throughput regressions/ck_rwlock/validate/validate regressions/ck_sequence/benchmark/ck_sequence regressions/ck_sequence/validate/ck_sequence regressions/ck_spinlock/benchmark/ck_anderson.LATENCY regressions/ck_spinlock/benchmark/ck_anderson.THROUGHPUT regressions/ck_spinlock/benchmark/ck_cas.LATENCY regressions/ck_spinlock/benchmark/ck_cas.THROUGHPUT regressions/ck_spinlock/benchmark/ck_clh.LATENCY regressions/ck_spinlock/benchmark/ck_clh.THROUGHPUT regressions/ck_spinlock/benchmark/ck_dec.LATENCY regressions/ck_spinlock/benchmark/ck_dec.THROUGHPUT regressions/ck_spinlock/benchmark/ck_fas.LATENCY regressions/ck_spinlock/benchmark/ck_fas.THROUGHPUT regressions/ck_spinlock/benchmark/ck_hclh.LATENCY regressions/ck_spinlock/benchmark/ck_hclh.THROUGHPUT regressions/ck_spinlock/benchmark/ck_mcs.LATENCY regressions/ck_spinlock/benchmark/ck_mcs.THROUGHPUT regressions/ck_spinlock/benchmark/ck_spinlock.LATENCY regressions/ck_spinlock/benchmark/ck_spinlock.THROUGHPUT regressions/ck_spinlock/benchmark/ck_ticket.LATENCY regressions/ck_spinlock/benchmark/ck_ticket.THROUGHPUT regressions/ck_spinlock/benchmark/ck_ticket_pb.LATENCY regressions/ck_spinlock/benchmark/ck_ticket_pb.THROUGHPUT regressions/ck_spinlock/benchmark/linux_spinlock.LATENCY regressions/ck_spinlock/benchmark/linux_spinlock.THROUGHPUT regressions/ck_spinlock/validate/ck_anderson regressions/ck_spinlock/validate/ck_cas regressions/ck_spinlock/validate/ck_clh regressions/ck_spinlock/validate/ck_dec regressions/ck_spinlock/validate/ck_fas regressions/ck_spinlock/validate/ck_hclh regressions/ck_spinlock/validate/ck_mcs regressions/ck_spinlock/validate/ck_spinlock regressions/ck_spinlock/validate/ck_ticket regressions/ck_spinlock/validate/ck_ticket_pb regressions/ck_spinlock/validate/linux_spinlock regressions/ck_stack/benchmark/latency regressions/ck_stack/validate/mpmc_pair regressions/ck_stack/validate/mpmc_pop regressions/ck_stack/validate/mpmc_push regressions/ck_stack/validate/mpmc_trypair regressions/ck_stack/validate/mpmc_trypop regressions/ck_stack/validate/mpmc_trypush regressions/ck_stack/validate/mpnc_push regressions/ck_stack/validate/pthreads_pair regressions/ck_stack/validate/serial regressions/ck_stack/validate/spinlock_eb_pair regressions/ck_stack/validate/spinlock_eb_pop regressions/ck_stack/validate/spinlock_eb_push regressions/ck_stack/validate/spinlock_pair regressions/ck_stack/validate/spinlock_pop regressions/ck_stack/validate/spinlock_push regressions/ck_stack/validate/upmc_pop regressions/ck_stack/validate/upmc_push regressions/ck_stack/validate/upmc_trypop regressions/ck_stack/validate/upmc_trypush regressions/ck_swlock/benchmark/latency regressions/ck_swlock/benchmark/throughput regressions/ck_swlock/validate/validate regressions/ck_tflock/benchmark/latency regressions/ck_tflock/benchmark/throughput regressions/ck_tflock/validate/validate ================================================ FILE: third_party/concurrency_kit/ck/LICENSE ================================================ Copyright 2010-2014 Samy Al Bahra. Copyright 2011-2013 AppNexus, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Hazard Pointers (src/ck_hp.c) also includes this license: (c) Copyright 2008, IBM Corporation. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ck_pr_rtm leverages work from Andi Kleen: Copyright (c) 2012,2013 Intel Corporation Redistribution and use in source and binary forms, with or without modification, are permitted provided that: (1) source code distributions retain the above copyright notice and this paragraph in its entirety, (2) distributions including binary code include the above copyright notice and this paragraph in its entirety in the documentation or other materials provided with the distribution THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ================================================ FILE: third_party/concurrency_kit/ck/README ================================================ ____ _ ___ _ / ___|___ _ __ ___ _ _ _ __ _ __ ___ _ __ ___ _ _ | |/ (_) |_ | | / _ \| '_ \ / __| | | | '__| '__/ _ \ '_ \ / __| | | | | ' /| | __| | |__| (_) | | | | (__| |_| | | | | | __/ | | | (__| |_| | | . \| | |_ \____\___/|_| |_|\___|\__,_|_| |_| \___|_| |_|\___|\__, | |_|\_\_|\__| |___/ Step 1. ./configure For additional options try ./configure --help Step 2. In order to compile regressions (requires POSIX threads) use "make regressions". In order to compile libck use "make all" or "make". Step 3. In order to install use "make install" To uninstall use "make uninstall". See http://concurrencykit.org/ for more information. ================================================ FILE: third_party/concurrency_kit/ck/build/ck.build.aarch64 ================================================ ================================================ FILE: third_party/concurrency_kit/ck/build/ck.build.arm ================================================ CFLAGS+=-D__arm__ ================================================ FILE: third_party/concurrency_kit/ck/build/ck.build.in ================================================ CC=@CC@ MAKE=make SRC_DIR=@SRC_DIR@ BUILD_DIR=@BUILD_DIR@ CFLAGS+=@CFLAGS@ -I$(SRC_DIR)/include -I$(BUILD_DIR)/include LDFLAGS+=@LDFLAGS@ ALL_LIBS=@ALL_LIBS@ LD=@LD@ include $(BUILD_DIR)/build/ck.build.@PROFILE@ ================================================ FILE: third_party/concurrency_kit/ck/build/ck.build.ppc ================================================ CFLAGS+=-m32 -D__ppc__ ================================================ FILE: third_party/concurrency_kit/ck/build/ck.build.ppc64 ================================================ CFLAGS+=-m64 -D__ppc64__ LDFLAGS+=-m64 ================================================ FILE: third_party/concurrency_kit/ck/build/ck.build.s390x ================================================ CFLAGS+=-O2 -D__s390x__ ================================================ FILE: third_party/concurrency_kit/ck/build/ck.build.sparcv9 ================================================ CFLAGS+=-m64 -D__sparcv9__ ================================================ FILE: third_party/concurrency_kit/ck/build/ck.build.x86 ================================================ CFLAGS+=-m32 -D__x86__ -msse -msse2 LDFLAGS+=-m32 ================================================ FILE: third_party/concurrency_kit/ck/build/ck.build.x86_64 ================================================ CFLAGS+=-m64 -D__x86_64__ LDFLAGS+=-m64 ================================================ FILE: third_party/concurrency_kit/ck/build/ck.pc.in ================================================ prefix=@PREFIX@ includedir=@HEADERS@ libdir=@LIBRARY@ Name: Concurrency Kit Description: Toolkit for well-specified design and implementation of concurrent systems URL: http://concurrencykit.org/ Version: @VERSION@ Libs: -L${libdir} -lck Cflags: -D__@PROFILE@__ -I${includedir} @PC_CFLAGS@ ================================================ FILE: third_party/concurrency_kit/ck/build/ck.spec.in ================================================ Name: ck Version: @VERSION@ Release: 1%{?dist} Group: Development/Libraries Summary: Concurrency Kit License: Simplified BSD License URL: http://concurrencykit.org BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Source: http://concurrencykit.org/releases/ck-%{version}.tar.gz %description Concurrency Kit provides a plethora of concurrency primitives, safe memory reclamation mechanisms and lock-less and lock-free data structures designed to aid in the design and implementation of high performance concurrent systems. It is designed to minimize dependencies on operating system-specific interfaces and most of the interface relies only on a strict subset of the standard library and more popular compiler extensions. %package devel Group: Development/Libraries Summary: Header files and libraries for CK development Requires: %{name} = %{version}-%{release} %description devel Concurrency Kit provides a plethora of concurrency primitives, safe memory reclamation mechanisms and lock-less and lock-free data structures designed to aid in the design and implementation of high performance concurrent systems. It is designed to minimize dependencies on operating system-specific interfaces and most of the interface relies only on a strict subset of the standard library and more popular compiler extensions. This package provides the libraries, include files, and other resources needed for developing Concurrency Kit applications. %prep %setup -q %build CFLAGS=$RPM_OPT_FLAGS ./configure \ --libdir=%{_libdir} \ --includedir=%{_includedir}/%{name} \ --mandir=%{_mandir} \ --prefix=%{_prefix} make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) %{_libdir}/libck.so.@VERSION@ %{_libdir}/libck.so.@VERSION_MAJOR@ %files devel %defattr(-,root,root) %{_libdir}/libck.so %{_includedir}/%{name}/*.h %{_includedir}/%{name}/*/*.h %{_includedir}/%{name}/*/*/*.h %{_libdir}/libck.a %{_libdir}/pkgconfig/%{name}.pc %{_mandir}/man3/*.3.gz %post /sbin/ldconfig %postun /sbin/ldconfig ================================================ FILE: third_party/concurrency_kit/ck/build/regressions.build.in ================================================ CC=@CC@ MAKE=make CORES=@CORES@ CFLAGS=@CFLAGS@ -I../../../include -DCORES=@CORES@ LD=@LD@ LDFLAGS=@LDFLAGS@ PTHREAD_CFLAGS=@PTHREAD_CFLAGS@ BUILD_DIR=@BUILD_DIR@ include $(BUILD_DIR)/build/ck.build.@PROFILE@ ================================================ FILE: third_party/concurrency_kit/ck/configure ================================================ #!/bin/sh # # Copyright © 2009-2013 Samy Al Bahra. # Copyright © 2011 Devon H. O'Dell # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # REQUIRE_HEADER="stdbool.h stddef.h stdint.h string.h" EXIT_SUCCESS=0 EXIT_FAILURE=1 WANT_PIC=yes P_PWD=`pwd` MAINTAINER='sbahra@repnop.org' VERSION=${VERSION:-'1.0.0'} VERSION_MAJOR='0' BUILD="$PWD/build/ck.build" PREFIX=${PREFIX:-"/usr/local"} LDNAME="libck.so" LDNAME_VERSION="libck.so.$VERSION" LDNAME_MAJOR="libck.so.$VERSION_MAJOR" OPTION_CHECKING=1 export CFLAGS export PREFIX LC_ALL=C export LC_ALL if test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi trap epilog 1 2 3 6 epilog() { rm -f .1.c .1 } assert() { if test "$#" -eq 2; then fail=$2 print=true elif test "$#" -eq 3; then fail=$3 print=echo else echo "Usage: assert or assert " 1>&2 exit $EXIT_FAILURE fi if test -z "$1"; then echo "failed [$fail]" exit $EXIT_FAILURE else ${print} "success [$1]" fi } get_git_sha() { # return a short SHA for the current HEAD GIT_SHA="" GIT_MSG="success" gitcmd=`which git` if test -n "$gitcmd"; then GIT_SHA=`git rev-parse --short HEAD 2>/dev/null` if ! test -n "$GIT_SHA"; then GIT_MSG="not within a git repo" fi else GIT_MSG="git not installed or executable" fi } generate() { sed -e "s#@PROFILE@#$PROFILE#g" \ -e "s#@VERSION@#$VERSION#g" \ -e "s#@VERSION_MAJOR@#$VERSION_MAJOR#g" \ -e "s#@CC@#$CC#g" \ -e "s#@CFLAGS@#$CFLAGS#g" \ -e "s#@HEADERS@#$HEADERS#g" \ -e "s#@LIBRARY@#$LIBRARY#g" \ -e "s#@PREFIX@#$PREFIX#g" \ -e "s#@CORES@#$CORES#g" \ -e "s#@ALL_LIBS@#$ALL_LIBS#g" \ -e "s#@INSTALL_LIBS@#$INSTALL_LIBS#g" \ -e "s#@LD@#$LD#g" \ -e "s#@LDFLAGS@#$LDFLAGS#g" \ -e "s#@PTHREAD_CFLAGS@#$PTHREAD_CFLAGS#g" \ -e "s#@MANDIR@#$MANDIR#g" \ -e "s#@GZIP@#$GZIP#g" \ -e "s#@GZIP_SUFFIX@#$GZIP_SUFFIX#g" \ -e "s#@POINTER_PACK_ENABLE@#$POINTER_PACK_ENABLE#g" \ -e "s#@DISABLE_DOUBLE@#$DISABLE_DOUBLE#g" \ -e "s#@RTM_ENABLE@#$RTM_ENABLE#g" \ -e "s#@LSE_ENABLE@#$LSE_ENABLE#g" \ -e "s#@VMA_BITS@#$VMA_BITS_R#g" \ -e "s#@VMA_BITS_VALUE@#$VMA_BITS_VALUE_R#g" \ -e "s#@MM@#$MM#g" \ -e "s#@BUILD_DIR@#$P_PWD#g" \ -e "s#@SRC_DIR@#$BUILD_DIR#g" \ -e "s#@LDNAME@#$LDNAME#g" \ -e "s#@LDNAME_MAJOR@#$LDNAME_MAJOR#g" \ -e "s#@LDNAME_VERSION@#$LDNAME_VERSION#g" \ -e "s#@PC_CFLAGS@#$PC_CFLAGS#g" \ -e "s#@GIT_SHA@#$GIT_SHA#g" \ $1 > $2 } generate_stdout() { echo echo " VERSION = $VERSION" echo " GIT_SHA = $GIT_SHA" echo " BUILD_DIR = $P_PWD" echo " SRC_DIR = $BUILD_DIR" echo " SYSTEM = $SYSTEM" echo " PROFILE = $PROFILE" echo " CC = $CC" echo " COMPILER = $COMPILER" echo " CFLAGS = $CFLAGS" echo " PTHREAD_CFLAGS = $PTHREAD_CFLAGS" echo " LD = $LD" echo " LDNAME = $LDNAME" echo " LDNAME_VERSION = $LDNAME_VERSION" echo " LDNAME_MAJOR = $LDNAME_MAJOR" echo " LDFLAGS = $LDFLAGS" echo " GZIP = $GZIP" echo " CORES = $CORES" echo " POINTER_PACK = $POINTER_PACK_ENABLE" echo " VMA_BITS = $VMA_BITS" echo " MEMORY_MODEL = $MM" echo " RTM = $RTM_ENABLE" echo " LSE = $LSE_ENABLE" echo echo "Headers will be installed in $HEADERS" echo "Libraries will be installed in $LIBRARY" echo "Documentation will be installed in $MANDIR" } for option; do case "$option" in *=?*) optname=`echo $option|cut -c 3-` value=`expr "$optname" : '[^=]*=\(.*\)'` ;; *=) value= ;; *) value=yes ;; esac case "$option" in --help) echo "Usage: $0 [OPTIONS]" echo echo "The following options may be used for cross-building." echo " --profile=N Use custom build profile (use in conjunction with \$CC)" echo echo "The following options may be used to modify installation behavior." echo " --includedir=N Headers directory (default is ${PREFIX}/include)" echo " --libdir=N Libraries directory (default is ${PREFIX}/lib)" echo " --mandir=N Manual pages directory (default is ${PREFIX}/man)" echo " --prefix=N Installs library files in N (default is $PREFIX)" echo echo "The following options will affect generated code." echo " --enable-pointer-packing Assumes address encoding is subset of pointer range" echo " --enable-rtm Enable restricted transactional memory (power, x86_64)" echo " --enable-lse Enable large system extensions (arm64)" echo " --memory-model=N Specify memory model (currently tso, pso or rmo)" echo " --vma-bits=N Specify valid number of VMA bits" echo " --platform=N Force the platform type, instead of relying on autodetection" echo " --use-cc-builtins Use the compiler atomic bultin functions, instead of the CK implementation" echo " --disable-double Don't generate any of the functions using the \"double\" type" echo echo "The following options affect regression testing." echo " --cores=N Specify number of cores available on target machine" echo echo "The following environment variables may be used:" echo " CC C compiler command" echo " CFLAGS C compiler flags" echo " LDFLAGS Linker flags" echo " GZIP GZIP compression tool" echo echo "Report bugs to ${MAINTAINER}." exit $EXIT_SUCCESS ;; --memory-model=*) case "$value" in "tso") MM="CK_MD_TSO" ;; "rmo") MM="CK_MD_RMO" ;; "pso") MM="CK_MD_PSO" ;; *) echo "./configure [--help]" exit $EXIT_FAILURE ;; esac ;; --vma-bits=*) VMA_BITS=$value ;; --enable-pointer-packing) POINTER_PACK_ENABLE="CK_MD_POINTER_PACK_ENABLE" ;; --enable-rtm) RTM_ENABLE_SET="CK_MD_RTM_ENABLE" ;; --enable-lse) LSE_ENABLE_SET="CK_MD_LSE_ENABLE" ;; --cores=*) CORES=$value ;; --profile=*) PROFILE=$value ;; --prefix=*) PREFIX=$value ;; --includedir=*) HEADERS=$value ;; --libdir=*) LIBRARY=$value ;; --mandir=*) MANDIR=$value ;; --with-pic) WANT_PIC=yes ;; --without-pic) WANT_PIC=no ;; --disable-option-checking) OPTION_CHECKING=0 ;; --use-cc-builtins) USE_CC_BUILTINS=1 ;; --disable-double) DISABLE_DOUBLE="CK_PR_DISABLE_DOUBLE" ;; --platform=*) PLATFORM=$value ;; --build=*|--host=*|--target=*|--exec-prefix=*|--bindir=*|--sbindir=*|\ --sysconfdir=*|--datadir=*|--libexecdir=*|--localstatedir=*|\ --enable-static|\ --sharedstatedir=*|--infodir=*|--enable-shared|--disable-shared|\ --cache-file=*|--srcdir=*) # ignore for compat with regular configure ;; --*) if test "$OPTION_CHECKING" -eq 1; then echo "$0 [--help]" echo "Unknown option $option" exit $EXIT_FAILURE fi ;; *=*) optname=`echo $option|cut -c 3-` NAME=`expr "$optname" : '\([^=]*\)='` eval "$NAME='$value'" export $NAME ;; *) echo "$0 [--help]" echo "Unknown option $option" exit $EXIT_FAILURE ;; esac done HEADERS=${HEADERS:-"${PREFIX}/include"} LIBRARY=${LIBRARY:-"${PREFIX}/lib"} MANDIR=${MANDIR:-"${PREFIX}/share/man"} GZIP=${GZIP:-"gzip -c"} POINTER_PACK_ENABLE=${POINTER_PACK_ENABLE:-"CK_MD_POINTER_PACK_DISABLE"} DISABLE_DOUBLE=${DISABLE_DOUBLE:-"CK_PR_ENABLE_DOUBLE"} RTM_ENABLE=${RTM_ENABLE_SET:-"CK_MD_RTM_DISABLE"} LSE_ENABLE=${LSE_ENABLE_SET:-"CK_MD_LSE_DISABLE"} VMA_BITS=${VMA_BITS:-"unknown"} DCORES=2 printf "Detecting operating system......." SYSTEM=`uname -s 2> /dev/null` case "$SYSTEM" in "SunOS") SYSTEM=solaris ;; "Linux"|"uClinux") DCORES=`egrep '(^CPU[0-9]+|^processor.*:.*)' /proc/cpuinfo|wc -l` SYSTEM=linux ;; "FreeBSD"|"GNU/kFreeBSD") DCORES=`sysctl -n hw.ncpu` SYSTEM=freebsd ;; "NetBSD") DCORES=`sysctl -n hw.ncpu` SYSTEM=netbsd ;; "OpenBSD") DCORES=`sysctl -n hw.ncpu` SYSTEM=openbsd ;; "DragonFly") DCORES=`sysctl -n hw.ncpu` SYSTEM=dragonflybsd ;; "Darwin") DCORES=`sysctl -n hw.ncpu` SYSTEM=darwin ;; MINGW32*|MSYS_NT*) SYSTEM=mingw32 LDFLAGS="-mthreads $LDFLAGS" ;; CYGWIN_NT*) SYSTEM=cygwin LDFLAGS="-mthreads $LDFLAGS" ;; *) SYSTEM= ;; esac assert "$SYSTEM" "$SYSTEM" "unsupported" CORES=${CORES:-${DCORES}} printf "Detecting machine architecture..." if test "x$PLATFORM" = "x"; then PLATFORM=`uname -m 2> /dev/null` fi case $PLATFORM in "macppc"|"Power Macintosh"|"powerpc") RTM_ENABLE="CK_MD_RTM_DISABLE" LSE_ENABLE="CK_MD_LSE_DISABLE" MM="${MM:-"CK_MD_RMO"}" PLATFORM=ppc ENVIRONMENT=32 LDFLAGS="-m32 $LDFLAGS" ;; "sun4u"|"sun4v"|"sparc64") RTM_ENABLE="CK_MD_RTM_DISABLE" LSE_ENABLE="CK_MD_LSE_DISABLE" MM="${MM:-"CK_MD_TSO"}" PLATFORM=sparcv9 ENVIRONMENT=64 LDFLAGS="-m64 $LDFLAGS" ;; i386|i486|i586|i686|i586_i686|pentium*|athlon*|k5|k6|k6_2|k6_3) LSE_ENABLE="CK_MD_LSE_DISABLE" MM="${MM:-"CK_MD_TSO"}" case $SYSTEM in darwin) ENVIRONMENT=64 PLATFORM=x86_64 ;; freebsd) PLATFORM=x86 ENVIRONMENT=32 # FreeBSD doesn't give us a nice way to determine the CPU # class of the running system, reporting any 32-bit x86 # architecture as i386. 486 is its minimum supported CPU # class and cmpxchg8b was implemented first in i586. dmesg | grep -q "486-class" if test "$?" -eq 0; then assert "" "" "Must have an i586 class or higher CPU" fi # FreeBSD still generates code for 486-class CPUs as its # default 32-bit target, but we need 586 at the least. echo "$CFLAGS" | grep -q 'march=' if test "$?" -ne 0; then # Needed for cmpxchg8b CFLAGS="$CFLAGS -march=i586" fi ;; linux) case $PLATFORM in i386|i486) assert "" "" "Must have an i586 class or higher CPU" ;; esac PLATFORM=x86 ENVIRONMENT=32 ;; *) PLATFORM=x86 ENVIRONMENT=32 assert "$PLATFORM $ENVIRONMENT" "$PLATFORM $ENVIRONMENT" "unsupported" ;; esac ;; "amd64"|"x86_64") LSE_ENABLE="CK_MD_LSE_DISABLE" PLATFORM=x86_64 ENVIRONMENT=64 LDFLAGS="-m64 $LDFLAGS" MM="${MM:-"CK_MD_TSO"}" ;; "i86pc") RTM_ENABLE="CK_MD_RTM_DISABLE" LSE_ENABLE="CK_MD_LSE_DISABLE" MM="${MM:-"CK_MD_TSO"}" if test -z "$ISA"; then ISA=`isainfo -n 2> /dev/null || echo i386` ; fi case "$ISA" in "amd64") RTM_ENABLE=${RTM_ENABLE_SET:-"CK_MD_RTM_DISABLE"} PLATFORM=x86_64 ENVIRONMENT=64 ;; *) PLATFORM=x86 ENVIRONMENT=32 assert "$PLATFORM $ENVIRONMENT" "$PLATFORM $ENVIRONMENT" "unsupported" ;; esac ;; "ppc64"|"ppc64le") RTM_ENABLE="CK_MD_RTM_DISABLE" LSE_ENABLE="CK_MD_LSE_DISABLE" MM="${MM:-"CK_MD_RMO"}" PLATFORM=ppc64 ENVIRONMENT=64 ;; arm|armv6l|armv7l) if test "$PLATFORM" = "armv6l"; then CFLAGS="$CFLAGS -march=armv6k"; elif test "$PLATFORM" = "armv7l"; then CFLAGS="$CFLAGS -march=armv7-a"; fi RTM_ENABLE="CK_MD_RTM_DISABLE" LSE_ENABLE="CK_MD_LSE_DISABLE" MM="${MM:-"CK_MD_RMO"}" PLATFORM=arm ENVIRONMENT=32 ;; "arm64"|"aarch64") RTM_ENABLE="CK_MD_RTM_DISABLE" MM="${MM:-"CK_MD_RMO"}" PLATFORM=aarch64 ENVIRONMENT=64 ;; "s390x") RTM_ENABLE="CK_MD_RTM_DISABLE" LSE_ENABLE="CK_MD_LSE_DISABLE" MM="${MM:-"CK_MD_RMO"}" PLATFORM=s390x ENVIRONMENT=64 ;; *) RTM_ENABLE="CK_MD_RTM_DISABLE" LSE_ENABLE="CK_MD_LSE_DISABLE" PLATFORM= MM="${MM:-"CK_MD_RMO"}" ;; esac assert "$PLATFORM" "$PLATFORM" "unsupported" if test "$VMA" = "unknown"; then VMA_BITS_R="CK_MD_VMA_BITS_UNKNOWN" VMA_BITS_VALUE_R="" POINTER_PACK_ENABLE="CK_MD_POINTER_PACK_DISABLE" else VMA_BITS_R="CK_MD_VMA_BITS" VMA_BITS_VALUE_R="${VMA_BITS}ULL" fi if test "$USE_CC_BUILTINS"; then CFLAGS="$CFLAGS -DCK_CC_BUILTINS" PC_CFLAGS="-DCK_CC_BULITINS" fi # `which` on Solaris sucks pathsearch() { what=$1 oldFS="$IFS" IFS=":" for d in $PATH ; do if test -x "$d/$what" ; then echo "$d/$what"; IFS="$oldFS" return fi done IFS="$oldFS" } printf "Finding dirname command.........." DIRNAME=`pathsearch "${DIRNAME:-dirname}"` if test -z "$DIRNAME" -o ! -x "$DIRNAME"; then DIRNAME=`pathsearch "${DIRNAME:-dirname}"` DIRNAME="$DIRNAME" else echo "success [$DIRNAME]" fi if test -z "$DIRNAME"; then echo "not found (out of source build unsupported)" else printf "Determining build directory......" BUILD_DIR=`$DIRNAME $0` cd `$DIRNAME $0` BUILD_DIR=`pwd` echo "success [$BUILD_DIR]" fi printf "Finding gzip tool................" GZIP=`pathsearch "${GZIP:-gzip}"` if test -z "$GZIP" -o ! -x "$GZIP"; then GZIP=`pathsearch "${GZIP:-gzip}"` GZIP="$GZIP" fi if test -z "$GZIP"; then echo "not found" GZIP=cat GZIP_SUFFIX="" else echo "success [$GZIP]" GZIP="$GZIP -c" GZIP_SUFFIX=".gz" fi printf "Finding suitable compiler........" if test ! -x "${CC}"; then CC=`pathsearch "${CC:-cc}"` if test -z "$CC" -o ! -x "$CC"; then CC=`pathsearch "${CC:-gcc}"` fi fi assert "$CC" "not found" cat << EOF > .1.c #include int main(void) { #if defined(_WIN32) #if defined(__MINGW64__) puts("mingw64"); return (0); #elif defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION >= 3) puts("mingw32"); return (0); #else return (1); #endif /* __MINGW32__ && __MINGW32_MAJOR_VERSION >= 3 */ #elif defined(__clang__) && (__clang_major__ >= 3) puts("clang"); return (0); #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5110) puts("suncc"); return (0); #elif defined(__GNUC__) && (__GNUC__ >= 4) puts("gcc"); return (0); #else return (1); #endif } EOF $CC -o .1 .1.c COMPILER=`./.1 2> /dev/null` r=$? rm -f .1.c .1 if test "$r" -ne 0; then assert "" "update compiler" else echo "success [$CC]" fi if test "$COMPILER" = "suncc"; then LD=/bin/ld LDFLAGS="-G -z text -h libck.so.$VERSION_MAJOR $LDFLAGS" CFLAGS="-xO5 $CFLAGS" PTHREAD_CFLAGS="-mt -lpthread" elif test "$COMPILER" = "gcc" || test "$COMPILER" = "clang" || test "$COMPILER" = "mingw32" || test "$COMPILER" = "mingw64"; then LD=$CC SONAME="$LDNAME_MAJOR" if test "$SYSTEM" = "darwin"; then CC_WL_OPT="-install_name" LDNAME="libck.dylib" LDNAME_VERSION="libck.$VERSION.dylib" LDNAME_MAJOR="libck.$VERSION_MAJOR.dylib" SONAME="$LIBRARY/$LDNAME_MAJOR" else CC_WL_OPT="-soname" fi LDFLAGS="-Wl,$CC_WL_OPT,$SONAME $LDFLAGS" if test "$WANT_PIC" = "yes"; then LDFLAGS="$LDFLAGS -shared -fPIC" CFLAGS="$CFLAGS -fPIC" ALL_LIBS="libck.so libck.a" INSTALL_LIBS="install-so install-lib" else LDFLAGS="$LDFLAGS -fno-PIC" CFLAGS="$CFLAGS -fno-PIC" ALL_LIBS="libck.a" INSTALL_LIBS="install-lib" fi CFLAGS="-D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_DEFAULT_SOURCE -std=gnu99 -pedantic -Wall -W -Wundef -Wendif-labels -Wshadow -Wpointer-arith -Wcast-align -Wcast-qual -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline -Wdisabled-optimization -fstrict-aliasing -O2 -pipe -Wno-parentheses $CFLAGS" PTHREAD_CFLAGS="-pthread" if test "$COMPILER" = "mingw64"; then ENVIRONMENT=64 PLATFORM=x86_64 fi else assert "" "unknown compiler" fi printf "Detecting VMA bits..............." VMA="unknown" if test "$VMA_BITS" = "unknown"; then if test "$PLATFORM" = "x86" || test $PLATFORM = "x86_64"; then case $SYSTEM in darwin) VMA=`sysctl -n machdep.cpu.address_bits.virtual` ;; linux) VMA=`awk '/address sizes/ {print $7;exit}' /proc/cpuinfo` ;; *) if test "$PLATFORM" = "x86"; then VMA="32" else cat << EOF > .1.c #include int main(int argc, char *argv[]) { unsigned long ret = 0x80000000; __asm __volatile("cpuid\n" : "+a" (ret)); if (ret >= 0x80000008) { ret = 0x80000008; __asm __volatile("cpuid\n" : "+a" (ret)); printf("%lu\n", (ret >> 8) & 0xff); } else { return (1); } return (0); } EOF $CC -o .1 .1.c 2>/dev/null VMA=`./.1 2>/dev/null` if test $? -ne 0; then VMA="unknown" fi rm -f .1.c .1 fi esac fi VMA_BITS=$VMA else VMA=$VMA_BITS fi if test "$VMA" = "unknown"; then echo "unknown" VMA_BITS_R="CK_MD_VMA_BITS_UNKNOWN" VMA_BITS_VALUE_R="" POINTER_PACK_ENABLE="CK_MD_POINTER_PACK_DISABLE" else echo "success [$VMA]" VMA_BITS_R="CK_MD_VMA_BITS" VMA_BITS_VALUE_R="${VMA_BITS}ULL" fi for i in $REQUIRE_HEADER; do printf "Checking header file usability..." cat << EOF > .1.c #include <$i> int main(void){return(0);} EOF $CC -o .1 .1.c 2> /dev/null hf_s=$? rm -f .1 .1.c if test $hf_s -eq 0; then echo "success [$i]" else echo "failed [$i]" exit $EXIT_FAILURE fi done printf "Detecting git SHA................" get_git_sha echo "$GIT_MSG [$GIT_SHA]" if test "$PROFILE"; then printf "Using user-specified profile....." if test -z "$CC"; then echo "failed [specify compiler]" exit $EXIT_FAILURE fi if test ! -f build/ck.build.$PROFILE; then echo "failed [$PROFILE]" exit $EXIT_FAILURE fi echo "success [$PROFILE]" printf "Generating header files.........." generate include/ck_md.h.in include/ck_md.h echo "success" printf "Generating build files..........." generate src/Makefile.in src/Makefile generate doc/Makefile.in doc/Makefile generate build/ck.build.in build/ck.build generate build/regressions.build.in build/regressions.build generate build/ck.pc.in build/ck.pc generate build/ck.spec.in build/ck.spec generate Makefile.in Makefile echo "success" generate_stdout exit $EXIT_SUCCESS fi # Platform will be used as a macro. PROFILE="${PROFILE:-$PLATFORM}" PLATFORM="__${PLATFORM}__" printf "Generating header files.........." generate include/ck_md.h.in include/ck_md.h echo "success" printf "Generating build files..........." mkdir -p $P_PWD/doc mkdir -p $P_PWD/build mkdir -p $P_PWD/include mkdir -p $P_PWD/src if test "$P_PWD" '!=' "$BUILD_DIR"; then mkdir -p $P_PWD/regressions cp $BUILD_DIR/regressions/Makefile.unsupported $P_PWD/regressions/Makefile &> /dev/null cp $BUILD_DIR/build/ck.build.$PROFILE $P_PWD/build/ck.build.$PROFILE &> /dev/null cp $BUILD_DIR/include/ck_md.h $P_PWD/include/ck_md.h &> /dev/null fi generate src/Makefile.in $P_PWD/src/Makefile generate doc/Makefile.in $P_PWD/doc/Makefile generate build/ck.build.in $P_PWD/build/ck.build generate build/regressions.build.in $P_PWD/build/regressions.build generate build/ck.pc.in $P_PWD/build/ck.pc generate build/ck.spec.in $P_PWD/build/ck.spec generate Makefile.in $P_PWD/Makefile touch src/*.c echo "success" generate_stdout ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_ARRAY_FOREACH ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd October 18, 2013 .Dt CK_ARRAY_FOREACH 3 .Sh NAME .Nm CK_ARRAY_FOREACH .Nd iterate through an array .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_array.h .Ft bool .Fn CK_ARRAY_FOREACH "ck_array_t *array" "ck_array_iterator_t *iterator" "void **b" .Sh DESCRIPTION The .Fn CK_ARRAY_FOREACH 3 macro iterates through the array pointed to by .Fa array . A pointer to an iterator object must be specified by .Fa iterator and .Fa b must point to a void pointer. .Sh EXAMPLE .Bd -literal -offset indent #include /* Assume this was already previously initialized. */ ck_array_t array; void example(void) { ck_array_iterator_t iterator; void *pointer; CK_ARRAY_FOREACH(&array, &iterator, &pointer) { do_something(pointer); } } .Ed .Sh RETURN VALUES This macro has no return value. .Sh SEE ALSO .Xr ck_array_init 3 , .Xr ck_array_commit 3 , .Xr ck_array_put 3 , .Xr ck_array_put_unique 3 , .Xr ck_array_remove 3 , .Xr ck_array_deinit 3 .Xr ck_array_length 3 , .Xr ck_array_buffer 3 , .Xr ck_array_initialized 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_COHORT_INIT ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_COHORT_INIT 3 .Sh NAME .Nm CK_COHORT_INIT .Nd initialize instance of a cohort type .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_COHORT_INIT "COHORT_NAME cohort_name" "COHORT *cohort" "void *global_lock" \ "void *local_lock" "unsigned int pass_limit" .Sh DESCRIPTION Until a cohort instance is initialized using the CK_COHORT_INIT macro, any operations involving it will have undefined behavior. After this macro has been called, the cohort pointed to by the .Fa cohort argument will use the lock pointed to by .Fa global_lock as its global lock and the lock pointed to by .Fa local_lock as its local lock. .Pp The cohort will relinquish its global lock after .Fa pass_limit consecutive acquisitions of its local lock, even if there are other threads waiting. If you are unsure of a value to use for the .Fa pass_limit argument, you should use CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT. .Sh SEE ALSO .Xr ck_cohort 3 , .Xr CK_COHORT_PROTOTYPE 3 , .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 , .Xr CK_COHORT_INSTANCE 3 , .Xr CK_COHORT_INITIALIZER 3 , .Xr CK_COHORT_LOCK 3 , .Xr CK_COHORT_UNLOCK 3 , .Xr CK_COHORT_LOCKED 3 , .Xr CK_COHORT_TRYLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_COHORT_INSTANCE ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_COHORT_INSTANCE 3 .Sh NAME .Nm CK_COHORT_INSTANCE .Nd declare an instance of a cohort type .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_COHORT_INSTANCE "COHORT_NAME cohort_name" .Sh DESCRIPTION The user must use this macro to declare instances of cohort types that they have defined. For instance, if they have used the CK_COHORT_PROTOTYPE macro to define a cohort type with name foo, they would create an instance of this type as follows: .br CK_COHORT_INSTANCE(foo) cohort; .Pp This macro should also be used when allocating memory for cohorts. For instance, to allocate a block of 4 cohorts: .br CK_COHORT_INSTANCE(foo) *cohorts = malloc(4 * sizeof(CK_COHORT_INSTANCE(foo))); .Sh SEE ALSO .Xr ck_cohort 3 , .Xr CK_COHORT_PROTOTYPE 3 , .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 , .Xr CK_COHORT_INSTANCE 3 , .Xr CK_COHORT_INITIALIZER 3 , .Xr CK_COHORT_LOCK 3 , .Xr CK_COHORT_UNLOCK 3 , .Xr CK_COHORT_LOCKED 3 , .Xr CK_COHORT_TRYLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_COHORT_LOCK ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_COHORT_LOCK 3 .Sh NAME .Nm CK_COHORT_LOCK .Nd acquire cohort lock .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_COHORT_LOCK "COHORT_NAME cohort_name" "COHORT *cohort" "void *global_context" \ "void *local_context" .Sh DESCRIPTION This call attempts to acquire both the local and global (if necessary) locks from .Fa cohort . The call will block until both locks have been acquired. .Fa global_context will be passed as the second argument to the function that was provided as the .Fa global_lock_method argument to CK_COHORT_PROTOTYPE if that method is called, and .Fa local_context will be passed to the function specified by .Fa local_lock_method . .Sh SEE ALSO .Xr ck_cohort 3 , .Xr CK_COHORT_PROTOTYPE 3 , .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 , .Xr CK_COHORT_INSTANCE 3 , .Xr CK_COHORT_INITIALIZER 3 , .Xr CK_COHORT_INIT 3 , .Xr CK_COHORT_UNLOCK 3 , .Xr CK_COHORT_LOCKED 3 , .Xr CK_COHORT_TRYLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_COHORT_PROTOTYPE ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_COHORT_PROTOTYPE 3 .Sh NAME .Nm CK_COHORT_PROTOTYPE .Nd define cohort type with specified lock types .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_COHORT_PROTOTYPE "COHORT_NAME cohort_name" "TYPE global_lock_method" \ "LOCK_FXN global_unlock_method" "LOCK_FXN local_lock_method" "LOCK_FXN local_unlock_method" .Sh DESCRIPTION The ck_cohort.h header file does not define any cohort types. Instead, the user must use the CK_COHORT_PROTOTYPE or .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 macros to define any types they want to use. They must use CK_COHORT_TRYLOCK_PROTOTYPE if they want their cohort type to support trylock operations. The CK_COHORT_PROTOTYPE macro takes the following arguments: .Pp .Fa cohort_name : An identifier used for this cohort type. This will have to be passed to each of the other CK_COHORT macros. .br .Fa global_lock_method : The method that should be called to acquire the global lock .br .Fa global_unlock_method : The method that should be called to relinquish the global lock .br .Fa local_lock_method : The method that should be called to acquire the local lock .br .Fa local_unlock_method : The method that should be called to relinquish the local lock .Pp Instances of the defined cohort type can be declared as: .br CK_COHORT_INSTANCE(cohort_name) cohort; .Sh SEE ALSO .Xr ck_cohort 3 , .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 , .Xr CK_COHORT_INSTANCE 3 , .Xr CK_COHORT_INITIALIZER 3 , .Xr CK_COHORT_INIT 3 , .Xr CK_COHORT_LOCK 3 , .Xr CK_COHORT_UNLOCK 3 , .Xr CK_COHORT_LOCKED 3 , .Xr CK_COHORT_TRYLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_COHORT_TRYLOCK ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 9, 2013. .Dt CK_COHORT_TRYLOCK 3 .Sh NAME .Nm CK_COHORT_TRYLOCK .Nd try to acquire cohort lock .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_COHORT_TRYLOCK "COHORT_NAME cohort_name" "COHORT *cohort" "void *global_trylock_context" \ "void *local_trylock_context" "void *lock_unlock_context" .Sh DESCRIPTION This call attempts to acquire both the local and global (if necessary) locks from .Fa cohort . It can only be used with cohort types that were defined using the .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 macro. The call will not block and will return a bool that will evaluate to true iff the cohort was successfully acquired. .Fa global_trylock_context will be passed as the second argument to the function that was provided as the .Fa global_trylock_method argument to CK_COHORT_TRYLOCK_PROTOTYPE if that method is called, and .Fa local_trylock_context will be passed to the function specified by .Fa local_trylock_method . If the global lock acquisition fails, then the cohort will immediately release its local lock as well, and .Fa local_unlock_context will be passed to the function specified by .Fa local_unlock_method when this call is made. .Sh SEE ALSO .Xr ck_cohort 3 , .Xr CK_COHORT_PROTOTYPE 3 , .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 , .Xr CK_COHORT_INSTANCE 3 , .Xr CK_COHORT_INITIALIZER 3 , .Xr CK_COHORT_INIT 3 , .Xr CK_COHORT_LOCK 3 , .Xr CK_COHORT_UNLOCK 3 , .Xr CK_COHORT_LOCKED 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_COHORT_TRYLOCK_PROTOTYPE ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 9, 2013. .Dt CK_COHORT_TRYLOCK_PROTOTYPE 3 .Sh NAME .Nm CK_COHORT_TRYLOCK_PROTOTYPE .Nd define cohort type with specified lock types .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_COHORT_TRYLOCK_PROTOTYPE "COHORT_NAME cohort_name" "LOCK_FXN global_lock_method" \ "LOCK_FXN global_unlock_method" "BOOL_LOCK_FXN global_locked_method" \ "BOOL_LOCK_FXN global_trylock_method" "LOCK_FXN local_lock_method" \ "LOCK_FXN local_unlock_method" "BOOL_LOCK_FXN local_locked_method" "BOOL_LOCK_FXN local_trylock_method" .Sh DESCRIPTION The ck_cohort.h header file does not define any cohort types. Instead, the user must use the CK_COHORT_PROTOTYPE or CK_COHORT_TRYLOCK_PROTOTYPE macros to define any types they want to use. They must use CK_COHORT_TRYLOCK_PROTOTYPE if they want their cohort type to have support for trylock operations. The CK_COHORT_TRYLOCK_PROTOTYPE macro takes the following arguments: .Pp .Fa cohort_name : An identifier used for this cohort type. This will have to be passed to each of the other CK_COHORT macros. .br .Fa global_lock_method : The method that should be called to acquire the global lock .br .Fa global_unlock_method : The method that should be called to relinquish the global lock .br .Fa global_locked_method : This method should return true iff the global lock is acquired by a thread. .br .Fa global_trylock_method : The method that should be called to try to acquire the global lock. It should not block and return true iff the lock was successfully acquired. .br .Fa local_lock_method : The method that should be called to acquire the local lock .br .Fa local_unlock_method : The method that should be called to relinquish the local lock .br .Fa global_locked_method : This method should return true iff the global lock is acquired by a thread. .br .Fa local_trylock_method : The method that should be called to try to acquire the local lock. It should not block and return true iff the lock was successfully acquired. .Pp Instances of the defined cohort type can be declared as: .br CK_COHORT_INSTANCE(cohort_name) cohort; .Sh SEE ALSO .Xr ck_cohort 3 , .Xr CK_COHORT_PROTOTYPE 3 , .Xr CK_COHORT_INSTANCE 3 , .Xr CK_COHORT_INITIALIZER 3 , .Xr CK_COHORT_INIT 3 , .Xr CK_COHORT_LOCK 3 , .Xr CK_COHORT_UNLOCK 3 , .Xr CK_COHORT_LOCKED 3 , .Xr CK_COHORT_TRYLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_COHORT_UNLOCK ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_COHORT_UNLOCK 3 .Sh NAME .Nm CK_COHORT_UNLOCK .Nd release cohort lock .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_COHORT_UNLOCK "COHORT_NAME cohort_name" "COHORT *cohort" "void *global_context" \ "void *local_context" .Sh DESCRIPTION This call instructs .Fa cohort to relinquish its local lock and potentially its global lock as well. .Fa global_context will be passed as the second argument to the function that was provided as the .Fa global_lock_method argument to CK_COHORT_PROTOTYPE if that method is called, and .Fa local_context will be passed to the function specified by .Fa local_lock_method . .Sh SEE ALSO .Xr ck_cohort 3 , .Xr CK_COHORT_PROTOTYPE 3 , .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 , .Xr CK_COHORT_INSTANCE 3 , .Xr CK_COHORT_INITIALIZER 3 , .Xr CK_COHORT_INIT 3 , .Xr CK_COHORT_LOCK 3 , .Xr CK_COHORT_LOCKED 3 , .Xr CK_COHORT_TRYLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_HS_HASH ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 28, 2012 .Dt CK_HS_HASH 3 .Sh NAME .Nm CK_HS_HASH .Nd invoke hash function with hash set seed .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft unsigned long .Fn CK_HS_HASH "ck_hs_t *hs" "ck_hs_hash_cb_t *hf" "const void *key" .Sh DESCRIPTION The .Fn CK_HS_HASH 3 macro will invoke the hash function pointed to by the .Fa hf argument with the seed value associated with .Fa hs and the key pointer specified by the .Fa key argument. .Sh RETURN VALUES This function will return the value returned by the .Fa hf function. .Sh ERRORS It is expected .Fa hs was previously initialized via .Fn ck_hs_init 3 . .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_destroy 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_set 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_RHS_HASH ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 28, 2012 .Dt CK_RHS_HASH 3 .Sh NAME .Nm CK_RHS_HASH .Nd invoke hash function with hash set seed .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft unsigned long .Fn CK_RHS_HASH "ck_rhs_t *hs" "ck_rhs_hash_cb_t *hf" "const void *key" .Sh DESCRIPTION The .Fn CK_RHS_HASH 3 macro will invoke the hash function pointed to by the .Fa hf argument with the seed value associated with .Fa hs and the key pointer specified by the .Fa key argument. .Sh RETURN VALUES This function will return the value returned by the .Fa hf function. .Sh ERRORS It is expected .Fa hs was previously initialized via .Fn ck_rhs_init 3 . .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_destroy 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_RWCOHORT_INIT ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_RWCOHORT_INIT 3 .Sh NAME .Nm CK_RWCOHORT_INIT .Nd initialize instance of a cohort-based reader-writer lock type .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rwcohort.h .Fn CK_RWCOHORT_NEUTRAL_INIT "COHORT_NAME cohort_name" "LOCK *lock" .Fn CK_RWCOHORT_RP_INIT "COHORT_NAME cohort_name" "LOCK *lock" "unsigned int wait_limit" .Fn CK_RWCOHORT_WP_INIT "COHORT_NAME cohort_name" "LOCK *lock" "unsigned int wait_limit" .Sh DESCRIPTION This macro initializes the lock instance pointed to by the .Fa lock argument. Until a lock instance is initialized using the CK_RWCOHORT_INIT macro, any operations involving it will have undefined behavior. Note that the .Fa wait_limit argument should only be used with reader-preference or writer-preference locks. For neutral locks, this argument should be excluded. If you are unsure of a value to use for the .Fa wait_limit argument, you should use CK_RWCOHORT_STRATEGY_DEFAULT_LOCAL_WAIT_LIMIT. .Sh SEE ALSO .Xr ck_rwcohort 3 , .Xr CK_RWCOHORT_PROTOTYPE 3 , .Xr CK_RWCOHORT_TRYLOCK_PROTOTYPE 3 , .Xr CK_RWCOHORT_INSTANCE 3 , .Xr CK_RWCOHORT_INITIALIZER 3 , .Xr CK_RWCOHORT_LOCK 3 , .Xr CK_RWCOHORT_UNLOCK 3 , .Xr CK_RWCOHORT_LOCKED 3 , .Xr CK_RWCOHORT_TRYLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_RWCOHORT_INSTANCE ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_RWCOHORT_INSTANCE 3 .Sh NAME .Nm CK_RWCOHORT_INSTANCE .Nd declare an instance of a cohort-based reader-writer lock type .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_RWCOHORT_NEUTRAL_INSTANCE "COHORT_NAME cohort_name" .Fn CK_RWCOHORT_RP_INSTANCE "COHORT_NAME cohort_name" .Fn CK_RWCOHORT_WP_INSTANCE "COHORT_NAME cohort_name" .Sh DESCRIPTION The user must use this macro to declare instances of lock types that they have defined using the .Xr CK_RWCOHORT_PROTOTYPE 3 macro. The cohort_name must be the same as the one used in the prototype macro. For instance, if CK_RWCOHORT_PROTOTYPE was called with the name "foo", the CK_RWCOHORT_INSTANCE macro should be called as .br CK_RWCOHORT_INSTANCE(foo) cohort; .Pp This macro should also be used when allocating memory for cohorts. For instance, to allocate a block of 4 cohorts: .br CK_RWCOHORT_WP_INSTANCE(foo) *cohorts = malloc(4 * sizeof(CK_RWCOHORT_WP_INSTANCE(foo))); .Sh SEE ALSO .Xr ck_rwcohort 3 , .Xr CK_RWCOHORT_PROTOTYPE 3 , .Xr CK_RWCOHORT_TRYLOCK_PROTOTYPE 3 , .Xr CK_RWCOHORT_INSTANCE 3 , .Xr CK_RWCOHORT_INITIALIZER 3 , .Xr CK_RWCOHORT_LOCK 3 , .Xr CK_RWCOHORT_UNLOCK 3 , .Xr CK_RWCOHORT_LOCKED 3 , .Xr CK_RWCOHORT_TRYLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_RWCOHORT_PROTOTYPE ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_RWCOHORT_PROTOTYPE 3 .Sh NAME .Nm CK_RWCOHORT_PROTOTYPE .Nd define reader-writer cohort-based lock using the specified cohort type .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rwcohort.h .Fn CK_RWCOHORT_NEUTRAL_PROTOTYPE "COHORT_NAME cohort_name" .Fn CK_RWCOHORT_RP_PROTOTYPE "COHORT_NAME cohort_name" .Fn CK_RWCOHORT_WP_PROTOTYPE "COHORT_NAME cohort_name" .Sh DESCRIPTION The ck_rwcohort.h header file does not define any cohort types. Instead, the user must use the CK_RWCOHORT_PROTOTYPE macro to define any types they want to use. This macro takes a single argument which corresponds to the type of the cohort lock that the reader-writer lock should use. A cohort type must have already been defined with that name using the .Xr CK_COHORT_PROTOTYPE 3 or .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 macros. .Pp Instances of the defined lock type can be declared as: .br CK_RWCOHORT_INSTANCE(cohort_name) lock; .Sh SEE ALSO .Xr ck_rwcohort 3 , .Xr CK_COHORT_PROTOTYPE 3 , .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 , .Xr CK_RWCOHORT_INSTANCE 3 , .Xr CK_RWCOHORT_INITIALIZER 3 , .Xr CK_RWCOHORT_INIT 3 , .Xr CK_RWCOHORT_READ_LOCK 3 , .Xr CK_RWCOHORT_READ_UNLOCK 3 , .Xr CK_RWCOHORT_WRITE_LOCK 3 , .Xr CK_RWCOHORT_WRITE_UNLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_RWCOHORT_READ_LOCK ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_RWCOHORT_READ_LOCK 3 .Sh NAME .Nm CK_RWCOHORT_READ_LOCK .Nd acquire read-only permission for cohort-based reader-writer lock .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_RWCOHORT_NEUTRAL_READ_LOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Fn CK_RWCOHORT_RP_READ_LOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Fn CK_RWCOHORT_WP_READ_LOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Sh DESCRIPTION This call will acquire read-only permission from .Fa lock . The call will block until this permission has been acquired. .Fa cohort must point to a cohort whose global lock is the same as all other cohorts used with .Fa lock . The .Fa global_context and .Fa local_context arguments will be passed along as the context arguments to any calls to .Fa cohort . . .Sh SEE ALSO .Xr ck_cohort 3 , .Xr CK_RWCOHORT_PROTOTYPE 3 , .Xr CK_RWCOHORT_INSTANCE 3 , .Xr CK_RWCOHORT_INITIALIZER 3 , .Xr CK_RWCOHORT_INIT 3 , .Xr CK_RWCOHORT_READ_UNLOCK 3 , .Xr CK_RWCOHORT_WRITE_LOCK 3 , .Xr CK_RWCOHORT_WRITE_UNLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_RWCOHORT_READ_UNLOCK ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_RWCOHORT_READ_UNLOCK 3 .Sh NAME .Nm CK_RWCOHORT_READ_UNLOCK .Nd relinquish read-only access to cohort-based reader-writer lock .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_RWCOHORT_NEUTRAL_READ_UNLOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Fn CK_RWCOHORT_RP_READ_UNLOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Fn CK_RWCOHORT_WP_READ_UNLOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Sh DESCRIPTION This call will relinquish read-only permission to .Fa lock . .Fa cohort must point to a cohort whose global lock is the same as all other cohorts used with .Fa lock . The .Fa global_context and .Fa local_context arguments will be passed along as the context arguments to any calls to .Fa cohort . . .Sh SEE ALSO .Xr ck_cohort 3 , .Xr CK_RWCOHORT_PROTOTYPE 3 , .Xr CK_RWCOHORT_INSTANCE 3 , .Xr CK_RWCOHORT_INITIALIZER 3 , .Xr CK_RWCOHORT_INIT 3 , .Xr CK_RWCOHORT_READ_LOCK 3 , .Xr CK_RWCOHORT_WRITE_LOCK 3 , .Xr CK_RWCOHORT_WRITE_UNLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_RWCOHORT_WRITE_LOCK ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_RWCOHORT_WRITE_LOCK 3 .Sh NAME .Nm CK_RWCOHORT_WRITE_LOCK .Nd acquite write access for a cohort-based reader-writer lock .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_RWCOHORT_NEUTRAL_WRITE_LOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Fn CK_RWCOHORT_RP_WRITE_LOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Fn CK_RWCOHORT_WP_WRITE_LOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Sh DESCRIPTION This call will acquire write permission for .Fa lock . The call will block until this permission has been acquired. .Fa cohort must point to a cohort whose global lock is the same as all other cohorts used with .Fa lock . The .Fa global_context and .Fa local_context arguments will be passed along as the context arguments to any calls to .Fa cohort . . .Sh SEE ALSO .Xr ck_cohort 3 , .Xr CK_RWCOHORT_PROTOTYPE 3 , .Xr CK_RWCOHORT_INSTANCE 3 , .Xr CK_RWCOHORT_INITIALIZER 3 , .Xr CK_RWCOHORT_INIT 3 , .Xr CK_RWCOHORT_READ_LOCK 3 , .Xr CK_RWCOHORT_READ_UNLOCK 3 , .Xr CK_RWCOHORT_WRITE_UNLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/CK_RWCOHORT_WRITE_UNLOCK ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt CK_RWCOHORT_WRITE_UNLOCK 3 .Sh NAME .Nm CK_RWCOHORT_WRITE_UNLOCK .Nd relinquish write access for cohort-based reader-writer lock .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_RWCOHORT_NEUTRAL_WRITE_UNLOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Fn CK_RWCOHORT_RP_WRITE_UNLOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Fn CK_RWCOHORT_WP_WRITE_UNLOCK "COHORT_NAME cohort_name" "LOCK *lock" "COHORT *cohort"\ "void *global_context" "void *local_context" .Sh DESCRIPTION This call will relinquish write permission for .Fa lock . .Fa cohort must point to a cohort whose global lock is the same as all other cohorts used with .Fa lock . The .Fa global_context and .Fa local_context arguments will be passed along as the context arguments to any calls to .Fa cohort . . .Sh SEE ALSO .Xr ck_cohort 3 , .Xr CK_RWCOHORT_PROTOTYPE 3 , .Xr CK_RWCOHORT_INSTANCE 3 , .Xr CK_RWCOHORT_INITIALIZER 3 , .Xr CK_RWCOHORT_INIT 3 , .Xr CK_RWCOHORT_READ_LOCK 3 , .Xr CK_RWCOHORT_READ_UNLOCK 3 , .Xr CK_RWCOHORT_WRITE_LOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_array_buffer ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd October 18, 2013 .Dt CK_ARRAY_BUFFER 3 .Sh NAME .Nm ck_array_buffer .Nd return length and pointer to array of reader-visible pointers .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_array.h .Ft void * .Fn ck_array_buffer "ck_array_t *array" "unsigned int *length" .Sh DESCRIPTION The .Fn ck_array_buffer 3 returns a pointer to the array of pointers currently visible to readers after the last commit operation in .Fa array . The unsigned integer pointed to by .Fa length is updated to reflect the length of the array. .Sh RETURN VALUES This function returns a pointer to an array of pointers. .Sh SEE ALSO .Xr ck_array_commit 3 , .Xr ck_array_put 3 , .Xr ck_array_put_unique 3 , .Xr ck_array_remove 3 , .Xr ck_array_init 3 .Xr ck_array_deinit 3 , .Xr ck_array_length 3 , .Xr ck_array_initialized 3 , .Xr CK_ARRAY_FOREACH 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_array_commit ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd October 18, 2013 .Dt CK_ARRAY_COMMIT 3 .Sh NAME .Nm ck_array_commit .Nd linearization point for mutations before commit call .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_array.h .Ft bool .Fn ck_array_commit "ck_array_t *array" .Sh DESCRIPTION The .Fn ck_array_commit 3 function will commit any pending put or remove operations associated with the array. The function may end up requesting the safe reclamation of memory actively being iterated upon by other threads. .Sh RETURN VALUES This function returns true if the commit operation succeeded. It will return false otherwise, and pending operations will not be applied. .Sh SEE ALSO .Xr ck_array_init 3 , .Xr ck_array_put 3 , .Xr ck_array_put_unique 3 , .Xr ck_array_remove 3 , .Xr ck_array_deinit 3 .Xr ck_array_length 3 , .Xr ck_array_buffer 3 , .Xr ck_array_initialized 3 , .Xr CK_ARRAY_FOREACH 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_array_deinit ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd October 18, 2013 .Dt CK_ARRAY_DEINIT 3 .Sh NAME .Nm ck_array_deinit .Nd destroy and deinitialize a pointer array .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_array.h .Ft void .Fn ck_array_deinit "ck_array_t *array" "bool defer" .Sh DESCRIPTION The .Fn ck_array_deinit 3 destroys the memory associated with the array pointed to by .Fa array . The .Fa defer argument is true if the allocator must destroy the memory using safe memory reclamation or false if the allocator can destroy this memory immediately. .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_array_commit 3 , .Xr ck_array_put 3 , .Xr ck_array_put_unique 3 , .Xr ck_array_remove 3 , .Xr ck_array_init 3 .Xr ck_array_length 3 , .Xr ck_array_buffer 3 , .Xr ck_array_initialized 3 , .Xr CK_ARRAY_FOREACH 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_array_init ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd October 18, 2013 .Dt CK_ARRAY_INIT 3 .Sh NAME .Nm ck_array_init .Nd initialize a pointer array .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_array.h .Ft bool .Fn ck_array_init "ck_array_t *array" "unsigned int mode" "struct ck_malloc *allocator" "unsigned int initial_length" .Sh DESCRIPTION The .Fn ck_array_init 3 function initializes the array pointed to by the argument .Fa array . The mode value must be .Dv CK_ARRAY_MODE_SPMC . The .Fa allocator argument must point to a ck_malloc data structure with valid non-NULL function pointers initialized for malloc, free and realloc. The .Fa initial_length specifies the initial length of the array. The value of .Fa initial_length must be greater than or equal to 2. An array allows for one concurrent put or remove operations in the presence of any number of concurrent CK_ARRAY_FOREACH operations. .Sh RETURN VALUES This function returns true if the array was successfully created. It returns false if the creation failed. Failure may occur due to internal memory allocation failures or invalid arguments. .Sh SEE ALSO .Xr ck_array_commit 3 , .Xr ck_array_put 3 , .Xr ck_array_put_unique 3 , .Xr ck_array_remove 3 , .Xr ck_array_deinit 3 .Xr ck_array_length 3 , .Xr ck_array_buffer 3 , .Xr ck_array_initialized 3 , .Xr CK_ARRAY_FOREACH 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_array_initialized ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd October 18, 2013 .Dt CK_ARRAY_INITIALIZED 3 .Sh NAME .Nm ck_array_initialized .Nd indicates whether an array was recently initialized or deinitialized .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_array.h .Ft bool .Fn ck_array_initialized "ck_array_t *array" .Sh DESCRIPTION The .Fn ck_array_initialized 3 can be used to determine whether an array was recently initialized with .Fn ck_array_init 3 or deinitialized with .Fn ck_array_deinit 3 . Behavior is undefined if a user allocates internal allocator data in through other means. .Sh RETURN VALUES This function returns true if the array is initialized, and false otherwise. .Sh SEE ALSO .Xr ck_array_commit 3 , .Xr ck_array_put 3 , .Xr ck_array_put_unique 3 , .Xr ck_array_remove 3 , .Xr ck_array_init 3 .Xr ck_array_deinit 3 , .Xr ck_array_length 3 , .Xr ck_array_buffer 3 , .Xr CK_ARRAY_FOREACH 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_array_length ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd October 18, 2013 .Dt CK_ARRAY_LENGTH 3 .Sh NAME .Nm ck_array_length .Nd returns the number of pointers committed to an array .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_array.h .Ft unsigned int .Fn ck_array_length "ck_array_t *array" .Sh DESCRIPTION The .Fn ck_array_length 3 function returns the number of items a concurrent traversal operation would encounter at completion time. .Sh RETURN VALUES The number of traversal-visible pointers is returned. .Sh SEE ALSO .Xr ck_array_commit 3 , .Xr ck_array_put 3 , .Xr ck_array_put_unique 3 , .Xr ck_array_remove 3 , .Xr ck_array_init 3 .Xr ck_array_deinit 3 , .Xr ck_array_buffer 3 , .Xr ck_array_initialized 3 , .Xr CK_ARRAY_FOREACH 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_array_put ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd October 18, 2013 .Dt CK_ARRAY_PUT 3 .Sh NAME .Nm ck_array_put .Nd attempt immediate or deferred insertion of a pointer into array .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_array.h .Ft bool .Fn ck_array_put "ck_array_t *array" "void *pointer" .Sh DESCRIPTION The .Fn ck_array_put 3 function will attempt to insert the value of .Fa pointer into the array pointed to by .Fa array . This function may incur additional memory allocations if not enough memory has been allocated in the array for a new entry. The operation is also free to apply the operation immediately if there is an opportunity for elimination with a pending (uncommitted) remove operation. .Sh RETURN VALUES This function returns true if the put operation succeeded. It will return false otherwise due to internal allocation failures. .Sh SEE ALSO .Xr ck_array_init 3 , .Xr ck_array_commit 3 , .Xr ck_array_put_unique 3 , .Xr ck_array_remove 3 , .Xr ck_array_deinit 3 .Xr ck_array_length 3 , .Xr ck_array_buffer 3 , .Xr ck_array_initialized 3 , .Xr CK_ARRAY_FOREACH 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_array_put_unique ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd October 18, 2013 .Dt CK_ARRAY_PUT_UNIQUE 3 .Sh NAME .Nm ck_array_put_unique .Nd attempt immediate or deferred insertion of a unique pointer into array .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_array.h .Ft int .Fn ck_array_put_unique "ck_array_t *array" "void *pointer" .Sh DESCRIPTION The .Fn ck_array_put_unique 3 function will attempt to insert the value of .Fa pointer into the array pointed to by .Fa array . This function may incur additional memory allocations if not enough memory has been allocated in the array for a new entry. The operation is also free to apply the operation immediately if there is an opportunity for elimination with a pending (uncommitted) remove operation. The function will not make any modifications if the pointer already exists in the array. .Sh RETURN VALUES This function returns 1 if the pointer already exists in the array. It returns 0 if the put operation succeeded. It returns -1 on error due to internal memory allocation failures. .Sh SEE ALSO .Xr ck_array_init 3 , .Xr ck_array_commit 3 , .Xr ck_array_put 3 , .Xr ck_array_remove 3 , .Xr ck_array_deinit 3 .Xr ck_array_length 3 , .Xr ck_array_buffer 3 , .Xr ck_array_initialized 3 , .Xr CK_ARRAY_FOREACH 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_array_remove ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd October 18, 2013 .Dt CK_ARRAY_REMOVE 3 .Sh NAME .Nm ck_array_remove .Nd attempt immediate or deferred removal of a pointer from an array .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_array.h .Ft bool .Fn ck_array_remove "ck_array_t *array" "void *pointer" .Sh DESCRIPTION The .Fn ck_array_remove 3 function will attempt to remove the value of .Fa pointer into the array pointed to by .Fa array . The operation is also free to apply the operation immediately if there is an opportunity for elimination with a pending (uncommitted) put operation. If no elimination was possible, the function may require to allocate more memory. .Sh RETURN VALUES This function returns true if the remove operation succeeded. It will return false otherwise due to internal allocation failures or because the value did not exist. .Sh SEE ALSO .Xr ck_array_init 3 , .Xr ck_array_commit 3 , .Xr ck_array_remove 3 , .Xr ck_array_put_unique 3 , .Xr ck_array_deinit 3 .Xr ck_array_length 3 , .Xr ck_array_buffer 3 , .Xr ck_array_initialized 3 , .Xr CK_ARRAY_FOREACH 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_base ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2012 .Dt CK_BITMAP_BASE 3 .Sh NAME .Nm ck_bitmap_base .Nd determine the size of a bit array in bytes .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft unsigned int .Fn ck_bitmap_base "unsigned int n_bits" .Sh DESCRIPTION The .Fn ck_bitmap_base function returns the number of bytes that would be used to store the number of bits specified by .Fa n_bits . .Sh RETURN VALUES This function returns a non-zero value that is guaranteed to be a multiple of .Dv sizeof(CK_BITMAP_WORD) . .Sh SEE ALSO .Xr ck_bitmap_size 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_set 3 , .Xr ck_bitmap_reset 3 , .Xr ck_bitmap_test 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_bits 3 , .Xr ck_bitmap_buffer 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_bits ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2012 .Dt CK_BITMAP_BITS 3 .Sh NAME .Nm ck_bitmap_bits .Nd return number of addressable bits in bitmap .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft unsigned int .Fn ck_bitmap_bits "ck_bitmap_t *bitmap" .Sh DESCRIPTION The .Fn ck_bitmap_bits function returns the maximum number of addressable bits in the object pointed to by .Fa bitmap . .Sh RETURN VALUES This function returns a non-zero value. .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_size 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_set 3 , .Xr ck_bitmap_reset 3 , .Xr ck_bitmap_test 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_buffer 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_bts ================================================ .\" .\" Copyright 2014 David Joseph. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd August 22, 2014 .Dt CK_BITMAP_BTS 3 .Sh NAME .Nm ck_bitmap_bts .Nd set the bit at the specified index and fetch its original value .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft bool .Fn ck_bitmap_bts "ck_bitmap_t *bitmap" "unsigned int n" .Sh DESCRIPTION .Fn ck_bitmap_bts sets the bit at the offset specified by the argument .Fa n to .Dv 1 and fetches its original value. .Sh RETURN VALUES This function returns the original value of the bit at offset .Fa n in .Fa bitmap . .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_size 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_reset 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_set 3 , .Xr ck_bitmap_test 3 , .Xr ck_bitmap_bits 3 , .Xr ck_bitmap_buffer 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_buffer ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2012 .Dt CK_BITMAP_BUFFER 3 .Sh NAME .Nm ck_bitmap_buffer .Nd returns pointer to bit array .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft void * .Fn ck_bitmap_buffer "ck_bitmap_t *bitmap" .Sh DESCRIPTION The .Fn ck_bitmap_buffer functions returns a pointer to the actual bit array. For ck_bitmap pointers, the bit array is of type CK_BITMAP_WORD[] and consists of ck_bitmap_base(bitmap) / sizeof(CK_BITMAP_WORD) elements. On currently supported 64-bit platforms .Dv CK_BITMAP_WORD is .Dv uint64_t . On currently supported 32-bit platforms .Dv CK_BITMAP_WORD is .Dv uint32_t . .Sh RETURN VALUES This function returns a non-NULL value. .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_size 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_set 3 , .Xr ck_bitmap_reset 3 , .Xr ck_bitmap_test 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_bits 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_clear ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2012 .Dt CK_BITMAP_CLEAR 3 .Sh NAME .Nm ck_bitmap_clear .Nd reset all bits .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft void .Fn ck_bitmap_clear "ck_bitmap_t *bitmap" .Sh DESCRIPTION The .Fn ck_bitmap_clear function sets all bits in the bitmap pointed to by .Fa bitmap to 0. .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_size 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_set 3 , .Xr ck_bitmap_reset 3 , .Xr ck_bitmap_test 3 , .Xr ck_bitmap_bits 3 , .Xr ck_bitmap_buffer 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_init ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2012 .Dt CK_BITMAP_INIT 3 .Sh NAME .Nm ck_bitmap_init .Nd initialize a bitmap .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft void .Fn ck_bitmap_init "ck_bitmap_t *bitmap" "unsigned int n_bits" "bool set" .Sh DESCRIPTION The .Fn ck_bitmap_init function initializes the bitmap pointed to by the .Fa bitmap pointer. The argument .Fa n_bits specifies the number of bits that are to be stored in the bitmap. The argument .Fa set determines whether the values of the bits in .Fa bitmap are to be initialized to .Dv 1 or .Dv 0 . .Pp It is expected that .Fa bitmap points to a contiguous region of memory containing at least the number of bytes specified by .Xr ck_bitmap_size 3 . .Sh RETURN VALUES This function has no return value. .Sh ERRORS .Bl -tag -width Er .Pp The behavior of .Fn ck_bitmap_init is undefined if .Fa bitmap is not a pointer to a region of bytes of at least .Xr ck_bitmap_size 3 length. .El .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_size 3 , .Xr ck_bitmap_set 3 , .Xr ck_bitmap_reset 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_test 3 , .Xr ck_bitmap_bits 3 , .Xr ck_bitmap_buffer 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_iterator_init ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" Copyright 2012-2013 Shreyas Prasad. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 27, 2012 .Dt CK_BITMAP_ITERATOR_INIT 3 .Sh NAME .Nm ck_bitmap_iterator_init .Nd initialize bitmap iterator .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Pp .Ft void .Fn ck_bitmap_iterator_init "ck_bitmap_iterator_t *iterator" "ck_bitmap_t *bitmap" .Sh DESCRIPTION The .Fn ck_bitmap_iterator_init function will initialize the object pointed to by the .Fa iterator argument for use with .Fa bitmap . .Pp An iterator is used to iterate through set bitmap bits with the .Xr ck_bitmap_next 3 function. .Sh RETURN VALUES The .Fn ck_bitmap_iterator_init function does not return a value. .Sh ERRORS This function will not fail. .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_size 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_set 3 , .Xr ck_bitmap_reset 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_bits 3 , .Xr ck_bitmap_buffer 3 , .Xr ck_bitmap_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_next ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" Copyright 2012-2013 Shreyas Prasad. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 27, 2012 .Dt CK_BITMAP_TEST 3 .Sh NAME .Nm ck_bitmap_next .Nd iterate to the next set bit in bitmap .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft bool .Fn ck_bitmap_next "ck_bitmap_t *bitmap" "ck_bitmap_iterator_t iterator" "unsigned int *bit" .Sh DESCRIPTION The .Fn ck_bitmap_next function will increment the iterator object pointed to by .Fa iterator to point to the next set bit in the bitmap. If .Fn ck_bitmap_next returns .Dv true then the pointer pointed to by .Fa bit is initialized to the number of the current set bit pointed to by the .Fa iterator object. .Pp It is expected that .Fa iterator has been initialized using the .Xr ck_bitmap_iterator_init 3 function. .Sh RETURN VALUES If .Fn ck_bitmap_next returns .Dv true then the object pointed to by .Fa bit contains a set bit. If .Fn ck_bitmap_next returns .Dv false then value of the object pointed to by .Fa bit is undefined. .Sh ERRORS Behavior is undefined if .Fa iterator or .Fa bitmap are uninitialized. .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_size 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_set 3 , .Xr ck_bitmap_reset 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_bits 3 , .Xr ck_bitmap_buffer 3 , .Xr ck_bitmap_iterator_init 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_reset ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2012 .Dt CK_BITMAP_RESET 3 .Sh NAME .Nm ck_bitmap_reset .Nd resets the bit at the specified index .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft void .Fn ck_bitmap_reset "ck_bitmap_t *bitmap" "unsigned int n" .Sh DESCRIPTION The .Fn ck_bitmap_reset resets the bit at offset specified by the argument .Fa n to .Dv 0 . .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_size 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_set 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_test 3 , .Xr ck_bitmap_bits 3 , .Xr ck_bitmap_buffer 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_set ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2012 .Dt CK_BITMAP_SET 3 .Sh NAME .Nm ck_bitmap_set .Nd set the bit at the specified index .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft void .Fn ck_bitmap_set "ck_bitmap_t *bitmap" "unsigned int n" .Sh DESCRIPTION The .Fn ck_bitmap_set sets the bit at offset specified by the argument .Fa n to .Dv 1 . .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_size 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_reset 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_test 3 , .Xr ck_bitmap_bits 3 , .Xr ck_bitmap_buffer 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_size ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2012 .Dt CK_BITMAP_SIZE 3 .Sh NAME .Nm ck_bitmap_size .Nd returns necessary number of bytes for bitmap .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft unsigned int .Fn ck_bitmap_size "unsigned int n_bits" .Sh DESCRIPTION The .Fn ck_bitmap_size function returns the number of bytes that are necessary to allocate for a bitmap that will contain the number of bits specified by .Fa n_bits . .Pp This function is used to determine how many bytes to allocate for dynamically created bitmap objects. The allocated object must still be initialized using .Xr ck_bitmap_init 3 . .Sh RETURN VALUES This function returns a non-zero value. .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_set_mpmc 3 , .Xr ck_bitmap_reset_mpmc 3 , .Xr ck_bitmap_test 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_bits 3 , .Xr ck_bitmap_buffer 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_test ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2012 .Dt CK_BITMAP_TEST 3 .Sh NAME .Nm ck_bitmap_test .Nd determine if the bit at the specified index is set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft bool .Fn ck_bitmap_test "ck_bitmap_t *bitmap" "unsigned int n" .Sh DESCRIPTION The .Fn ck_bitmap_test determines if the bit at the offset specified by the argument .Fa n is set to .Dv 1 . .Sh RETURN VALUES This function returns .Dv true if the bit at the specified offset is set to .Dv 1 and otherwise returns .Dv false . .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_size 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_set_mpmc 3 , .Xr ck_bitmap_reset_mpmc 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_bits 3 , .Xr ck_bitmap_buffer 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_bitmap_union ================================================ .\" .\" Copyright 2012-2014 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 23, 2013 .Dt CK_BITMAP_UNION 3 .Sh NAME .Nm ck_bitmap_union .Nd generates union of two bitmaps .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_bitmap.h .Ft void .Fn ck_bitmap_union "ck_bitmap_t *dst" "ck_bitmap_t *src" .Sh DESCRIPTION The .Fn ck_bitmap_union function sets all bits in the bitmap pointed to by .Fa src in the bitmap pointed to by .Fa dst . .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_bitmap_base 3 , .Xr ck_bitmap_size 3 , .Xr ck_bitmap_init 3 , .Xr ck_bitmap_reset 3 , .Xr ck_bitmap_set 3 , .Xr ck_bitmap_clear 3 , .Xr ck_bitmap_test 3 , .Xr ck_bitmap_bits 3 , .Xr ck_bitmap_buffer 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_brlock ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd July 26, 2013. .Dt ck_brlock 3 .Sh NAME .Nm ck_brlock_init , .Nm ck_brlock_write_lock , .Nm ck_brlock_write_unlock , .Nm ck_brlock_write_trylock , .Nm ck_brlock_read_register , .Nm ck_brlock_read_unregister , .Nm ck_brlock_read_lock , .Nm ck_brlock_read_trylock , .Nm ck_brlock_read_unlock .Nd big-reader locks .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_brlock.h .Pp .Dv ck_brlock_t brlock = CK_BRLOCK_INITIALIZER; .Pp .Dv ck_brlock_reader_t reader = CK_BRLOCK_READER_INITIALIZER; .Pp .Ft void .Fn ck_brlock_init "ck_brlock_t *br" .Ft void .Fn ck_brlock_write_lock "ck_brlock_t *br" .Ft void .Fn ck_brlock_write_unlock "ck_brlock_t *br" .Ft bool .Fn ck_brlock_write_trylock "ck_brlock_t *br" "unsigned int factor" .Ft void .Fn ck_brlock_read_register "ck_brlock_t *br" "ck_brlock_reader_t *reader" .Ft void .Fn ck_brlock_read_unregister "ck_brlock_t *br" "ck_brlock_reader_t *reader" .Ft void .Fn ck_brlock_read_lock "ck_brlock_t *br" "ck_brlock_reader_t *reader" .Ft bool .Fn ck_brlock_read_trylock "ck_brlock_t *br" "ck_brlock_reader_t *reader" \ "unsigned int factor" .Ft void .Fn ck_brlock_read_unlock "ck_brlock_reader_t *reader" .Sh DESCRIPTION Big reader locks are distributed reader-writer locks with low latency constant time reader acquisition (with respect to number of concurrent readers). On the other hand, writer acquisitions are a relatively expensive O(n) operation. This is a write-biased lock. .Sh EXAMPLE .Bd -literal -offset indent static ck_brlock_t lock = CK_BRLOCK_INITIALIZER; static __thread ck_brlock_reader_t reader; static void reader(void) { /* Add our thread as a lock participant. */ ck_brlock_read_register(&lock, &reader); for (;;) { ck_brlock_read_lock(&lock, &reader); /* Read-side critical section. */ ck_brlock_read_unlock(&reader); if (ck_brlock_read_trylock(&lock, &reader, 1) == true) { /* Read-side critical section. */ ck_brlock_read_unlock(&reader); } } return; } static void writer(void) { for (;;) { ck_brlock_write_lock(&lock); /* Write-side critical section. */ ck_brlock_write_unlock(&lock); if (ck_brlock_write_trylock(&lock, 1) == true) { /* Write-side critical section. */ ck_brlock_write_unlock(&lock); } } return; } .Ed .Sh SEE ALSO .Xr ck_bytelock 3 , .Xr ck_rwlock 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_cohort ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd February 24, 2013. .Dt ck_cohort 3 .Sh NAME .Nm ck_cohort .Nd generalized interface for lock cohorts .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_cohort.h .Fn CK_COHORT_PROTOTYPE "COHORT_NAME cohort_name" "LOCK_FXN global_lock_method" \ "LOCK_FXN global_unlock_method" "LOCK_FXN local_lock_method" "LOCK_FXN local_unlock_method" .Fn CK_COHORT_TRYLOCK_PROTOTYPE "COHORT_NAME cohort_name" \ "LOCK_FXN global_lock_method" "LOCK_FXN global_unlock_method" \ "BOOL_LOCK_FXN global_locked_method" "BOOL_LOCK_FXN global_trylock_method" \ "LOCK_FXN local_lock_method" "LOCK_FXN local_unlock_method" \ "BOOL_LOCK_FXN local_locked_method" "BOOL_LOCK_FXN local_trylock_method" .Fn CK_COHORT_INSTANCE "COHORT_NAME cohort_name" .Fn CK_COHORT_INIT "COHORT_NAME cohort_name" "ck_cohort *cohort" \ "void *global_lock" "void *local_lock" "unsigned int pass_limit" .Fn CK_COHORT_LOCK "COHORT_NAME cohort_name" "ck_cohort *cohort" \ "void *global_context" "void *local_context" .Fn CK_COHORT_UNLOCK "COHORT_NAME cohort_name" "ck_cohort *cohort" \ "void *global_context" "void *local_context" .Pp Where LOCK_FXN refers to a method with the signature .br void(void *lock, void *context) .br BOOL_LOCK_FXN refers to a method with the signature .br bool(void *lock, void *context) .Pp The .Fa context argument in each signature is used to pass along any additional information that the lock might need for its lock, unlock and trylock methods. The values for this argument are provided to each call to .Xr CK_COHORT_LOCK 3 , .Xr CK_COHORT_UNLOCK 3 , .Xr CK_COHORT_LOCKED 3 , and .Xr CK_COHORT_TRYLOCK 3 . .Sh DESCRIPTION ck_cohort.h provides an interface for defining lock cohorts with arbitrary lock types. Cohorts are a mechanism for coordinating threads on NUMA architectures in order to reduce the frequency with which a lock is passed between threads on different clusters. .Pp Before using a cohort, the user must define a cohort type using either the .Fn CK_COHORT_PROTOTYPE or the .Fn CK_COHORT_TRYLOCK_PROTOTYPE macros. These macros allow the user to specify the lock methods that they would like the cohort to use. See the .Xr CK_COHORT_PROTOTYPE 3 and .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 man pages for more details. .Pp .Sh EXAMPLE .Bd -literal -offset indent #include #include #include #include #include /* * Create cohort methods with signatures that match * the required signature */ static void ck_spinlock_lock_with_context(ck_spinlock_t *lock, void *context) { (void)context; ck_spinlock_lock(lock); return; } static void ck_spinlock_unlock_with_context(ck_spinlock_t *lock, void *context) { (void)context; ck_spinlock_unlock(lock); return; } static bool ck_spinlock_locked_with_context(ck_spinlock_t *lock, void *context) { (void)context; return ck_spinlock_locked(lock); } /* * define a cohort type named "test_cohort" that will use * the above methods for both its global and local locks */ CK_COHORT_PROTOTYPE(test_cohort, ck_spinlock_lock_with_context, ck_spinlock_unlock_with_context, ck_spinlock_locked_with_context, ck_spinlock_lock_with_context, ck_spinlock_unlock_with_context, ck_spinlock_locked_with_context) static ck_spinlock_t global_lock = CK_SPINLOCK_INITIALIZER; static unsigned int ready; static void * function(void *context) { CK_COHORT_INSTANCE(test_cohort) *cohort = context; while (ready == 0); while (ready > 0) { /* * acquire the cohort lock before performing critical section. * note that we pass NULL for both the global and local context * arguments because neither the lock nor unlock functions * will use them. */ CK_COHORT_LOCK(test_cohort, cohort, NULL, NULL); /* perform critical section */ /* relinquish cohort lock */ CK_COHORT_UNLOCK(test_cohort, cohort, NULL, NULL); } return NULL; } int main(void) { unsigned int nthr = 4; unsigned int n_cohorts = 2; unsigned int i; /* allocate 2 cohorts of the defined type */ CK_COHORT_INSTANCE(test_cohort) *cohorts = calloc(n_cohorts, sizeof(CK_COHORT_INSTANCE(test_cohort))); /* create local locks to use with each cohort */ ck_spinlock_t *local_locks = calloc(n_cohorts, sizeof(ck_spinlock_t)); pthread_t *threads = calloc(nthr, sizeof(pthread_t)); /* initialize each of the cohorts before using them */ for (i = 0 ; i < n_cohorts ; ++i) { CK_COHORT_INIT(test_cohort, cohorts + i, &global_lock, local_locks + i, CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT); } /* start each thread and assign cohorts equally */ for (i = 0 ; i < nthr ; ++i) { pthread_create(threads + i, NULL, function, cohorts + (i % n_cohorts)); } ck_pr_store_uint(&ready, 1); sleep(10); ck_pr_store_uint(&ready, 0); for (i = 0 ; i < nthr ; ++i) { pthread_join(threads[i], NULL); } return 0; } .Ed .Sh SEE ALSO .Xr CK_COHORT_PROTOTYPE 3 , .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 , .Xr CK_COHORT_INSTANCE 3 , .Xr CK_COHORT_INITIALIZER 3 , .Xr CK_COHORT_INIT 3 , .Xr CK_COHORT_LOCK 3 , .Xr CK_COHORT_UNLOCK 3 , .Xr CK_COHORT_LOCKED 3 , .Xr CK_COHORT_TRYLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_elide ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd July 13, 2013. .Dt ck_elide 3 .Sh NAME .Nm CK_ELIDE_PROTOTYPE , .Nm CK_ELIDE_LOCK_ADAPTIVE , .Nm CK_ELIDE_UNLOCK_ADAPTIVE , .Nm CK_ELIDE_LOCK , .Nm CK_ELIDE_UNLOCK , .Nm CK_ELIDE_TRYLOCK_PROTOTYPE , .Nm CK_ELIDE_TRYLOCK .Nd lock elision wrappers .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_elide.h .Pp .Dv ck_elide_stat_t stat = CK_ELIDE_STAT_INITIALIZER; .Pp .Ft void .Fn ck_elide_stat_init "ck_elide_stat_t *" .Pp .Dv struct ck_elide_config config = CK_ELIDE_CONFIG_DEFAULT_INITIALIZER; .Pp .Bd -literal -offset struct ck_elide_config { unsigned short skip_busy; short retry_busy; unsigned short skip_other; short retry_other; unsigned short skip_conflict; short retry_conflict; }; .Ed .Pp .Fn CK_ELIDE_PROTOTYPE "NAME" "TYPE" "LOCK_PREDICATE" "LOCK_FUNCTION" "UNLOCK_PREDICATE" "UNLOCK_FUNCTION" .Fn CK_ELIDE_LOCK_ADAPTIVE "NAME" "ck_elide_stat_t *" "struct ck_elide_config *" "TYPE *" .Fn CK_ELIDE_UNLOCK_ADAPTIVE "NAME" "ck_elide_stat_t *" "TYPE *" .Fn CK_ELIDE_LOCK "NAME" "TYPE *" .Fn CK_ELIDE_UNLOCK "NAME" "TYPE *" .Fn CK_ELIDE_TRYLOCK_PROTOTYPE "NAME" "TYPE" "LOCK_PREDICATE" "TRYLOCK_FUNCTION" .Sh DESCRIPTION These macros implement lock elision wrappers for a user-specified single-argument lock interface. The wrappers will attempt to elide lock acquisition, allowing concurrent execution of critical sections that do not issue conflicting memory operations. If any threads have successfully elided a lock acquisition, conflicting memory operations will roll-back any side-effects of the critical section and force every thread to retry the lock acquisition regularly. .Pp .Fn CK_ELIDE_LOCK , .Fn CK_ELIDE_UNLOCK , .Fn CK_ELIDE_LOCK_ADAPTIVE , and .Fn CK_ELIDE_UNLOCK_ADAPTIVE macros require a previous .Fn CK_ELIDE_PROTOTYPE with the same .Fa NAME . Elision is attempted if the .Fa LOCK_PREDICATE function returns false. If .Fa LOCK_PREDICATE returns true then elision is aborted and .Fa LOCK_FUNCTION is executed instead. If any threads are in an elided critical section, .Fa LOCK_FUNCTION must force them to rollback through a conflicting memory operation. The .Fa UNLOCK_PREDICATE function must return true if the lock is acquired by the caller, meaning that the lock was not successfully elided. If .Fa UNLOCK_PREDICATE returns true, then the .Fa UNLOCK_FUNCTION is executed. If RTM is unsupported (no CK_F_PR_RTM macro) then .Fn CK_ELIDE_LOCK and .Fn CK_ELIDE_LOCK_ADAPTIVE will immediately call .Fn LOCK_FUNCTION . .Fn CK_ELIDE_UNLOCK and .Fn CK_ELIDE_UNLOCK_ADAPTIVE will immediately call .Fn UNLOCK_FUNCTION . .Pp .Fn CK_ELIDE_TRYLOCK requires a previous .Fn CK_ELIDE_TRYLOCK_PROTOTYPE with the same name. Elision is attempted if the .Fa LOCK_PREDICATE function returns false. If .Fa LOCK_PREDICATE returns true or if elision fails then the operation is aborted. If RTM is unsupported (no CK_F_PR_RTM macro) then .Fn CK_ELIDE_TRYLOCK will immediately call .Fn TRYLOCK_FUNCTION . .Pp .Fn CK_ELIDE_LOCK_ADAPTIVE and .Fn CK_ELIDE_UNLOCK_ADAPTIVE will adapt the elision behavior associated with lock operations according to the run-time behavior of the program. This behavior is defined by the ck_elide_config structure pointer passed to .Fn CK_ELIDE_LOCK_ADAPTIVE . A thread-local ck_elide_stat structure must be passed to both .Fn CK_ELIDE_LOCK_ADAPTIVE and .Fn CK_ELIDE_UNLOCK_ADAPTIVE . This structure is expected to be unique for different workloads, may not be re-used in recursive acquisitions and must match the lifetime of the lock it is associated with. It is safe to mix adaptive calls with best-effort calls. .Pp Both ck_spinlock.h and ck_rwlock.h define ck_elide wrappers under the ck_spinlock and ck_rwlock namespace, respectively. .Sh EXAMPLES This example utilizes built-in lock elision facilities in ck_rwlock and ck_spinlock. .Bd -literal -offset indent #include #include static ck_rwlock_t rw = CK_RWLOCK_INITIALIZER; static struct ck_elide_config rw_config = CK_ELIDE_CONFIG_DEFAULT_INITIALIZER; static __thread ck_elide_stat_t rw_stat = CK_ELIDE_STAT_INITIALIZER; static ck_spinlock_t spinlock = CK_SPINLOCK_INITIALIZER; static struct ck_elide_config spinlock_config = CK_ELIDE_CONFIG_DEFAULT_INITIALIZER; static __thread ck_elide_stat_t spinlock_stat = CK_ELIDE_STAT_INITIALIZER; void function(void) { /* Lock-unlock write-side lock in weak best-effort manner. */ CK_ELIDE_LOCK(ck_rwlock_write, &rw); CK_ELIDE_UNLOCK(ck_rwlock_write, &rw); /* Attempt to acquire the write-side lock. */ if (CK_ELIDE_TRYLOCK(ck_rwlock_write, &rw) == true) CK_ELIDE_UNLOCK(ck_rwlock_write, &rw); /* Lock-unlock read-side lock in weak best-effort manner. */ CK_ELIDE_LOCK(ck_rwlock_read, &rw); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw); /* Attempt to acquire the read-side lock. */ if (CK_ELIDE_TRYLOCK(ck_rwlock_read, &rw) == true) CK_ELIDE_UNLOCK(ck_rwlock_read, &rw); /* Lock-unlock write-side lock in an adaptive manner. */ CK_ELIDE_LOCK_ADAPTIVE(ck_rwlock_write, &rw_stat, &rw_config, &rw); CK_ELIDE_UNLOCK_ADAPTIVE(ck_rwlock_write, &rw_stat, &rw_config, &rw); /* Lock-unlock read-side lock in an adaptive manner. */ CK_ELIDE_LOCK_ADAPTIVE(ck_rwlock_read, &rw_stat, &rw_config, &rw); CK_ELIDE_UNLOCK_ADAPTIVE(ck_rwlock_read, &rw_stat, &rw_config, &rw); /* Lock-unlock spinlock in weak best-effort manner. */ CK_ELIDE_LOCK(ck_spinlock, &spinlock); CK_ELIDE_UNLOCK(ck_spinlock, &spinlock); /* Attempt to acquire the lock. */ if (CK_ELIDE_TRYLOCK(ck_spinlock, &lock) == true) CK_ELIDE_UNLOCK(ck_spinlock, &spinlock); /* Lock-unlock spinlock in an adaptive manner. */ CK_ELIDE_LOCK_ADAPTIVE(ck_spinlock, &spinlock_stat, &spinlock_config, &spinlock); CK_ELIDE_UNLOCK_ADAPTIVE(ck_spinlock, &spinlock_stat, &spinlock_config, &spinlock); } .Ed .Pp In this example, user-defined locking functions are provided an elision implementation. .Bd -literal -offset indent /* Assume lock_t has been previously defined. */ #include /* * This function returns true if the lock is unavailable at the time * it was called or false if the lock is available. */ bool is_locked(lock_t *); /* * This function acquires the supplied lock. */ void lock(lock_t *); /* * This function releases the lock. */ void unlock(lock_t *); CK_ELIDE_PROTOTYPE(my_lock, lock_t, is_locked, lock, is_locked, unlock) static lock_t lock; void function(void) { CK_ELIDE_LOCK(my_lock, &lock); CK_ELIDE_UNLOCK(my_lock, &lock); } .Ed .Sh SEE ALSO .Xr ck_rwlock 3 , .Xr ck_spinlock 3 .Pp Ravi Rajwar and James R. Goodman. 2001. Speculative lock elision: enabling highly concurrent multithreaded execution. In Proceedings of the 34th annual ACM/IEEE international symposium on Microarchitecture (MICRO 34). IEEE Computer Society, Washington, DC, USA, 294-305. .Pp Additional information available at http://en.wikipedia.org/wiki/Transactional_Synchronization_Extensions and http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_epoch_barrier ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 2, 2012 .Dt CK_EPOCH_BARRIER 3 .Sh NAME .Nm ck_epoch_barrier .Nd block until a grace period and all callbacks have been dispatched .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_epoch.h .Ft void .Fn ck_epoch_barrier "ck_epoch_record_t *record" .Sh DESCRIPTION The .Fn ck_epoch_barrier 3 function will block the caller until a grace period has been detected, according to the semantics of epoch reclamation. Any objects requiring safe memory reclamation which are logically deleted are safe for physical deletion following a call to .Fn ck_epoch_barrier 3 . This function will also dispatch all callbacks associated with .Fa epoch that were previously scheduled via .Fn ck_epoch_call 3 . .Sh EXAMPLE .Bd -literal -offset indent #include #include #include /* * epoch was previously initialized with ck_epoch_init. * stack was previously initialized with ck_stack_init. */ ck_epoch_t *epoch; ck_stack_t *stack; void function(void) { ck_epoch_record_t *record; ck_stack_entry_t *s; record = malloc(sizeof *record); ck_epoch_register(&epoch, record); /* * We are using an epoch section here to guarantee no * nodes in the stack are deleted while we are dereferencing * them. This is needed here because there are multiple writers. * If there was only one thread popping from the this stack, * then there is no need to ck_epoch_begin/ck_epoch_end. */ ck_epoch_begin(record); /* Logically delete an object. */ s = ck_stack_pop_upmc(stack); ck_epoch_end(record); /* * Wait until no threads could possibly have a reference to the * object we just popped (assume all threads are simply executing * ck_stack_pop_upmc). */ ck_epoch_barrier(record); /* It is now safe to physically delete the object. */ free(s); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh ERRORS Behavior is undefined if the object pointed to by .Fa epoch is not a valid epoch object. The object pointed to by .Fa record must have been previously registered via .Fn ck_epoch_register 3 . .Sh SEE ALSO .Xr ck_epoch_init 3 , .Xr ck_epoch_register 3 , .Xr ck_epoch_unregister 3 , .Xr ck_epoch_recycle 3 , .Xr ck_epoch_poll 3 , .Xr ck_epoch_synchronize 3 , .Xr ck_epoch_reclaim 3 , .Xr ck_epoch_call 3 , .Xr ck_epoch_begin 3 , .Xr ck_epoch_end 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_epoch_begin ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 2, 2012 .Dt CK_EPOCH_BEGIN 3 .Sh NAME .Nm ck_epoch_begin .Nd begin epoch-protected segment of execution .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_epoch.h .Ft void .Fn ck_epoch_begin "ck_epoch_record_t *record" "ck_epoch_section_t *section" .Sh DESCRIPTION The .Fn ck_epoch_begin 3 function will mark the beginning of an epoch-protected code section. An epoch-protected code section is delimited by a call to the .Fn ck_epoch_end 3 function. Though recursion is allowed for epoch-protected sections, recursive calls will be associated with the .Fn ck_epoch_begin 3 that is at the top of the call stack. If a section is passed, then recursion on a record will cause the epoch to be refreshed on entry of every protected section. .Sh RETURN VALUES This function has no return value. .Sh ERRORS The object pointed to by .Fa epoch must have been previously initiated via .Fn ck_epoch_init 3 . The object pointed to by .Fa record must have been previously registered via .Fn ck_epoch_register 3 . .Sh SEE ALSO .Xr ck_epoch_init 3 , .Xr ck_epoch_register 3 , .Xr ck_epoch_unregister 3 , .Xr ck_epoch_recycle 3 , .Xr ck_epoch_poll 3 , .Xr ck_epoch_synchronize 3 , .Xr ck_epoch_reclaim 3 , .Xr ck_epoch_barrier 3 , .Xr ck_epoch_call 3 , .Xr ck_epoch_end 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_epoch_call ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 2, 2012 .Dt CK_EPOCH_CALL 3 .Sh NAME .Nm ck_epoch_call .Nd defer function execution until a grace period .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_epoch.h typedef struct ck_epoch_entry ck_epoch_entry_t; .br typedef void ck_epoch_cb_t(ck_epoch_entry_t *); .Ft void .Fn ck_epoch_call "ck_epoch_record_t *record" "ck_epoch_entry_t *entry" "ck_epoch_cb_t *function" .Sh DESCRIPTION The .Fn ck_epoch_call 3 function will defer the execution of the function pointed to by .Fa function until a grace-period has been detected in .Fa epoch . The function will be provided the pointer specified by .Fa entry . The function will execute at some time in the future via calls to .Fn ck_epoch_reclaim 3 , .Fn ck_epoch_barrier 3 or .Fn ck_epoch_poll 3 . .Sh EXAMPLE .Bd -literal -offset indent #include #include #include /* * epoch was previously initialized with ck_epoch_init. */ ck_epoch_t *epoch; struct object { int value; ck_epoch_entry_t epoch_entry; }; static struct object *global; CK_EPOCH_CONTAINER(struct object, epoch_entry, object_container) void destroy_object(ck_epoch_entry_t *e) { struct object *o = object_container(e); free(o); return; } void function(void) { ck_epoch_record_t *record; struct object *n; record = malloc(sizeof *record); ck_epoch_register(&epoch, record); n = malloc(sizeof *n); if (n == NULL) return; n->value = 1; /* * We are using an epoch section here because there are multiple * writers. It is also an option to use other forms of blocking * write-side synchronization such as mutexes. */ ck_epoch_begin(record); n = ck_pr_fas_ptr(&global, n); ck_epoch_end(record); /* Defer destruction of previous object. */ ck_epoch_call(record, &n->epoch_entry, destroy_object); /* Poll epoch sub-system in non-blocking manner. */ ck_epoch_poll(record); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh ERRORS The object pointed to by .Fa record must have been previously registered via .Fn ck_epoch_register 3 . .Sh SEE ALSO .Xr ck_epoch_init 3 , .Xr ck_epoch_register 3 , .Xr ck_epoch_unregister 3 , .Xr ck_epoch_recycle 3 , .Xr ck_epoch_poll 3 , .Xr ck_epoch_synchronize 3 , .Xr ck_epoch_reclaim 3 , .Xr ck_epoch_barrier 3 , .Xr ck_epoch_begin 3 , .Xr ck_epoch_end 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_epoch_end ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 2, 2012 .Dt CK_EPOCH_END 3 .Sh NAME .Nm ck_epoch_end .Nd end epoch-protected segment of execution .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_epoch.h .Ft void .Fn ck_epoch_end "ck_epoch_record_t *record" "ck_epoch_section_t *section" .Sh DESCRIPTION The .Fn ck_epoch_end 3 function will mark the end of an epoch-protected code section. .Fa section must point to a section object initialized previously with .Fn ck_epoch_begin 3 . .Sh RETURN VALUES This function has no return value. .Sh ERRORS The object pointed to by .Fa record must have been previously registered via .Fn ck_epoch_register 3 . .Sh SEE ALSO .Xr ck_epoch_init 3 , .Xr ck_epoch_register 3 , .Xr ck_epoch_unregister 3 , .Xr ck_epoch_recycle 3 , .Xr ck_epoch_poll 3 , .Xr ck_epoch_synchronize 3 , .Xr ck_epoch_reclaim 3 , .Xr ck_epoch_barrier 3 , .Xr ck_epoch_call 3 , .Xr ck_epoch_begin 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_epoch_init ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 2, 2012 .Dt CK_EPOCH_INIT 3 .Sh NAME .Nm ck_epoch_init .Nd initialize epoch reclamation object .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_epoch.h .Ft void .Fn ck_epoch_init "ck_epoch_t *epoch" .Sh DESCRIPTION The .Fn ck_epoch_init function initializes the epoch object pointed to by the .Fa epoch pointer. .Sh RETURN VALUES This function has no return value. .Sh ERRORS .Bl -tag -width Er .Pp The behavior of .Fn ck_epoch_init is undefined if .Fa epoch is not a pointer to a .Tn ck_epoch_t object. .El .Sh SEE ALSO .Xr ck_epoch_register 3 , .Xr ck_epoch_unregister 3 , .Xr ck_epoch_recycle 3 , .Xr ck_epoch_poll 3 , .Xr ck_epoch_synchronize 3 , .Xr ck_epoch_reclaim 3 , .Xr ck_epoch_barrier 3 , .Xr ck_epoch_call 3 , .Xr ck_epoch_begin 3 , .Xr ck_epoch_end 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_epoch_poll ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 2, 2012 .Dt CK_EPOCH_POLL 3 .Sh NAME .Nm ck_epoch_poll .Nd non-blocking poll of epoch object for dispatch cycles .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_epoch.h .Ft bool .Fn ck_epoch_poll "ck_epoch_record_t *record" .Sh DESCRIPTION The .Fn ck_epoch_poll 3 function will attempt to dispatch any functions associated with the object pointed to by .Fa epoch via .Fn ck_epoch_call 3 if deemed safe. This function is meant to be used in cases epoch reclamation cost must be amortized over time in a manner that does not affect caller progress. .Sh RETURN VALUES This function will return true if at least one function was dispatched. This function will return false if it has determined not all threads have observed the latest generation of epoch-protected objects. Neither value indicates an error. .Sh ERRORS Behavior is undefined if the object pointed to by .Fa record has not have been previously registered via .Fn ck_epoch_register 3 . .Sh SEE ALSO .Xr ck_epoch_init 3 , .Xr ck_epoch_register 3 , .Xr ck_epoch_unregister 3 , .Xr ck_epoch_recycle 3 , .Xr ck_epoch_synchronize 3 , .Xr ck_epoch_reclaim 3 , .Xr ck_epoch_barrier 3 , .Xr ck_epoch_call 3 , .Xr ck_epoch_begin 3 , .Xr ck_epoch_end 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_epoch_reclaim ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 2, 2013 .Dt CK_EPOCH_RECLAIM 3 .Sh NAME .Nm ck_epoch_reclaim .Nd immediately execute all deferred callbacks .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_epoch.h .Ft void .Fn ck_epoch_reclaim "ck_epoch_record_t *record" .Sh DESCRIPTION The .Fn ck_epoch_reclaim 3 function will unconditionally execute all callbacks that have been deferred with .Fn ck_epoch_call 3 . .Sh EXAMPLE .Bd -literal -offset indent #include #include #include /* * epoch was previously initialized with ck_epoch_init. */ ck_epoch_t *epoch; void function(void) { ck_epoch_record_t *record; logically_delete(object); ck_epoch_call(epoch, record, &object->epoch_entry, destructor); /* * Wait until no threads could possibly have a reference to the * object we just deleted. */ ck_epoch_synchronize(epoch, record); /* * Execute all deferred callbacks. */ ck_epoch_reclaim(record); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_epoch_init 3 , .Xr ck_epoch_register 3 , .Xr ck_epoch_unregister 3 , .Xr ck_epoch_recycle 3 , .Xr ck_epoch_poll 3 , .Xr ck_epoch_reclaim 3 , .Xr ck_epoch_barrier 3 , .Xr ck_epoch_call 3 , .Xr ck_epoch_begin 3 , .Xr ck_epoch_end 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_epoch_recycle ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 2, 2012 .Dt CK_EPOCH_RECYCLE 3 .Sh NAME .Nm ck_epoch_recycle .Nd return an epoch record that may be used by caller .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_epoch.h .Ft ck_epoch_record_t * .Fn ck_epoch_recycle "ck_epoch_t *epoch" .Sh DESCRIPTION The .Fn ck_epoch_recycle 3 function attempts to return an unused epoch record object for use by the caller. These epoch records were associated with previous calls to the .Fn ck_epoch_unregister 3 function. .Sh EXAMPLE .Bd -literal -offset indent #include #include /* * epoch was previously initialized with ck_epoch_init. */ ck_epoch_t *epoch; void function(void) { ck_epoch_record_t *record; record = ck_epoch_recycle(&epoch); if (record == NULL) { record = malloc(sizeof *record); if (record == NULL) return; ck_epoch_register(&epoch, record); } /* * After we are done, we will unregister the record so it * can be used by other new participants in the epoch system * provided by the object pointed to by "epoch". */ ck_epoch_unregister(&epoch, record); return; } .Ed .Sh RETURN VALUES This function returns a pointer to a .Dv ck_epoch_record_t object. If no unused record was found to be associated with the object pointed to by .Fa epoch , then the function will return NULL. .Sh ERRORS Behavior is undefined if the object pointed to by .Fa epoch is not a valid epoch object. .Sh SEE ALSO .Xr ck_epoch_init 3 , .Xr ck_epoch_register 3 , .Xr ck_epoch_unregister 3 , .Xr ck_epoch_poll 3 , .Xr ck_epoch_synchronize 3 , .Xr ck_epoch_reclaim 3 , .Xr ck_epoch_barrier 3 , .Xr ck_epoch_call 3 , .Xr ck_epoch_begin 3 , .Xr ck_epoch_end 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_epoch_register ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 2, 2012 .Dt CK_EPOCH_REGISTER 3 .Sh NAME .Nm ck_epoch_register .Nd register a thread for epoch reclamation .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_epoch.h .Ft void .Fn ck_epoch_register "ck_epoch_t *epoch" "ck_epoch_record_t *record" "void *cl" .Sh DESCRIPTION The .Fn ck_epoch_register 3 function associates a record object specified by the .Fa record pointer with the epoch object pointed to by .Fa epoch . Any thread or processor that will require safe memory reclamation guarantees must register a unique record object. After registration, the object pointed to by the .Fa record argument will have lifetime managed by the underlying epoch sub-system. The record object must not be destroyed after it is associated with a .Fn ck_epoch_register 3 call. An optional context pointer .Fa cl may be passed that is retrievable with the .Fn ck_epoch_record_ct 3 function. .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_epoch_init 3 , .Xr ck_epoch_unregister 3 , .Xr ck_epoch_recycle 3 , .Xr ck_epoch_poll 3 , .Xr ck_epoch_synchronize 3 , .Xr ck_epoch_reclaim 3 , .Xr ck_epoch_barrier 3 , .Xr ck_epoch_call 3 , .Xr ck_epoch_begin 3 , .Xr ck_epoch_end 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_epoch_synchronize ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 2, 2012 .Dt CK_EPOCH_SYNCHRONIZE 3 .Sh NAME .Nm ck_epoch_synchronize .Nd block until a grace period has been detected .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_epoch.h .Ft void .Fn ck_epoch_synchronize "ck_epoch_record_t *record" .Sh DESCRIPTION The .Fn ck_epoch_synchronize 3 function will block the caller until a grace period has been detected, according to the semantics of epoch reclamation. Any objects requiring safe memory reclamation which are logically deleted are safe for physical deletion following a call to .Fn ck_epoch_synchronize 3 . If you require that all callbacks be dispatched, then it is suggested that you use .Fn ck_epoch_barrier 3 instead or follow a call of .Fn ck_epoch_synchronize 3 with .Fn ck_epoch_reclaim 3 . .Sh EXAMPLE .Bd -literal -offset indent #include #include #include /* * epoch was previously initialized with ck_epoch_init. * stack was previously initialized with ck_stack_init. */ ck_epoch_t *epoch; ck_stack_t *stack; void function(void) { ck_epoch_record_t *record; ck_stack_entry_t *s; record = malloc(sizeof *record); ck_epoch_register(&epoch, record); /* * We are using an epoch section here to guarantee no * nodes in the stack are deleted while we are dereferencing * them. This is needed here because there are multiple writers. * If there was only one thread popping from the this stack, * then there is no need to ck_epoch_begin/ck_epoch_end. */ ck_epoch_begin(record); /* Logically delete an object. */ s = ck_stack_pop_upmc(stack); ck_epoch_end(record); /* * Wait until no threads could possibly have a reference to the * object we just popped (assume all threads are simply executing * ck_stack_pop_upmc). */ ck_epoch_synchronize(record); /* It is now safe to physically delete the object. */ free(s); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh ERRORS The object pointed to by .Fa record must have been previously registered via .Fn ck_epoch_register 3 . .Sh SEE ALSO .Xr ck_epoch_init 3 , .Xr ck_epoch_register 3 , .Xr ck_epoch_unregister 3 , .Xr ck_epoch_recycle 3 , .Xr ck_epoch_poll 3 , .Xr ck_epoch_reclaim 3 , .Xr ck_epoch_barrier 3 , .Xr ck_epoch_call 3 , .Xr ck_epoch_begin 3 , .Xr ck_epoch_end 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_epoch_unregister ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 2, 2012 .Dt CK_EPOCH_UNREGISTER 3 .Sh NAME .Nm ck_epoch_unregister .Nd unregister a thread for epoch reclamation .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_epoch.h .Ft void .Fn ck_epoch_unregister "ck_epoch_record_t *record" .Sh DESCRIPTION The .Fn ck_epoch_unregister 3 function allows for the record pointed by the .Fa record pointer to be used as a return value by the .Fn ck_epoch_recycle 3 function. This record can now be used by another thread of execution. Behavior is undefined if the object pointed by .Fa record is modified in any way, even after a call is made to the .Fn ck_epoch_unregister 3 function. .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_epoch_init 3 , .Xr ck_epoch_register 3 , .Xr ck_epoch_recycle 3 , .Xr ck_epoch_poll 3 , .Xr ck_epoch_synchronize 3 , .Xr ck_epoch_reclaim 3 , .Xr ck_epoch_barrier 3 , .Xr ck_epoch_call 3 , .Xr ck_epoch_begin 3 , .Xr ck_epoch_end 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_apply ================================================ .\" .\" Copyright 2014 Samy Al Bahra. .\" Copyright 2014 Backtrace I/O, Inc. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 1, 2014 .Dt CK_HS_APPLY 3 .Sh NAME .Nm ck_hs_apply .Nd apply a function to hash set value .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft void * .Fn ck_hs_apply_fn_t "void *key" "void *closure" .Ft bool .Fn ck_hs_apply "ck_hs_t *hs" "unsigned long hash" "const void *key" "ck_hs_apply_fn_t *function" "void *argument" .Sh DESCRIPTION The .Fn ck_hs_apply 3 function will lookup the hash set slot associated with .Fa key and pass it to function pointed to by .Fa function for further action. This callback may remove or replace the value by respectively returning NULL or a pointer to another object with an identical key. The first argument passed to .Fa function is a pointer to the object found in the hash set and the second argument is the .Fa argument pointer passed to .Fn ck_hs_apply 3 . If the pointer returned by .Fa function is equivalent to the first argument then no modification is made to the hash set. .Sh RETURN VALUES Upon successful completion, .Fn ck_hs_apply 3 returns true and otherwise returns false on failure. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr ck_hs_fas 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_count ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_COUNT 3 .Sh NAME .Nm ck_hs_count .Nd returns number of entries in hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft unsigned long .Fn ck_hs_count "ck_hs_t *hs" .Sh DESCRIPTION The .Fn ck_hs_count 3 function returns the number of keys currently stored in .Fa hs . .Sh ERRORS Behavior is undefined if .Fa hs is uninitialized. Behavior is undefined if this function is called by a non-writer thread. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_destroy ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_DESTROY 3 .Sh NAME .Nm ck_hs_destroy .Nd destroy hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft void .Fn ck_hs_destroy "ck_hs_t *hs" .Sh DESCRIPTION The .Fn ck_hs_destroy 3 function will request that the underlying allocator, as specified by the .Xr ck_hs_init 3 function, immediately destroy the object pointed to by the .Fa hs argument. The user must guarantee that no threads are accessing the object pointed to by .Fa hs when .Fn ck_hs_destroy 3 is called. .Sh RETURN VALUES .Fn ck_hs_destroy 3 has no return value. .Sh ERRORS This function is guaranteed not to fail. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_fas ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd June 20, 2013 .Dt CK_HS_FAS 3 .Sh NAME .Nm ck_hs_fas .Nd fetch and store key in hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft bool .Fn ck_hs_fas "ck_hs_t *hs" "unsigned long hash" "const void *key" "void **previous" .Sh DESCRIPTION The .Fn ck_hs_fas 3 function will fetch and store the key specified by the .Fa key argument in the hash set pointed to by the .Fa hs argument. The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which was previously generated using the .Xr CK_HS_HASH 3 macro). .Pp If the call to .Fn ck_hs_fas 3 was successful then the key specified by .Fa key was successfully stored in the hash set pointed to by .Fa hs . The key must already exist in the hash set, and is replaced by .Fa key and the previous value is stored into the void pointer pointed to by the .Fa previous argument. If the key does not exist in the hash set then the function will return false and the hash set is unchanged. This function is guaranteed to be stable with respect to memory usage. .Sh RETURN VALUES Upon successful completion, .Fn ck_hs_fas 3 returns true and otherwise returns false on failure. .Sh ERRORS Behavior is undefined if .Fa key or .Fa hs are uninitialized. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_gc ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd December 17, 2013 .Dt CK_HS_GC 3 .Sh NAME .Nm ck_hs_gc .Nd perform maintenance on a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft bool .Fn ck_hs_gc "ck_hs_t *hs" "unsigned long cycles" "unsigned long seed" .Sh DESCRIPTION The .Fn ck_hs_gc 3 function will perform various maintenance routines on the hash set pointed to by .Fa hs , including defragmentation of probe sequences with respect to tombstones and in the case that the delete workload hint has been passed, recalculation of probe sequence bounds. The .Fa cycles argument is used to indicate how many hash set entries should be subject to attempted maintenance. If .Fa cycles is 0, then maintenance is performed on the complete hash set. The .Fa seed argument determines the start location of the maintenance process. If .Fa cycles is non-zero, it is recommended that .Fa seed is some random value. If the delete hint has been passed, the function will require an additional 12% of memory (with respect to existing memory usage of the set), until operation completion. .Sh RETURN VALUES Upon successful completion, .Fn ck_hs_gc 3 returns true and otherwise returns false on failure due to memory allocation failure. .Sh ERRORS This function will only return false if there are internal memory allocation failures. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_get ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_GET 3 .Sh NAME .Nm ck_hs_get .Nd load a key from a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft void * .Fn ck_hs_get "ck_hs_t *hs" "unsigned long hash" "const void *key" .Sh DESCRIPTION The .Fn ck_hs_get 3 function will return a pointer to a key in the hash set .Fa hs that is of equivalent value to the object pointed to by .Fa key . The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which is to have been previously generated using the .Xr CK_HS_HASH 3 macro). .Sh RETURN VALUES If the provided key is a member of .Fa hs then a pointer to the key as stored in .Fa hs is returned. If the key was not found in .Fa hs then a value of .Dv NULL is returned. .Sh ERRORS Behavior is undefined if .Fa entry or .Fa hs are uninitialized. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_grow ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_GROW 3 .Sh NAME .Nm ck_hs_grow .Nd enlarge hash set capacity .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft bool .Fn ck_hs_grow "ck_hs_t *hs" "unsigned long capacity" .Sh DESCRIPTION The .Fn ck_hs_grow 3 function will resize the hash set in order to be able to store at least the number of entries specified by .Fa capacity at a load factor of one. The default hash set load factor is 0.5. If you wish to minimize the likelihood of memory allocations for a hash set meant to store n entries, then specify a .Fa capacity of 2n. The default behavior of ck_hs is to round .Fa capacity to the next power of two if it is not already a power of two. .Sh RETURN VALUES Upon successful completion, .Fn ck_hs_grow 3 returns true and otherwise returns false on failure. .Sh ERRORS Behavior is undefined if .Fa hs is uninitialized. This function will only return false if there are internal memory allocation failures. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_init ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_INIT 3 .Sh NAME .Nm ck_hs_init .Nd initialize a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft typedef unsigned long .Fn ck_hs_hash_cb_t "const void *key" "unsigned long seed" .Ft typedef bool .Fn ck_hs_compare_cb_t "const void *c1" "const void *c2" .Ft bool .Fn ck_hs_init "ck_hs_t *hs" "unsigned int mode" "ck_hs_hash_cb_t *hash_function" "ck_hs_compare_cb_t *compare" "struct ck_malloc *allocator" "unsigned long capacity" "unsigned long seed" .Sh DESCRIPTION The .Fn ck_hs_init function initializes the hash set pointed to by the .Fa hs pointer. .Pp The argument .Fa mode specifies the type of key-value pairs to be stored in the hash set as well as the expected concurrent access model. The value of .Fa mode consists of a bitfield of one of the following: .Bl -tag -width indent .It CK_HS_MODE_OBJECT The hash set is meant to store pointers to objects. This provides a hint that only CK_MD_VMA_BITS are necessary to encode the key argument. Any unused pointer bits are leveraged for internal optimizations. .It CK_HS_MODE_DIRECT The hash set is meant to directly store key values and that all bits of the key are used to encode values. .El .Pp The concurrent access model is specified by: .Bl -tag -width indent .It CK_HS_MODE_SPMC The hash set should allow for concurrent readers in the presence of a single writer. .It CK_HS_MODE_MPMC The hash set should allow for concurrent readers in the presence of concurrent writers. This is currently unsupported. .El .Pp The developer is free to specify additional workload hints. These hints are one of: .Bl -tag -width indent .It CK_HS_MODE_DELETE The hash set is expected to have a delete-heavy workload. At the cost of approximately 13% increased memory usage, allow for stronger per-slot probe bounds to combat the effects of tombstone accumulation. .El .Pp The argument .Fa hash_function is a mandatory pointer to a user-specified hash function. A user-specified hash function takes two arguments. The .Fa key argument is a pointer to a key. The .Fa seed argument is the initial seed associated with the hash set. This initial seed is specified by the user in .Xr ck_hs_init 3 . .Pp The .Fa compare argument is an optional pointer to a user-specified key comparison function. If NULL is specified in this argument, then pointer equality will be used to determine key equality. A user-specified comparison function takes two arguments representing pointers to the objects being compared for equality. It is expected to return true if the keys are of equal value and false otherwise. .Pp The .Fa allocator argument is a pointer to a structure containing .Fa malloc and .Fa free function pointers which respectively define the memory allocation and destruction functions to be used by the hash set being initialized. .Pp The argument .Fa capacity represents the initial number of keys the hash set is expected to contain. This argument is simply a hint and the underlying implementation is free to allocate more or less memory than necessary to contain the number of entries .Fa capacity specifies. .Pp The argument .Fa seed specifies the initial seed used by the underlying hash function. The user is free to choose a value of their choice. .Sh RETURN VALUES Upon successful completion .Fn ck_hs_init returns a value of .Dv true and otherwise returns a value of .Dv false to indicate an error. .Sh ERRORS .Bl -tag -width Er .Pp The behavior of .Fn ck_hs_init is undefined if .Fa hs is not a pointer to a .Tn ck_hs_t object. .El .Sh SEE ALSO .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_iterator_init ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_ITERATOR_INIT 3 .Sh NAME .Nm ck_hs_iterator_init .Nd initialize hash set iterator .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Pp .Dv ck_hs_iterator_t iterator = CK_HS_ITERATOR_INITIALIZER .Pp .Ft void .Fn ck_hs_iterator_init "ck_hs_iterator_t *iterator" .Sh DESCRIPTION The .Fn ck_hs_iterator_init 3 function will initialize the object pointed to by the .Fa iterator argument. Alternatively, an iterator may be statically initialized by assigning it to the CK_HS_ITERATOR_INITIALIZER value. .Pp An iterator is used to iterate through hash set entries with the .Xr ck_hs_next 3 function. .Sh RETURN VALUES .Fn ck_hs_iterator_init 3 has no return value. .Sh ERRORS This function will not fail. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_move ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd July 18, 2013 .Dt CK_HS_MOVE 3 .Sh NAME .Nm ck_hs_move .Nd move one from hash set to another .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft bool .Fn ck_hs_move "ck_hs_t *destination" "ck_hs_t *source" "ck_hs_hash_cb_t *hash_cb" "ck_hs_compare_cb_t *compare_cb" "struct ck_malloc *m" .Sh DESCRIPTION The .Fn ck_hs_move 3 function will initialize .Fa source from .Fa destination . The hash function is set to .Fa hash_cb , comparison function to .Fa compare_cb and the allocator callbacks to .Fa m . Further modifications to .Fa source will result in undefined behavior. Concurrent .Xr ck_hs_get 3 and .Xr ck_hs_fas 3 operations to .Fa source are legal until the next write operation to .Fa destination . .Pp This operation moves ownership from one hash set object to another and re-assigns callback functions to developer-specified values. This allows for dynamic configuration of allocation callbacks and is necessary for use-cases involving executable code which may be unmapped underneath the hash set. .Sh RETURN VALUES Upon successful completion .Fn ck_hs_move 3 returns true and otherwise returns false to indicate an error. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_next ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_NEXT 3 .Sh NAME .Nm ck_hs_next .Nd iterate to next entry in hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft bool .Fn ck_hs_next "ck_hs_t *hs" "ck_hs_iterator_t *iterator" "void **entry" .Sh DESCRIPTION The .Fn ck_hs_next 3 function will increment the iterator object pointed to by .Fa iterator to point to the next non-empty hash set entry. If .Fn ck_hs_next 3 returns true then the pointer pointed to by .Fa entry is initialized to the current hash set key pointed to by the .Fa iterator object. .Pp It is expected that .Fa iterator has been initialized using the .Xr ck_hs_iterator_init 3 function or statically initialized using CK_HS_ITERATOR_INITIALIZER. .Sh RETURN VALUES If .Fn ck_hs_next 3 returns true then the object pointed to by .Fa entry points to a valid hash set key. If .Fn ck_hs_next 3 returns false then the value of the object pointed to by .Fa entry is undefined. .Sh ERRORS Behavior is undefined if .Fa iterator or .Fa hs are uninitialized. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_put ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_PUT 3 .Sh NAME .Nm ck_hs_put .Nd store unique key into a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft bool .Fn ck_hs_put "ck_hs_t *hs" "unsigned long hash" "const void *key" .Sh DESCRIPTION The .Fn ck_hs_put 3 function will store the key specified by the .Fa key argument in the hash set pointed to by the .Fa hs argument. The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which was previously generated using the .Xr CK_HS_HASH 3 macro). .Pp If the call to .Fn ck_hs_put 3 was successful then the key specified by .Fa key was successfully stored in the hash set pointed to by .Fa hs . The function will fail if a key with an equivalent value to .Fa key is already present in the hash set. For replacement semantics, please see the .Xr ck_hs_set 3 function. .Sh RETURN VALUES Upon successful completion, .Fn ck_hs_put 3 returns true and otherwise returns false on failure. .Sh ERRORS Behavior is undefined if .Fa key or .Fa hs are uninitialized. The function will also return false if the hash set could not be enlarged to accomodate key insertion. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_get 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_put_unique ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd December 7, 2013 .Dt CK_HS_PUT_UNIQUE 3 .Sh NAME .Nm ck_hs_put_unique .Nd unconditionally store unique key into a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft bool .Fn ck_hs_put_unique "ck_hs_t *hs" "unsigned long hash" "const void *key" .Sh DESCRIPTION The .Fn ck_hs_put_unique 3 function will store the key specified by the .Fa key argument in the hash set pointed to by the .Fa hs argument. The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which was previously generated using the .Xr CK_HS_HASH 3 macro). .Pp If the call to .Fn ck_hs_put 3 was successful then the key specified by .Fa key was successfully stored in the hash set pointed to by .Fa hs . The function will cause undefined behavior if a key with an equivalent value is already present in the hash set. For replacement semantics, please see the .Xr ck_hs_set 3 function. .Sh RETURN VALUES Upon successful completion, .Fn ck_hs_put_unique 3 returns true and otherwise returns false on failure. .Sh ERRORS Behavior is undefined if .Fa key or .Fa hs are uninitialized. The function will also return false if the hash set could not be enlarged to accomodate key insertion. The function will result in undefined behavior if called for an already inserted key value. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_rebuild ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd December 7, 2013 .Dt CK_HS_REBUILD 3 .Sh NAME .Nm ck_hs_rebuild .Nd rebuild a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft bool .Fn ck_hs_rebuild "ck_hs_t *hs" .Sh DESCRIPTION The .Fn ck_hs_rebuild 3 function will regenerate the hash set pointed to by .Fa hs . This has the side-effect of pruning degradatory side-effects of workloads that are delete heavy. The regenerated hash set should have shorter probe sequences on average. This operation will require a significant amount of memory and is free to allocate a duplicate hash set in the rebuild process. .Sh RETURN VALUES Upon successful completion, .Fn ck_hs_rebuild 3 returns true and otherwise returns false on failure. .Sh ERRORS This function will only return false if there are internal memory allocation failures. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_remove ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_REMOVE 3 .Sh NAME .Nm ck_hs_remove .Nd remove key from a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft void * .Fn ck_hs_remove "ck_hs_t *hs" "unsigned long hash" "const void *key" .Sh DESCRIPTION The .Fn ck_hs_remove 3 function will attempt to remove the key specified by the .Fa key argument in the hash set pointed to by the .Fa hs argument. The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which was previously generated using the .Xr CK_HS_HASH 3 macro). .Pp If the call to .Fn ck_hs_remove 3 was successful then the key contained in the hash set is returned. If the key was not a member of the hash set then .Dv NULL is returned. .Sh RETURN VALUES Upon successful completion, .Fn ck_hs_remove 3 returns a pointer to a key and otherwise returns .Dv NULL on failure. .Sh ERRORS Behavior is undefined if .Fa key or .Fa hs are uninitialized. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_reset ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_RESET 3 .Sh NAME .Nm ck_hs_reset .Nd remove all keys from a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft bool .Fn ck_hs_reset "ck_hs_t *hs" .Sh DESCRIPTION The .Fn ck_hs_reset 3 function will remove all keys stored in the hash set pointed to by the .Fa hs argument. .Sh RETURN VALUES If successful, .Fn ck_hs_reset 3 will return true and will otherwise return false on failure. This function will only fail if a replacement hash set could not be allocated internally. .Sh ERRORS Behavior is undefined if .Fa hs is uninitialized. Behavior is undefined if this function is called by a non-writer thread. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_count 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_reset_size ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 5, 2013 .Dt CK_HS_RESET_SIZE 3 .Sh NAME .Nm ck_hs_reset_size .Nd remove all keys from a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft bool .Fn ck_hs_reset_size "ck_hs_t *hs" "unsigned long size" .Sh DESCRIPTION The .Fn ck_hs_reset_size 3 function will remove all keys stored in the hash set pointed to by the .Fa hs argument and create a new generation of the hash set that is preallocated for .Fa size entries. .Sh RETURN VALUES If successful, .Fn ck_hs_reset_size 3 will return true and will otherwise return false on failure. This function will only fail if a replacement hash set could not be allocated internally. .Sh ERRORS Behavior is undefined if .Fa hs is uninitialized. Behavior is undefined if this function is called by a non-writer thread. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_set ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_SET 3 .Sh NAME .Nm ck_hs_set .Nd store key into a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft bool .Fn ck_hs_set "ck_hs_t *hs" "unsigned long hash" "const void *key" "void **previous" .Sh DESCRIPTION The .Fn ck_hs_set 3 function will store the key specified by the .Fa key argument in the hash set pointed to by the .Fa hs argument. The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which was previously generated using the .Xr CK_HS_HASH 3 macro). .Pp If the call to .Fn ck_hs_set 3 was successful then the key specified by .Fa key was successfully stored in the hash set pointed to by .Fa hs . If the key already exists in the hash set, then it is replaced by .Fa key and the previous value is stored into the void pointer pointed to by the .Fa previous argument. If previous is set to .Dv NULL then .Fa key was not a replacement for an existing entry in the hash set. .Sh RETURN VALUES Upon successful completion, .Fn ck_hs_set 3 returns true and otherwise returns false on failure. .Sh ERRORS Behavior is undefined if .Fa key or .Fa hs are uninitialized. The function will also return false if the hash set could not be enlarged to accomodate key insertion. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 , .Xr ck_hs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_hs_stat ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HS_STAT 3 .Sh NAME .Nm ck_hs_stat .Nd get hash set status .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_hs.h .Ft void .Fn ck_hs_stat "ck_hs_t *hs" "struct ck_hs_stat *st" .Sh DESCRIPTION The .Fn ck_hs_stat 3 function will store various hash set statistics in the object pointed to by .Fa st . The ck_hs_stat structure is defined as follows: .Bd -literal -offset indent struct ck_hs_stat { unsigned long tombstones; /* Current number of tombstones in hash set. */ unsigned long n_entries; /* Current number of keys in hash set. */ unsigned int probe_maximum; /* Longest read-side probe sequence. */ }; .Ed .Sh RETURN VALUES .Fn ck_hs_stat 3 has no return value. .Sh ERRORS Behavior is undefined if .Fa hs is uninitialized. Behavior is undefined if this function is called by a non-writer thread. .Sh SEE ALSO .Xr ck_hs_init 3 , .Xr ck_hs_move 3 , .Xr ck_hs_destroy 3 , .Xr CK_HS_HASH 3 , .Xr ck_hs_iterator_init 3 , .Xr ck_hs_next 3 , .Xr ck_hs_get 3 , .Xr ck_hs_put 3 , .Xr ck_hs_put_unique 3 , .Xr ck_hs_set 3 , .Xr ck_hs_fas 3 , .Xr ck_hs_remove 3 , .Xr ck_hs_grow 3 , .Xr ck_hs_gc 3 , .Xr ck_hs_rebuild 3 , .Xr ck_hs_count 3 , .Xr ck_hs_reset 3 , .Xr ck_hs_reset_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_count ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 29, 2012 .Dt CK_HT_COUNT 3 .Sh NAME .Nm ck_ht_count .Nd return count of key-value pairs in hash table .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft uint64_t .Fn ck_ht_count "ck_ht_t *ht" .Sh DESCRIPTION The .Fn ck_ht_count function will return the number of entries in the hash table pointed to be the .Fa ht argument. The function may only be called without the presence of concurrent write operations. .Sh ERRORS Behavior is undefined if .Fa ht has not been initialized. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_destroy ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 29, 2012 .Dt CK_HT_DESTROY 3 .Sh NAME .Nm ck_ht_destroy .Nd immediately destroy a hash table .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft void .Fn ck_ht_destroy "ck_ht_t *ht" .Sh DESCRIPTION The .Fn ck_ht_destroy function will request that the underlying allocator, as specified by the .Xr ck_ht_init 3 function, immediately destroy the object pointed to by the .Fa ht argument. .Pp The user must guarantee that no threads are accessing the object pointed to by .Fa ht when .Fn ck_ht_destroy is called. .Sh RETURN VALUES .Fn ck_ht_destroy has no return value. .Sh ERRORS .Bl -tag -width Er This function is guaranteed not to fail. .El .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_entry_empty ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 29, 2012 .Dt CK_HT_ENTRY_EMPTY 3 .Sh NAME .Nm ck_ht_entry_empty .Nd determine whether entry contains a key-value pair .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft bool .Fn ck_ht_entry_empty "ck_ht_entry_t *entry" .Sh DESCRIPTION The .Fn ck_ht_entry_empty function will return .Dv false if .Fa entry points to a valid key-value pair. If .Fa entry does not point to a valid key-value pair it returns .Dv true. It is expected that the object pointed to by .Fa entry was initialized by a preceding call to the .Xr ck_ht_entry_set family of functions, the .Xr ck_ht_get_spmc 3 function or the .Xr ck_ht_set_spmc 3 function. .Sh ERRORS Behavior is undefined if .Fa entry has not been initialized. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_entry_key ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 30, 2012 .Dt CK_HT_ENTRY_KEY 3 .Sh NAME .Nm ck_ht_entry_key .Nd return pointer to key as specified in hash table entry .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft void * .Fn ck_ht_entry_key "ck_ht_entry_t *entry" .Sh DESCRIPTION The .Fn ck_ht_entry_key function will return the key pointer as specified in the object pointed to by the .Fa entry argument. .Pp It is expected that the entry is associated with a hash table initialized with .Dv CK_HT_MODE_BYTESTRING (see .Xr ck_ht_init 3 for more information). .Sh RETURN VALUES .Fn ck_ht_entry_key returns .Dv NULL if the entry is empty. .Sh ERRORS Behavior is undefined if .Fa entry has not been initialized. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_entry_key_direct ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 30, 2012 .Dt CK_HT_ENTRY_KEY_DIRECT 3 .Sh NAME .Nm ck_ht_entry_key_direct .Nd return key value as specified in hash table entry .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft uintptr_t .Fn ck_ht_entry_key_direct "ck_ht_entry_t *entry" .Sh DESCRIPTION The .Fn ck_ht_entry_key_direct function will return the key value as specified in the object pointed to by the .Fa entry argument. .Pp It is expected that the entry is associated with a hash table initialized with .Dv CK_HT_MODE_DIRECT (see .Xr ck_ht_init 3 for more information). .Sh RETURN VALUES .Fn ck_ht_entry_key_direct returns .Dv 0 if the entry is empty. Otherwise, it returns the key value stored in the object pointed to by the .Fa entry argument. .Sh ERRORS Behavior is undefined if .Fa entry has not been initialized. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_entry_key_length ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 30, 2012 .Dt CK_HT_ENTRY_KEY_LENGTH 3 .Sh NAME .Nm ck_ht_entry_key_length .Nd returns the length of the key specified in the argument .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft uint16_t .Fn ck_ht_entry_key_length "ck_ht_entry_t *entry" .Sh DESCRIPTION The .Fn ck_ht_entry_key_length function will return the length of the key associated with the object pointed to by the .Fa entry argument. .Pp It is expected that the entry is associated with a hash table initialized with .Dv CK_HT_MODE_BYTESTRING (see .Xr ck_ht_init 3 for more information). .Sh RETURN VALUES .Fn ck_ht_entry_key_length returns .Dv 0 if the entry is empty. .Sh ERRORS Behavior is undefined if .Fa entry has not been initialized. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_entry_key_set ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 30, 2012 .Dt CK_HT_ENTRY_KEY_SET 3 .Sh NAME .Nm ck_ht_entry_key_set .Nd initialize pointer to key in hash table entry .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft void .Fn ck_ht_entry_key_set "ck_ht_entry_t *entry" "const void *key" "uint16_t key_length" .Sh DESCRIPTION The .Fn ck_ht_entry_key_set function will initialize the object pointed to by .Fa entry with a key pointed to by the .Fa key argument. The length of the key is specified by .Fa key_length. The maximum value of .Fa key_length is defined by the CK_HT_KEY_LENGTH macro. This function is typically used to initialize an entry for .Xr ck_ht_get_spmc 3 and .Xr ck_ht_remove_spmc 3 operations. It is expected that the entry will be associated with a hash table initialized with .Dv CK_HT_MODE_BYTESTRING (see .Xr ck_ht_init 3 for more information). .Sh RETURN VALUES .Fn ck_ht_entry_key_set has no return value. .Sh ERRORS This function will never fail. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_entry_key_set_direct ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 30, 2012 .Dt CK_HT_ENTRY_KEY_SET_DIRECT 3 .Sh NAME .Nm ck_ht_entry_key_set_direct .Nd initialize key value in hash table entry .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft void .Fn ck_ht_entry_key_set_direct "ck_ht_entry_t *entry" "uintptr_t key" .Sh DESCRIPTION The .Fn ck_ht_entry_key_set_direct function will initialize the object pointed to by .Fa entry with the key value specified in the .Fa key argument. This function is typically used to initialize an entry for .Xr ck_ht_get_spmc 3 and .Xr ck_ht_remove_spmc 3 operations. It is expected that the entry will be associated with a hash table initialized with .Dv CK_HT_MODE_DIRECT (see .Xr ck_ht_init 3 for more information). .Sh RETURN VALUES .Fn ck_ht_entry_key_set_direct has no return value. .Sh ERRORS This function will never fail. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_entry_set ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 30, 2012 .Dt CK_HT_ENTRY_SET 3 .Sh NAME .Nm ck_ht_entry_set .Nd initialize a key-value pair .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft void .Fn ck_ht_entry_set "ck_ht_entry_t *entry" "ck_ht_hash_t h" "const void *key" "uint16_t key_length" "const void *value" .Sh DESCRIPTION The .Fn ck_ht_entry_set function will initialize the object pointed to by .Fa entry with a key pointed to by the .Fa key argument and a value pointed to by the .Fa value argument. The length of the key is specified by .Fa key_length. The maximum value of .Fa key_length is defined by the CK_HT_KEY_LENGTH macro. This function is typically used to initialize an entry for .Xr ck_ht_set_spmc 3 and .Xr ck_ht_put_spmc 3 operations. It is expected that the entry will be associated with a hash table initialized with .Dv CK_HT_MODE_BYTESTRING (see .Xr ck_ht_init 3 for more information). .Sh RETURN VALUES .Fn ck_ht_entry_set has no return value. .Sh ERRORS This function will never fail. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_entry_set_direct ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 30, 2012 .Dt CK_HT_ENTRY_SET_DIRECT 3 .Sh NAME .Nm ck_ht_entry_set_direct .Nd initialize a key-value pair .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft void .Fn ck_ht_entry_set_direct "ck_ht_entry_t *entry" "ck_ht_hash_t h" "uintptr_t key" "uintptr_t value" .Sh DESCRIPTION The .Fn ck_ht_entry_set function will initialize the object pointed to by .Fa entry with the hash value specified by the .Fa h argument, the key value specified in the .Fa key argument and the value specified by the .Fa value argument. .Pp This function is typically used to initialize an entry for .Xr ck_ht_set_spmc 3 and .Xr ck_ht_put_spmc 3 operations. It is expected that the entry will be associated with a hash table initialized with .Dv CK_HT_MODE_DIRECT (see .Xr ck_ht_init 3 for more information). .Sh RETURN VALUES .Fn ck_ht_entry_set_direct has no return value. .Sh ERRORS This function will never fail. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_entry_value ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 30, 2012 .Dt CK_HT_ENTRY_VALUE 3 .Sh NAME .Nm ck_ht_entry_value .Nd return pointer to value as specified in hash table entry .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft void * .Fn ck_ht_entry_value "ck_ht_entry_t *entry" .Sh DESCRIPTION The .Fn ck_ht_entry_value function will return the value pointer as specified in the object pointed to by the .Fa entry argument. .Pp It is expected that the entry is associated with a hash table initialized with .Dv CK_HT_MODE_BYTESTRING (see .Xr ck_ht_init 3 for more information). .Sh RETURN VALUES The .Fn ck_ht_entry_value function returns the value pointed to by .Dv entry. .Sh ERRORS Behavior is undefined if .Fa entry has not been initialized or if the key is empty. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_entry_value_direct ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 30, 2012 .Dt CK_HT_ENTRY_VALUE_DIRECT 3 .Sh NAME .Nm ck_ht_entry_value_direct .Nd return value as specified in hash table entry .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft uintptr_t .Fn ck_ht_entry_value_direct "ck_ht_entry_t *entry" .Sh DESCRIPTION The .Fn ck_ht_entry_value_direct function will return the value of the key-value pair as specified in the object pointed to by the .Fa entry argument. .Pp It is expected that the entry is associated with a hash table initialized with .Dv CK_HT_MODE_DIRECT (see .Xr ck_ht_init 3 for more information). .Sh RETURN VALUES The .Fn ck_ht_entry_value_direct function returns the value stored in the object pointed to by the .Fa entry argument. .Sh ERRORS Behavior is undefined if .Fa entry has not been initialized or if the key is empty. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_gc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd December 18, 2013 .Dt CK_HT_GC 3 .Sh NAME .Nm ck_ht_gc .Nd perform maintenance on a hash table .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft bool .Fn ck_ht_gc "ck_ht_t *ht" "unsigned long cycles" "unsigned long seed" .Sh DESCRIPTION The .Fn ck_ht_gc function will perform various maintenance routines on the hash table pointed to by .Fa ht , including defragmentation of probe sequences with respect to tombstones and in the case that the delete workload hint has been passed, recalculation of probe sequence bounds. The .Fa cycles argument is used to indicate how many hash table entries should be subject to attempted maintenance. If .Fa cycles is 0, then maintenance is performed on the complete hash table. The .Fa seed argument determines the start location of the maintenance process. If .Fa cycles is non-zero, it is recommended that .Fa seed is some random value. If the delete hint has been passed, the function will require an additional 12% of memory (with respect to existing memory usage of the set), until operation completion. .Sh RETURN VALUES Upon successful completion, .Fn ck_ht_gc 3 returns true and otherwise returns false on failure due to memory allocation failure. .Sh ERRORS This function will only return false if there are internal memory allocation failures. .Sh SEE ALSO .Xr ck_ht_count 3 , .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_get_spmc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 29, 2012 .Dt CK_HT_GET_SPMC 3 .Sh NAME .Nm ck_ht_get_spmc .Nd load a key-value pair from a hash table .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft bool .Fn ck_ht_get_spmc "ck_ht_t *ht" "ck_ht_hash_t h" "ck_ht_entry_t *entry" .Sh DESCRIPTION The .Fn ck_ht_get_spmc function will return the value associated with the key specified in the .Fa entry argument in the hash table pointed to by the .Fa ht argument. The key specified in .Fa entry is expected to have the hash value specified by the .Fa h argument. .Pp If .Fa ht was created with CK_HT_MODE_BYTESTRING then .Fa entry must have been initialized with the .Xr ck_ht_entry_set_key 3 or .Xr ck_ht_entry_set 3 functions. If .Fa ht was created with CK_HT_MODE_DIRECT then .Fa entry must have been initialized with the .Xr ck_ht_entry_key_set_direct 3 or .Xr ck_ht_entry_set_direct 3 functions. .Pp It is expected that .Fa h was initialized with .Xr ck_ht_hash 3 if .Fa ht was created with CK_HT_MODE_BYTESTRING. If .Fa ht was initialized with CK_HT_MODE_DIRECT then it is expected that .Fa h was initialized with the .Xr ck_ht_hash_direct 3 function. .Pp If the call to .Fn ck_ht_get_spmc was successful then the key-value pair in .Fa entry was successfully found in the hash table pointed to by .Fa h and will fail if the key specified in .Fa entry does not exist in the hash table. If successful .Fa entry will contain the key-value pair found in the hash table pointed to by the .Fa ht argument. .Pp If .Fa ht was initialized with CK_HT_MODE_BYTESTRING then the key/value pair in .Fa entry may be extracted using the .Xr ck_ht_entry_key 3 and .Xr ck_ht_entry_value 3 functions. The length of the key may be extracted using the .Xr ck_ht_entry_key_length 3 function. .Pp If .Fa ht was initialized with CK_HT_MODE_DIRECT then the key/value pair in .Fa entry may be extracted using the .Xr ck_ht_entry_key_direct 3 and .Xr ck_ht_entry_value_direct 3 functions. .Pp This function is safe to call in the presence of a concurrent writer. .Sh RETURN VALUES Upon successful completion .Fn ck_ht_get_spmc returns .Dv true. If successful, .Fa entry will contain the key/value pair as found in the hash table. Otherwise the function returns .Dv false on failure. .Sh ERRORS .Bl -tag -width Er Behavior is undefined if .Fa entry or .Fa ht are uninitialized. The function will return .Dv false if the key as specified in .Fa entry was not found in the hash table. .El .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_grow_spmc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 29, 2012 .Dt CK_HT_GROW_SPMC 3 .Sh NAME .Nm ck_ht_grow_spmc .Nd resize a hash table if necessary .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft bool .Fn ck_ht_grow_spmc "ck_ht_t *ht" "uint64_t capacity" .Sh DESCRIPTION The .Fn ck_ht_grow_spmc function will resize the hash table in order to be able to at least store the number of entries specified by .Fa capacity at a load factor of one. The default load hash table load factor is 0.5. If you wish to minimize the likelihood of memory allocations for a hash table meant to store n entries then specify a capacity of 2n. The default behavior of ck_ht is to round .Fa capacity to the next available power of two if it is not already a power of two. .Pp This function is safe to call in the presence of concurrent .Xr ck_ht_get_spmc 3 operations. .Sh RETURN VALUES Upon successful completion .Fn ck_ht_grow_spmc returns .Dv true and otherwise returns a .Dv false value. .Sh ERRORS .Bl -tag -width Er Behavior is undefined if .Fa ht is uninitialized. The function will only return .Dv false if there are internal memory allocation failures. .El .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_hash ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 29, 2012 .Dt CK_HT_HASH 3 .Sh NAME .Nm ck_ht_hash .Nd generate a hash value for a hash table .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft void .Fn ck_ht_hash "ck_ht_hash_t *h" "ck_ht_t *ht" "const void *key" "uint16_t key_length" .Sh DESCRIPTION The .Fn ck_ht_hash function will generate a hash value in the object pointed to by the .Fa h argument. The hash value is valid for use in the hash table pointed to by the .Fa ht argument for the key (of bytestring type) specified by the .Fa key argument. The length of the key is specified by the .Fa key_length argument. .Sh RETURN VALUES .Fn ck_ht_hash has no return value. .Sh ERRORS .Bl -tag -width Er Behavior is undefined if .Fa key is .Dv NULL or if .Fa ht is uninitialized. .El .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_hash_direct ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 29, 2012 .Dt CK_HT_HASH_DIRECT 3 .Sh NAME .Nm ck_ht_hash_direct .Nd generate a hash value for a hash table .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft void .Fn ck_ht_hash_direct "ck_ht_hash_t *h" "ck_ht_t *ht" "uintptr_t key" .Sh DESCRIPTION The .Fn ck_ht_hash_direct function will generate a hash value in the object pointed to by the .Fa h argument. The hash value is valid for use in the hash table pointed to by the .Fa ht argument for the key (of direct type) specified by the .Fa key argument. .Sh RETURN VALUES .Fn ck_ht_hash_direct has no return value. .Sh ERRORS .Bl -tag -width Er Behavior is undefined if .Fa key is a .Dv 0 or .Dv UINTPTR_MAX value or if .Fa ht is uninitialized. .El .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_init ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 28, 2012 .Dt CK_HT_INIT 3 .Sh NAME .Nm ck_ht_init .Nd initialize a hash table .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft typedef void .Fn ck_ht_hash_cb_t "ck_ht_hash_t *h" "const void *key" "size_t key_length" "uint64_t seed" .Ft bool .Fn ck_ht_init "ck_ht_t *ht" "enum ck_ht_mode mode" "ck_ht_hash_cb_t *hash_function" "struct ck_malloc *allocator" "uint64_t capacity" "uint64_t seed" .Sh DESCRIPTION The .Fn ck_ht_init function initializes the hash table pointed to by the .Fa ht pointer. .Pp The argument .Fa mode specifies the type of key-value pairs to be stored in the hash table. The value of .Fa mode may be one of: .Bl -tag -width indent .It CK_HT_MODE_BYTESTRING The hash table is meant to store key-value pointers where key is a region of memory that is up to 65536 bytes long. This pointer will be dereferenced during hash table operations for key comparison. Entries of this hash table are expected to be interacted with using the .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , and .Xr ck_ht_entry_set 3 functions. Attempting a hash table operation with a key of value NULL or (void *)UINTPTR_MAX will result in undefined behavior. .It CK_HT_MODE_DIRECT The hash table is meant to store key-value pointers where the key is of fixed width field compatible with the .Tn uintptr_t type. The key will be directly compared with other keys for equality. Entries of this hash table are expected to be interacted with using the .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 and .Xr ck_ht_entry_set_direct 3 functions. Attempting a hash table operation with a key of value of 0 or UINTPTR_MAX will result in undefined behavior. .El .Pp In addition to this, the user may bitwise OR the mode flag with CK_HT_WORKLOAD_DELETE to indicate that the hash table will have to handle a delete heavy workload, in which case stronger bounds on latency can be provided at the cost of approximately 13% higher memory usage. The argument .Fa hash_function is a pointer to a user-specified hash function. It is optional, if .Dv NULL is specified, then the default hash function implementation will be used ( .Xr ck_ht_hash 3 ). A user-specified hash function takes four arguments. The .Fa h argument is a pointer to a hash value object. The hash function is expected to update the .Fa value object of type .Fa uint64_t contained with-in the object pointed to by .Fa h . The .Fa key argument is a pointer to a key, the .Fa key_length argument is the length of the key and the .Fa seed argument is the initial seed associated with the hash table. This initial seed is specified by the user in .Xr ck_ht_init 3 . .Pp The .Fa allocator argument is a pointer to a structure containing .Fa malloc and .Fa free function pointers which respectively define the memory allocation and destruction functions to be used by the hash table being initialized. .Pp The argument .Fa capacity represents the initial number of key-value pairs the hash table is expected to contain. This argument is simply a hint and the underlying implementation is free to allocate more or less memory than necessary to contain the number of entries .Fa capacity specifies. .Pp The argument .Fa seed specifies the initial seed used by the underlying hash function. The user is free to choose a value of their choice. .Pp The hash table is safe to access by multiple readers in the presence of one concurrent writer. Behavior is undefined in the presence of concurrent writers. .Sh RETURN VALUES Upon successful completion .Fn ck_ht_init returns a value of .Dv true and otherwise returns a value of .Dv false to indicate an error. .Sh ERRORS .Bl -tag -width Er .Pp The behavior of .Fn ck_ht_init is undefined if .Fa ht is not a pointer to a .Tn ck_ht_t object. .El .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_iterator_init ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 30, 2012 .Dt CK_HT_ITERATOR_INIT 3 .Sh NAME .Nm ck_ht_iterator_init .Nd initialize hash table iterator .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Pp .Dv ck_ht_iterator_t iterator = CK_HT_ITERATOR_INITIALIZER .Pp .Ft void .Fn ck_ht_iterator_init "ck_ht_iterator_t *iterator" .Sh DESCRIPTION The .Fn ck_ht_iterator_init function will initialize the object pointed to by the .Fa iterator argument. Alternatively, an iterator may be statically initialized by assigning it the .Dv CK_HT_ITERATOR_INITIALIZER value. .Pp An iterator is used to iterate through hash table entries with the .Xr ck_ht_next 3 function. .Sh RETURN VALUES The .Fn ck_ht_iterator_init function does not return a value. .Sh ERRORS This function will not fail. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_next ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 30, 2012 .Dt CK_HT_NEXT 3 .Sh NAME .Nm ck_ht_next .Nd iterate to next entry in hash table .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft bool .Fn ck_ht_next "ck_ht_t *ht" "ck_ht_iterator_t *iterator" "ck_ht_entry_t **entry" .Sh DESCRIPTION The .Fn ck_ht_next function will increment the iterator object pointed to by .Fa iterator to point to the next non-empty hash table entry. If .Fn ck_ht_next returns .Dv true then the pointer pointed to by .Fa entry is initialized to the current hash table entry pointed to by the .Fa iterator object. .Pp It is expected that .Fa iterator has been initialized using the .Xr ck_ht_iterator_init 3 function or statically initialized using .Dv CK_HT_ITERATOR_INITIALIZER. .Sh RETURN VALUES If .Fn ck_ht_next returns .Dv true then the object pointed to by .Fa entry points to a valid hash table entry. If .Fn ck_ht_next returns .Dv false then value of the object pointed to by .Fa entry is undefined. .Sh ERRORS Behavior is undefined if .Fa iterator or .Fa ht are uninitialized. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_put_spmc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 29, 2012 .Dt CK_HT_PUT_SPMC 3 .Sh NAME .Nm ck_ht_put_spmc .Nd store unique key-value pair into hash table .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft bool .Fn ck_ht_put_spmc "ck_ht_t *ht" "ck_ht_hash_t h" "ck_ht_entry_t *entry" .Sh DESCRIPTION The .Fn ck_ht_put_spmc function will store the key-value pair specified in the .Fa entry argument in the hash table pointed to by the .Fa ht argument. The key specified in .Fa entry is expected to have the hash value specified by the .Fa h argument. .Pp If .Fa ht was created with CK_HT_MODE_BYTESTRING then .Fa entry must have been initialized with the .Xr ck_ht_entry_set 3 function. If .Fa ht was created with CK_HT_MODE_DIRECT then .Fa entry must have been initialized with the .Xr ck_ht_entry_set_direct 3 function. .Pp It is expected that .Fa h was initialized with .Xr ck_ht_hash 3 if .Fa ht was created with CK_HT_MODE_BYTESTRING. If .Fa ht was initialized with CK_HT_MODE_DIRECT then it is expected that .Fa h was initialized with the .Xr ck_ht_hash_direct 3 function. .Pp If the call to .Fn ck_ht_put_spmc was successful then the key-value pair in .Fa entry was successfully stored in the hash table pointed to by .Fa ht and will fail if the key specified in .Fa entry already exists with-in the hash table. Replacement semantics are provided by the .Xr ck_ht_set_spmc 3 function. .Pp This function is safe to call in the presence of concurrent .Xr ck_ht_get_spmc 3 operations. .Sh RETURN VALUES Upon successful completion .Fn ck_ht_put_spmc returns .Dv true and otherwise returns .Dv false on failure. .Sh ERRORS .Bl -tag -width Er Behavior is undefined if .Fa entry or .Fa ht are uninitialized. The function will return .Dv false if the hash table required to be grown but failed while attempting to grow or if the key specified in .Fa entry was already present in the hash table. .El .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_remove_spmc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 29, 2012 .Dt CK_HT_GROW_SPMC 3 .Sh NAME .Nm ck_ht_remove_spmc .Nd resize a hash table if necessary .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft bool .Fn ck_ht_remove_spmc "ck_ht_t *ht" "ck_ht_hash_t h" "ck_ht_entry_t *entry" .Sh DESCRIPTION The .Fn ck_ht_remove_spmc function will remove the key-value pair associated with the key specified by the .Fa entry argument. .Pp If .Fa ht was created with CK_HT_MODE_BYTESTRING then .Fa entry must have been initialized with the .Xr ck_ht_entry_set_key 3 or .Xr ck_ht_entry_set 3 functions. If .Fa ht was created with CK_HT_MODE_DIRECT then .Fa entry must have been initialized with the .Xr ck_ht_entry_key_set_direct 3 or .Xr ck_ht_entry_set_direct 3 functions. .Pp It is expected that .Fa h was initialized with .Xr ck_ht_hash 3 if .Fa ht was created with CK_HT_MODE_BYTESTRING. If .Fa ht was initialized with CK_HT_MODE_DIRECT then it is expected that .Fa h was initialized with the .Xr ck_ht_hash_direct 3 function. .Sh RETURN VALUES If successful, .Fa entry will contain the key-value pair that was found in the hash table and .Fn ck_ht_remove_spmc will return .Dv true. If the entry could not be found then .Fn ck_ht_remove_spmc will return .Dv false. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_reset_size_spmc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 5, 2013 .Dt CK_HT_RESET_SPMC 3 .Sh NAME .Nm ck_ht_reset_size_spmc .Nd remove all entries from a hash table and reset size .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft bool .Fn ck_ht_reset_size_spmc "ck_ht_t *ht" "uint64_t capacity" .Sh DESCRIPTION The .Fn ck_ht_reset_size_spmc function will remove all key-value pairs stored in the hash table pointed to by the .Fa ht argument and create a new generation of the hash table that is preallocated for .Fa capacity entries. .Sh RETURN VALUES If successful, .Fn ck_ht_reset_size_spmc will return .Dv true and will otherwise return .Dv false. This function will only fail if a replacement hash table could not be allocated internally. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_reset_spmc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 29, 2012 .Dt CK_HT_RESET_SPMC 3 .Sh NAME .Nm ck_ht_reset_spmc .Nd remove all entries from a hash table .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft bool .Fn ck_ht_reset_spmc "ck_ht_t *ht" .Sh DESCRIPTION The .Fn ck_ht_reset_spmc function will remove all key-value pairs stored in the hash table pointed to by the .Fa ht argument. .Sh RETURN VALUES If successful, .Fn ck_ht_reset_spmc will return .Dv true and will otherwise return .Dv false. This function will only fail if a replacement hash table could not be allocated internally. .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_set_spmc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd March 29, 2012 .Dt CK_HT_SET_SPMC 3 .Sh NAME .Nm ck_ht_set_spmc .Nd store key-value pair into hash table .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft bool .Fn ck_ht_set_spmc "ck_ht_t *ht" "ck_ht_hash_t h" "ck_ht_entry_t *entry" .Sh DESCRIPTION The .Fn ck_ht_set_spmc function will store the key-value pair specified in the .Fa entry argument in the hash table pointed to by the .Fa ht argument. The key specified in .Fa entry is expected to have the hash value specified by the .Fa h argument. .Pp If .Fa ht was created with CK_HT_MODE_BYTESTRING then .Fa entry must have been initialized with the .Xr ck_ht_entry_set 3 function. If .Fa ht was created with CK_HT_MODE_DIRECT then .Fa entry must have been initialized with the .Xr ck_ht_entry_set_direct 3 function. .Pp It is expected that .Fa h was initialized with .Xr ck_ht_hash 3 if .Fa ht was created with CK_HT_MODE_BYTESTRING. If .Fa ht was initialized with CK_HT_MODE_DIRECT then it is expected that .Fa h was initialized with the .Xr ck_ht_hash_direct 3 function. .Pp If the call to .Fn ck_ht_set_spmc was successful then the key-value pair in .Fa entry will contain the previous key-value pair associated with the key originally contained in the .Fa entry argument. If the operation was unsuccessful then .Fa entry is unmodified. .Pp This function is safe to call in the presence of concurrent .Xr ck_ht_get_spmc operations. .Sh RETURN VALUES Upon successful completion .Fn ck_ht_set_spmc returns .Dv true and otherwise returns .Dv false on failure. .Sh ERRORS .Bl -tag -width Er Behavior is undefined if .Fa entry or .Fa ht are uninitialized. The function will return .Dv false if the hash table required to be grown but failed while attempting to grow. .El .Sh SEE ALSO .Xr ck_ht_stat 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_count 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ht_stat ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_HT_STAT 3 .Sh NAME .Nm ck_ht_stat .Nd get hash table status .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ht.h .Ft void .Fn ck_ht_stat "ck_ht_t *ht" "struct ck_ht_stat *st" .Sh DESCRIPTION The .Fn ck_ht_stat 3 function will store various hash set statistics in the object pointed to by .Fa st . The ck_ht_stat structure is defined as follows: .Bd -literal -offset indent struct ck_ht_stat { uint64_t probe_maximum; /* Longest read-side probe sequence. */ uint64_t n_entries; /* Current number of keys in hash set. */ }; .Ed .Sh RETURN VALUES .Fn ck_ht_stat 3 has no return value. .Sh ERRORS Behavior is undefined if .Fa ht has not been initialized. .Sh SEE ALSO .Xr ck_ht_count 3 , .Xr ck_ht_init 3 , .Xr ck_ht_destroy 3 , .Xr ck_ht_hash 3 , .Xr ck_ht_hash_direct 3 , .Xr ck_ht_set_spmc 3 , .Xr ck_ht_put_spmc 3 , .Xr ck_ht_gc 3 , .Xr ck_ht_get_spmc 3 , .Xr ck_ht_grow_spmc 3 , .Xr ck_ht_remove_spmc 3 , .Xr ck_ht_reset_spmc 3 , .Xr ck_ht_reset_size_spmc 3 , .Xr ck_ht_entry_empty 3 , .Xr ck_ht_entry_key_set 3 , .Xr ck_ht_entry_key_set_direct 3 , .Xr ck_ht_entry_key 3 , .Xr ck_ht_entry_key_length 3 , .Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_set 3 , .Xr ck_ht_entry_set_direct 3 , .Xr ck_ht_entry_key_direct 3 , .Xr ck_ht_entry_value_direct 3 , .Xr ck_ht_iterator_init 3 , .Xr ck_ht_next 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pflock ================================================ .\" .\" Copyright 2014 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2014. .Dt ck_pflock 3 .Sh NAME .Nm ck_pflock_init , .Nm ck_pflock_write_lock , .Nm ck_pflock_write_unlock , .Nm ck_pflock_read_lock , .Nm ck_pflock_read_unlock , .Nd centralized phase-fair reader-writer locks .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pflock.h .Pp .Dv ck_pflock_t lock = CK_PFLOCK_INITIALIZER; .Pp .Ft void .Fn ck_pflock_init "ck_pflock_t *lock" .Ft void .Fn ck_pflock_write_lock "ck_pflock_t *lock" .Ft void .Fn ck_pflock_write_unlock "ck_pflock_t *lock" .Ft void .Fn ck_pflock_read_lock "ck_pflock_t *lock" .Ft void .Fn ck_pflock_read_unlock "ck_pflock_t *lock" .Sh DESCRIPTION This is a centralized phase-fair reader-writer lock. It requires little space overhead and has a low latency fast path. .Sh EXAMPLE .Bd -literal -offset indent #include static ck_pflock_t lock = CK_TFLOCK_INITIALIZER; static void reader(void) { for (;;) { ck_pflock_read_lock(&lock); /* Read-side critical section. */ ck_pflock_read_unlock(&lock); } return; } static void writer(void) { for (;;) { ck_pflock_write_lock(&lock); /* Write-side critical section. */ ck_pflock_write_unlock(&lock); } return; } .Ed .Sh SEE ALSO .Xr ck_brlock 3 , .Xr ck_rwlock 3 , .Xr ck_tflock 3 , .Xr ck_swlock 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr 3 .Sh NAME .Nm ck_pr .Nd concurrency primitives interface .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Sh DESCRIPTION ck_pr.h provides an interface to volatile atomic instructions, memory barriers and busy-wait facilities as provided by the underlying processor. The presence of an atomic operation is detected by the presence of a corresponding CK_F_PR macro. For example, the availability of .Xr ck_pr_add_16 3 would be determined by the presence of CK_F_PR_ADD_16. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_acquire 3 , .Xr ck_pr_fence_release 3 , .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_add ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 11, 2013 .Dt ck_pr_add 3 .Sh NAME .Nm ck_pr_add_ptr , .Nm ck_pr_add_double , .Nm ck_pr_add_char , .Nm ck_pr_add_uint , .Nm ck_pr_add_int , .Nm ck_pr_add_64 , .Nm ck_pr_add_32 , .Nm ck_pr_add_16 , .Nm ck_pr_add_8 .Nd atomic addition operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_add_ptr "void *target" "uintptr_t delta" .Ft void .Fn ck_pr_add_double "double *target" "double delta" .Ft void .Fn ck_pr_add_char "char *target" "char delta" .Ft void .Fn ck_pr_add_uint "unsigned int *target" "unsigned int delta" .Ft void .Fn ck_pr_add_int "int *target" "int delta" .Ft void .Fn ck_pr_add_64 "uint64_t *target" "uint64_t delta" .Ft void .Fn ck_pr_add_32 "uint32_t *target" "uint32_t delta" .Ft void .Fn ck_pr_add_16 "uint16_t *target" "uint16_t delta" .Ft void .Fn ck_pr_add_8 "uint8_t *target" "uint8_t delta" .Sh DESCRIPTION The .Fn ck_pr_add 3 family of functions atomically add the value specified by .Fa delta to the value pointed to by .Fa target . .Sh RETURN VALUES This family of functions does not have a return value. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_and ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 11, 2013 .Dt ck_pr_and 3 .Sh NAME .Nm ck_pr_and_ptr , .Nm ck_pr_and_char , .Nm ck_pr_and_uint , .Nm ck_pr_and_int , .Nm ck_pr_and_64 , .Nm ck_pr_and_32 , .Nm ck_pr_and_16 , .Nm ck_pr_and_8 .Nd atomic bitwise-and operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_and_ptr "void *target" "uintptr_t delta" .Ft void .Fn ck_pr_and_char "char *target" "char delta" .Ft void .Fn ck_pr_and_uint "unsigned int *target" "unsigned int delta" .Ft void .Fn ck_pr_and_int "int *target" "int delta" .Ft void .Fn ck_pr_and_64 "uint64_t *target" "uint64_t delta" .Ft void .Fn ck_pr_and_32 "uint32_t *target" "uint32_t delta" .Ft void .Fn ck_pr_and_16 "uint16_t *target" "uint16_t delta" .Ft void .Fn ck_pr_and_8 "uint8_t *target" "uint8_t delta" .Sh DESCRIPTION The .Fn ck_pr_and 3 family of functions atomically compute and store the result of a bitwise-and of the value pointed to by .Fa target and .Fa delta into the value pointed to by .Fa target . .Sh RETURN VALUES This family of functions does not have a return value. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_barrier ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_barrier 3 .Sh NAME .Nm ck_pr_barrier .Nd compiler optimization barrier .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_barrier void .Sh DESCRIPTION The .Fn ck_pr_barrier 3 function is used to disable code movement optimizations across the invocation of the function. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_btc ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 11, 2013 .Dt ck_pr_btc 3 .Sh NAME .Nm ck_pr_btc_ptr , .Nm ck_pr_btc_uint , .Nm ck_pr_btc_int , .Nm ck_pr_btc_64 , .Nm ck_pr_btc_32 , .Nm ck_pr_btc_16 .Nd atomic bit test-and-complement operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft bool .Fn ck_pr_btc_ptr "void *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_btc_uint "uint *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_btc_int "int *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_btc_64 "uint64_t *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_btc_32 "uint32_t *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_btc_16 "uint16_t *target" "unsigned int bit_index" .Sh DESCRIPTION The .Fn ck_pr_btc 3 family of functions atomically fetch the value of the bit in .Fa target at index .Fa bit_index and set that bit to its complement. .Sh RETURN VALUES These family of functions return the original value of the bit at offset .Fa bit_index that is in the value pointed to by .Fa target . .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_add 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_btr 3 , .Xr ck_pr_cas 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_btr ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 11, 2013 .Dt ck_pr_btr 3 .Sh NAME .Nm ck_pr_btr_ptr , .Nm ck_pr_btr_uint , .Nm ck_pr_btr_int , .Nm ck_pr_btr_64 , .Nm ck_pr_btr_32 , .Nm ck_pr_btr_16 .Nd atomic bit test-and-reset operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft bool .Fn ck_pr_btr_ptr "void *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_btr_uint "uint *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_btr_int "int *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_btr_64 "uint64_t *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_btr_32 "uint32_t *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_btr_16 "uint16_t *target" "unsigned int bit_index" .Sh DESCRIPTION The .Fn ck_pr_btr 3 family of functions atomically fetch the value of the bit in .Fa target at index .Fa bit_index and set that bit to 0. .Sh RETURN VALUES This family of functions returns the original value of the bit at offset .Fa bit_index that is in the value pointed to by .Fa target . .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_add 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_cas 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_bts ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 11, 2013 .Dt ck_pr_bts 3 .Sh NAME .Nm ck_pr_bts_ptr , .Nm ck_pr_bts_uint , .Nm ck_pr_bts_int , .Nm ck_pr_bts_64 , .Nm ck_pr_bts_32 , .Nm ck_pr_bts_16 .Nd atomic bit test-and-set operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft bool .Fn ck_pr_bts_ptr "void *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_bts_uint "uint *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_bts_int "int *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_bts_64 "uint64_t *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_bts_32 "uint32_t *target" "unsigned int bit_index" .Ft bool .Fn ck_pr_bts_16 "uint16_t *target" "unsigned int bit_index" .Sh DESCRIPTION The .Fn ck_pr_bts 3 family of functions atomically fetch the value of the bit in .Fa target at index .Fa bit_index and set that bit to 1. .Sh RETURN VALUES This family of functions returns the original value of the bit at offset .Fa bit_index that is in the value pointed to by .Fa target . .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_add 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_btr 3 , .Xr ck_pr_cas 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_cas ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 11, 2013 .Dt ck_pr_cas 3 .Sh NAME .Nm ck_pr_cas_ptr , .Nm ck_pr_cas_ptr_value , .Nm ck_pr_cas_ptr_2 , .Nm ck_pr_cas_ptr_2_value , .Nm ck_pr_cas_double , .Nm ck_pr_cas_double_value , .Nm ck_pr_cas_char , .Nm ck_pr_cas_char_value , .Nm ck_pr_cas_uint , .Nm ck_pr_cas_uint_value , .Nm ck_pr_cas_int , .Nm ck_pr_cas_int_value , .Nm ck_pr_cas_64_2 , .Nm ck_pr_cas_64_2_value , .Nm ck_pr_cas_64 , .Nm ck_pr_cas_64_value , .Nm ck_pr_cas_32 , .Nm ck_pr_cas_32_value , .Nm ck_pr_cas_16 , .Nm ck_pr_cas_16_value , .Nm ck_pr_cas_8 , .Nm ck_pr_cas_8_value .Nd atomic compare-and-swap operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft bool .Fn ck_pr_cas_ptr "void *target" "void *old_value" "void *new_value" .Ft bool .Fn ck_pr_cas_ptr_value "void *target" "void *old_value" "void *new_value" "void *original_value" .Ft bool .Fn ck_pr_cas_ptr_2 "void *target" "void *old_value" "void *new_value" .Ft bool .Fn ck_pr_cas_ptr_2_value "void *target" "void *old_value" "void *new_value" "void *original_value" .Ft bool .Fn ck_pr_cas_double "double *target" "double old_value" "double new_value" .Ft bool .Fn ck_pr_cas_double_value "double *target" "double old_value" "double new_value" "double *original_value" .Ft bool .Fn ck_pr_cas_char "char *target" "char old_value" "char new_value" .Ft bool .Fn ck_pr_cas_char_value "char *target" "char old_value" "char new_value" "char *original_value" .Ft bool .Fn ck_pr_cas_uint "unsigned int *target" "unsigned int old_value" "unsigned int new_value" .Ft bool .Fn ck_pr_cas_uint_value "unsigned int *target" "unsigned int old_value" "unsigned int new_value" "unsigned int *original_value" .Ft bool .Fn ck_pr_cas_int "int *target" "int old_value" "int new_value" .Ft bool .Fn ck_pr_cas_int_value "int *target" "int old_value" "int new_value" "int *original_value" .Ft bool .Fn ck_pr_cas_64_2 "uint64_t target[static 2]" "uint64_t old_value[static 2]" "uint64_t new_value[static 2]" .Ft bool .Fn ck_pr_cas_64_2_value "uint64_t target[static 2]" "uint64_t old_value[static 2]" "uint64_t new_value[static 2]" "uint64_t original_value[static 2]" .Ft bool .Fn ck_pr_cas_64 "uint64_t *target" "uint64_t old_value" "uint64_t new_value" .Ft bool .Fn ck_pr_cas_64_value "uint64_t *target" "uint64_t old_value" "uint64_t new_value" "uint64_t *original_value" .Ft bool .Fn ck_pr_cas_32 "uint32_t *target" "uint32_t old_value" "uint32_t new_value" .Ft bool .Fn ck_pr_cas_32_value "uint32_t *target" "uint32_t old_value" "uint32_t new_value" "uint32_t *original_value" .Ft bool .Fn ck_pr_cas_16 "uint16_t *target" "uint16_t old_value" "uint16_t new_value" .Ft bool .Fn ck_pr_cas_16_value "uint16_t *target" "uint16_t old_value" "uint16_t new_value" "uint16_t *original_value" .Ft bool .Fn ck_pr_cas_8 "uint8_t *target" "uint8_t old_value" "uint8_t new_value" .Ft bool .Fn ck_pr_cas_8_value "uint8_t *target" "uint8_t old_value" "uint8_t new_value" "uint8_t *original_value" .Sh DESCRIPTION The .Fn ck_pr_cas 3 family of functions atomically compare the value in .Fa target for equality with .Fa old_value and if so, replace the value pointed to by .Fa target with the value specified by .Fa new_value . If the value in .Fa target was not equal to the value specified by .Fa old_value then no modifications occur to the value in .Fa target . The *_value form of these functions unconditionally update .Fa original_value . .Sh RETURN VALUES This family of functions return true if the value in .Fa target was modified as a result of the operation. Otherwise, they return false. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_add 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_dec ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_dec 3 .Sh NAME .Nm ck_pr_dec_ptr , .Nm ck_pr_dec_ptr_zero , .Nm ck_pr_dec_double , .Nm ck_pr_dec_double_zero , .Nm ck_pr_dec_char , .Nm ck_pr_dec_char_zero , .Nm ck_pr_dec_uint , .Nm ck_pr_dec_uint_zero , .Nm ck_pr_dec_int , .Nm ck_pr_dec_int_zero , .Nm ck_pr_dec_64 , .Nm ck_pr_dec_64_zero , .Nm ck_pr_dec_32 , .Nm ck_pr_dec_32_zero , .Nm ck_pr_dec_16 , .Nm ck_pr_dec_16_zero , .Nm ck_pr_dec_8 , .Nm ck_pr_dec_8_zero .Nd atomic decrement operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_dec_ptr "void *target" .Ft void .Fn ck_pr_dec_ptr_zero "void *target" "bool *z" .Ft void .Fn ck_pr_dec_double "double *target" .Ft void .Fn ck_pr_dec_double_zero "double *target" "bool *z" .Ft void .Fn ck_pr_dec_char "char *target" .Ft void .Fn ck_pr_dec_char_zero "char *target" "bool *z" .Ft void .Fn ck_pr_dec_uint "unsigned int *target" .Ft void .Fn ck_pr_dec_uint_zero "unsigned int *target" "bool *z" .Ft void .Fn ck_pr_dec_int "int *target" .Ft void .Fn ck_pr_dec_int_zero "int *target" "bool *z" .Ft void .Fn ck_pr_dec_64 "uint64_t *target" .Ft void .Fn ck_pr_dec_64_zero "uint64_t *target" "bool *z" .Ft void .Fn ck_pr_dec_32 "uint32_t *target" .Ft void .Fn ck_pr_dec_32_zero "uint32_t *target" "bool *z" .Ft void .Fn ck_pr_dec_16 "uint16_t *target" .Ft void .Fn ck_pr_dec_16_zero "uint16_t *target" "bool *z" .Ft void .Fn ck_pr_dec_8 "uint8_t *target" .Ft void .Fn ck_pr_dec_8_zero "uint8_t *target" "bool *z" .Sh DESCRIPTION The .Fn ck_pr_dec 3 family of functions atomically decrement the value pointed to by .Fa target . .Sh RETURN VALUES The ck_pr_dec_zero family of functions set the value pointed to by .Fa z to true if the result of the decrement operation was 0. They set the value pointed to by .Fa z to false otherwise. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_faa ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_faa 3 .Sh NAME .Nm ck_pr_faa_ptr , .Nm ck_pr_faa_double , .Nm ck_pr_faa_char , .Nm ck_pr_faa_uint , .Nm ck_pr_faa_int , .Nm ck_pr_faa_64 , .Nm ck_pr_faa_32 , .Nm ck_pr_faa_16 , .Nm ck_pr_faa_8 .Nd atomic fetch-and-add operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft uintptr_t .Fn ck_pr_faa_ptr "void *target" "uintptr_t delta" .Ft double .Fn ck_pr_faa_double "double *target" "double delta" .Ft char .Fn ck_pr_faa_char "char *target" "char delta" .Ft unsigned int .Fn ck_pr_faa_uint "unsigned int *target" "unsigned int delta" .Ft int .Fn ck_pr_faa_int "int *target" "int delta" .Ft uint64_t .Fn ck_pr_faa_64 "uint64_t *target" "uint64_t delta" .Ft uint32_t .Fn ck_pr_faa_32 "uint32_t *target" "uint32_t delta" .Ft uint16_t .Fn ck_pr_faa_16 "uint16_t *target" "uint16_t delta" .Ft uint8_t .Fn ck_pr_faa_8 "uint8_t *target" "uint8_t delta" .Sh DESCRIPTION The .Fn ck_pr_faa 3 family of functions atomically fetch the value pointed to by .Fa target and add the value specified by .Fa delta to the value pointed to by .Fa target . .Sh RETURN VALUES This function returns the value pointed to by .Fa target at the time of operation invocation before the addition operation is applied. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fas ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_fas 3 .Sh NAME .Nm ck_pr_fas_ptr , .Nm ck_pr_fas_double , .Nm ck_pr_fas_char , .Nm ck_pr_fas_uint , .Nm ck_pr_fas_int , .Nm ck_pr_fas_64 , .Nm ck_pr_fas_32 , .Nm ck_pr_fas_16 , .Nm ck_pr_fas_8 .Nd atomic swap operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void * .Fn ck_pr_fas_ptr "void *target" "void *new_value" .Ft double .Fn ck_pr_fas_double "double *target" "double new_value" .Ft char .Fn ck_pr_fas_char "char *target" "char new_value" .Ft unsigned int .Fn ck_pr_fas_uint "unsigned int *target" "unsigned int new_value" .Ft int .Fn ck_pr_fas_int "int *target" "int new_value" .Ft uint64_t .Fn ck_pr_fas_64 "uint64_t *target" "uint64_t new_value" .Ft uint32_t .Fn ck_pr_fas_32 "uint32_t *target" "uint32_t new_value" .Ft uint16_t .Fn ck_pr_fas_16 "uint16_t *target" "uint16_t new_value" .Ft uint8_t .Fn ck_pr_fas_8 "uint8_t *target" "uint8_t new_value" .Sh DESCRIPTION The .Fn ck_pr_fas 3 family of functions atomically fetch the value pointed to by .Fa target and replace the value pointed to by .Fa target with the value specified by .Fa new_value . .Sh RETURN VALUES This function returns the value pointed to by .Fa target at the time of operation invocation before it was atomically replaced with .Fa new_value . .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_acquire ================================================ .\" .\" Copyright 2014 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd January 2, 2014 .Dt CK_PR_FENCE_ACQUIRE 3 .Sh NAME .Nm ck_pr_fence_acquire .Nd enforce acquire semantics .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_acquire void .Sh DESCRIPTION This function enforces the partial ordering of any loads prior to invocation with respect to any following stores, loads and atomic operations. It is typically used to implement critical sections. .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_release 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_atomic ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 16, 2013 .Dt CK_PR_FENCE_ATOMIC 3 .Sh NAME .Nm ck_pr_fence_atomic .Nd enforce partial ordering of atomic read-modify-write operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_atomic void .Ft void .Fn ck_pr_fence_strict_atomic void .Sh DESCRIPTION The .Fn ck_pr_fence_atomic function enforces the ordering of any atomic read-modify-write operations relative to the invocation of the function. This function always serve as an implicit compiler barrier. On architectures implementing CK_MD_TSO, this operation only serves as a compiler barrier and no fences are emitted. On architectures implementing CK_MD_PSO and CK_MD_RMO, a store fence is emitted. To force the unconditional emission of a fence, use .Fn ck_pr_fence_strict_atomic . .Sh EXAMPLE .Bd -literal -offset indent #include static int a = 0; static int b = 0; static int c = 0; void function(void) { ck_pr_fas_int(&a, 1); /* * Guarantee that the update to a is completed * with respect to the updates of b and c. */ ck_pr_fence_atomic(); ck_pr_fas_int(&b, 2); ck_pr_fas_int(&c, 2); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_atomic 3 , .Xr ck_pr_fence_load_store 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_atomic_load ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 16, 2013 .Dt CK_PR_FENCE_ATOMIC_LOAD 3 .Sh NAME .Nm ck_pr_fence_atomic_load .Nd enforce ordering of atomic read-modify-write operations to load operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_atomic_load void .Ft void .Fn ck_pr_fence_strict_atomic_load void .Sh DESCRIPTION The .Fn ck_pr_fence_atomic_load function enforces the ordering of any atomic read-modify-write operations relative to any load operations following the function invocation. This function always serve as an implicit compiler barrier. On architectures implementing CK_MD_TSO, this operation only serves as a compiler barrier and no fences are emitted. To force the unconditional emission of a fence, use .Fn ck_pr_fence_strict_atomic_load . .Sh EXAMPLE .Bd -literal -offset indent #include static int a = 0; static int b = 0; void function(void) { int c; ck_pr_fas_int(&a, 1); /* * Guarantee that the update to a is completed * with respect to the load of *b. */ ck_pr_fence_atomic_load(); c = ck_pr_load_int(&b); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_atomic 3 , .Xr ck_pr_fence_load_store 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_atomic_store ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 16, 2013 .Dt CK_PR_FENCE_ATOMIC_STORE 3 .Sh NAME .Nm ck_pr_fence_atomic_store .Nd enforce ordering of atomic read-modify-write operations to store operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_atomic_store void .Ft void .Fn ck_pr_fence_strict_atomic_store void .Sh DESCRIPTION The .Fn ck_pr_fence_atomic_store function enforces the ordering of any atomic read-modify-write operations relative to any load operations following the function invocation. This function always serve as an implicit compiler barrier. On architectures implementing CK_MD_TSO, this operation only serves as a compiler barrier and no fences are emitted. To force the unconditional emission of a fence, use .Fn ck_pr_fence_strict_atomic_store . .Sh EXAMPLE .Bd -literal -offset indent #include static int a = 0; static int b = 0; void function(void) { int c; ck_pr_fas_int(&a, 1); /* * Guarantee that the update to a is completed * with respect to the store into the value pointed * to by b. */ ck_pr_fence_atomic_store(); c = ck_pr_store_int(&b, 2); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_atomic 3 , .Xr ck_pr_fence_load_store 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_load ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_fence_load 3 .Sh NAME .Nm ck_pr_fence_load .Nd enforce partial ordering of load operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_load void .Ft void .Fn ck_pr_fence_strict_load void .Sh DESCRIPTION This function enforces the ordering of any memory load and .Fn ck_pr_load 3 operations relative to the invocation of the function. Any store operations that were committed on remote processors and received by the calling processor before the invocation of .Fn ck_pr_fence_load is also be made visible only after a call to .Fn ck_pr_fence_load . This function always serves as an implicit compiler barrier. On architectures with CK_MD_TSO or CK_MD_PSO specified (total store ordering and partial store ordering respectively), this operation only serves as a compiler barrier and no fence instructions will be emitted. To force the unconditional emission of a load fence, use .Fn ck_pr_fence_strict_load . Architectures implementing CK_MD_RMO always emit a load fence. .Sh EXAMPLE .Bd -literal -offset indent #include static unsigned int a; static unsigned int b; void function(void) { unsigned int snapshot_a, snapshot_b; snapshot_a = ck_pr_load_uint(&a); /* * Guarantee that the load from "a" completes * before the load from "b". */ ck_pr_fence_load(); snapshot_b = ck_pr_load_uint(&b); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_load_atomic 3 , .Xr ck_pr_fence_load_store 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_load_atomic ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 18, 2013 .Dt CK_PR_FENCE_LOAD_ATOMIC 3 .Sh NAME .Nm ck_pr_fence_load_atomic .Nd enforce ordering of load operations to atomic read-modify-write operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_load_atomic void .Ft void .Fn ck_pr_fence_strict_load_atomic void .Sh DESCRIPTION This function enforces the ordering of any memory load and .Fn ck_pr_load 3 operations with respect to store operations relative to the invocation of the function. Any store operations that were committed on remote processors and received by the calling processor before the invocation of .Fn ck_pr_fence_load_atomic is also be made visible only after a call to the ck_pr_fence_load family of functions. This function always serves as an implicit compiler barrier. On architectures with CK_MD_TSO or CK_MD_PSO specified (total store ordering and partial store ordering respectively), this operation only serves as a compiler barrier and no fence instructions will be emitted. To force the unconditional emission of a load fence, use .Fn ck_pr_fence_strict_load_atomic . Architectures implementing CK_MD_RMO always emit a fence. .Sh EXAMPLE .Bd -literal -offset indent #include static unsigned int a; static unsigned int b; void function(void) { unsigned int snapshot_a, snapshot_b; snapshot_a = ck_pr_load_uint(&a); /* * Guarantee that the load from "a" completes * before the update to "b". */ ck_pr_fence_load_atomic(); ck_pr_fas_uint(&b, 1); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_load_store 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_load_depends ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_fence_load_depends 3 .Sh NAME .Nm ck_pr_fence_load_depends .Nd data dependency barrier .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_load_depends void .Sh DESCRIPTION The .Fn ck_pr_fence_load_depends 3 emits necessary fences for pure data-dependent loads. It currently only serves as a compiler barrier for Concurrency Kit's supported platforms. Unless you're on architecture which re-orders data-dependent loads (such as the defunct Alpha), this function is unnecessary. .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_atomic 3 , .Xr ck_pr_fence_load_store 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_load_store ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 18, 2013 .Dt CK_PR_FENCE_LOAD_STORE 3 .Sh NAME .Nm ck_pr_fence_load_store .Nd enforce ordering of load operations to store operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_load_store void .Ft void .Fn ck_pr_fence_strict_load_store void .Sh DESCRIPTION This function enforces the ordering of any memory load and .Fn ck_pr_load 3 operations with respect to store operations relative to the invocation of the function. Any store operations that were committed on remote processors and received by the calling processor before the invocation of .Fn ck_pr_fence_load_store is also be made visible only after a call to the ck_pr_fence_load family of functions. This function always serves as an implicit compiler barrier. On architectures with CK_MD_TSO or CK_MD_PSO specified (total store ordering and partial store ordering respectively), this operation only serves as a compiler barrier and no fence instructions will be emitted. To force the unconditional emission of a load fence, use .Fn ck_pr_fence_strict_load_store . Architectures implementing CK_MD_RMO always emit a fence. .Sh EXAMPLE .Bd -literal -offset indent #include static unsigned int a; static unsigned int b; void function(void) { unsigned int snapshot_a; snapshot_a = ck_pr_load_uint(&a); /* * Guarantee that the load from "a" completes * before the store to "b". */ ck_pr_fence_load_store(); ck_pr_store_uint(&b, 1); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_load_atomic 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_memory ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_fence_memory 3 .Sh NAME .Nm ck_pr_fence_memory .Nd enforce partial ordering of all memory operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_memory .Ft void .Fn ck_pr_fence_strict_memory .Sh DESCRIPTION The .Fn ck_pr_fence_memory 3 function enforces the ordering of any memory operations with respect to the invocation of the function. This function always serves as an implicit compiler barrier. Achitectures implementing CK_MD_TSO do not emit a barrier, but compiler barrier semantics remain. Architectures implementing CK_MD_PSO and CK_MD_RMO always emit an instructions which provides the specified ordering guarantees. To force the unconditional emission of a memory fence, use .Fn ck_pr_fence_strict_memory . .Sh EXAMPLE .Bd -literal -offset indent #include static int a = 0; static int b; static int c; static int d; void function(void) { int snapshot_a; ck_pr_store_int(&b, 1); snapshot_a = ck_pr_load_int(&a); /* * Make sure previous memory operations are * ordered with respect to memory operations * following the ck_pr_fence_memory. */ ck_pr_fence_memory(); ck_pr_store_int(&d, 3); ck_pr_store_int(&c, 2); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_release ================================================ .\" .\" Copyright 2014 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd January 2, 2014 .Dt CK_PR_FENCE_RELEASE 3 .Sh NAME .Nm ck_pr_fence_release .Nd enforce release semantics .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_release void .Sh DESCRIPTION This function enforces the partial ordering of any loads prior to invocation with respect to any following stores and any stores prior to invocation with respect to any following stores. .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_acquire 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_store ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_fence_store 3 .Sh NAME .Nm ck_pr_fence_store .Nd enforce partial ordering of store operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_store void .Ft void .Fn ck_pr_fence_strict_store void .Sh DESCRIPTION The .Fn ck_pr_fence_store function enforces the ordering of any memory store, .Fn ck_pr_store and atomic read-modify-write operations relative to the invocation of the function. This function always serve as an implicit compiler barrier. On architectures implementing CK_MD_TSO, this operation only serves as a compiler barrier and no fences are emitted. On architectures implementing CK_MD_PSO and CK_MD_RMO, a store fence is emitted. To force the unconditional emission of a store fence, use .Fn ck_pr_fence_strict_store . .Sh EXAMPLE .Bd -literal -offset indent #include static int a = 0; static int b = 0; static int c = 0; void function(void) { ck_pr_store_int(&a, 1); /* * Guarantee that the store to a is completed * with respect to the stores of b and c. */ ck_pr_fence_store(); ck_pr_store_int(&b, 2); ck_pr_store_int(&c, 2); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_atomic 3 , .Xr ck_pr_fence_load_store 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_store_atomic ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 18, 2013 .Dt CK_PR_FENCE_STORE_ATOMIC 3 .Sh NAME .Nm ck_pr_fence_store_atomic .Nd enforce ordering of store operations to load operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_store_atomic void .Ft void .Fn ck_pr_fence_strict_store_atomic void .Sh DESCRIPTION The .Fn ck_pr_fence_store_atomic function enforces the ordering of any memory store, .Fn ck_pr_store and atomic read-modify-write operations to atomic read-modify-write operations relative to the invocation of the function. This function always serve as an implicit compiler barrier. This functions will emit a fence for PSO and RMO targets. In order to force the emission of a fence use the .Fn ck_pr_fence_strict_store_atomic function. .Sh EXAMPLE .Bd -literal -offset indent #include static int a = 0; static int b = 0; void function(void) { ck_pr_store_int(&a, 1); /* * Guarantee that the store to a is completed * with respect to the update of b. */ ck_pr_fence_store_atomic(); ck_pr_add_int(&b, 2); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_atomic 3 , .Xr ck_pr_fence_load_store 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_store_load 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_fence_store_load ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 18, 2013 .Dt CK_PR_FENCE_STORE_LOAD 3 .Sh NAME .Nm ck_pr_fence_store_load .Nd enforce ordering of store operations to load operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_fence_store_load void .Ft void .Fn ck_pr_fence_strict_store_load void .Sh DESCRIPTION The .Fn ck_pr_fence_store_load function enforces the ordering of any memory store, .Fn ck_pr_store and atomic read-modify-write operations to load operations relative to the invocation of the function. This function always serve as an implicit compiler barrier. A fence will currently always be emitted for this operation, including for TSO memory model targets. .Sh EXAMPLE .Bd -literal -offset indent #include static int a = 0; static int b = 0; void function(void) { unsigned int snapshot_b; ck_pr_store_int(&a, 1); /* * Guarantee that the store to a is completed * with respect to load from b. */ ck_pr_fence_store_load(); snapshot_b = ck_pr_load_int(&b, 2); return; } .Ed .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_pr_stall 3 , .Xr ck_pr_fence_atomic 3 , .Xr ck_pr_fence_atomic_store 3 , .Xr ck_pr_fence_atomic_load 3 , .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_atomic 3 , .Xr ck_pr_fence_load_store 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_store_atomic 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_inc ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_inc 3 .Sh NAME .Nm ck_pr_inc_ptr , .Nm ck_pr_inc_ptr_zero , .Nm ck_pr_inc_double , .Nm ck_pr_inc_double_zero , .Nm ck_pr_inc_char , .Nm ck_pr_inc_char_zero , .Nm ck_pr_inc_uint , .Nm ck_pr_inc_uint_zero , .Nm ck_pr_inc_int , .Nm ck_pr_inc_int_zero , .Nm ck_pr_inc_64 , .Nm ck_pr_inc_64_zero , .Nm ck_pr_inc_32 , .Nm ck_pr_inc_32_zero , .Nm ck_pr_inc_16 , .Nm ck_pr_inc_16_zero , .Nm ck_pr_inc_8 , .Nm ck_pr_inc_8_zero .Nd atomic increment operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_inc_ptr "void *target" .Ft void .Fn ck_pr_inc_ptr_zero "void *target" "bool *z" .Ft void .Fn ck_pr_inc_double "double *target" .Ft void .Fn ck_pr_inc_double_zero "double *target" "bool *z" .Ft void .Fn ck_pr_inc_char "char *target" .Ft void .Fn ck_pr_inc_char_zero "char *target" "bool *z" .Ft void .Fn ck_pr_inc_uint "unsigned int *target" .Ft void .Fn ck_pr_inc_uint_zero "unsigned int *target" "bool *z" .Ft void .Fn ck_pr_inc_int "int *target" .Ft void .Fn ck_pr_inc_int_zero "int *target" "bool *z" .Ft void .Fn ck_pr_inc_64 "uint64_t *target" .Ft void .Fn ck_pr_inc_64_zero "uint64_t *target" "bool *z" .Ft void .Fn ck_pr_inc_32 "uint32_t *target" .Ft void .Fn ck_pr_inc_32_zero "uint32_t *target" "bool *z" .Ft void .Fn ck_pr_inc_16 "uint16_t *target" .Ft void .Fn ck_pr_inc_16_zero "uint16_t *target" "bool *z" .Ft void .Fn ck_pr_inc_8 "uint8_t *target" .Ft void .Fn ck_pr_inc_8_zero "uint8_t *target" "bool *z" .Sh DESCRIPTION The .Fn ck_pr_inc 3 family of functions atomically increment the value pointed to by .Fa target . .Sh RETURN VALUES The ck_pr_inc_zero family of functions set the value pointed to by .Fa z to true if the result of the increment operation was 0. The functions set the value pointed to by .Fa z false otherwise. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_load ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 15, 2013 .Dt ck_pr_load 3 .Sh NAME .Nm ck_pr_load_ptr , .Nm ck_pr_load_double , .Nm ck_pr_load_uint , .Nm ck_pr_load_int , .Nm ck_pr_load_char , .Nm ck_pr_load_64 , .Nm ck_pr_load_32 , .Nm ck_pr_load_16 , .Nm ck_pr_load_8 .Nd atomic volatile load operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void * .Fn ck_pr_load_ptr "const void *target" .Ft double .Fn ck_pr_load_double "const double *target" .Ft unsigned int .Fn ck_pr_load_uint "const unsigned int *target" .Ft int .Fn ck_pr_load_int "const int *target" .Ft char .Fn ck_pr_load_char "const char *target" .Ft uint64_t .Fn ck_pr_load_64 "const uint64_t *target" .Ft uint32_t .Fn ck_pr_load_32 "const uint32_t *target" .Ft uint16_t .Fn ck_pr_load_16 "const uint16_t *target" .Ft uint8_t .Fn ck_pr_load_8 "const uint8_t *target" .Sh DESCRIPTION The .Fn ck_pr_load 3 family of functions atomically loads the value pointed to by .Fa target and returns it. This family of functions always serves as an implicit compiler barrier and is not susceptible to re-ordering by the compiler. .Sh RETURN VALUES This family of functions returns the value contained in the location pointed to by the first argument. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_add 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_neg ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_neg 3 .Sh NAME .Nm ck_pr_neg_ptr , .Nm ck_pr_neg_ptr_zero , .Nm ck_pr_neg_double , .Nm ck_pr_neg_double_zero , .Nm ck_pr_neg_char , .Nm ck_pr_neg_char_zero , .Nm ck_pr_neg_uint , .Nm ck_pr_neg_uint_zero , .Nm ck_pr_neg_int , .Nm ck_pr_neg_int_zero , .Nm ck_pr_neg_64 , .Nm ck_pr_neg_64_zero , .Nm ck_pr_neg_32 , .Nm ck_pr_neg_32_zero , .Nm ck_pr_neg_16 , .Nm ck_pr_neg_16_zero , .Nm ck_pr_neg_8 , .Nm ck_pr_neg_8_zero .Nd atomic negation operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_neg_ptr "void *target" .Ft void .Fn ck_pr_neg_ptr_zero "void *target" "bool *z" .Ft void .Fn ck_pr_neg_double "double *target" .Ft void .Fn ck_pr_neg_double_zero "double *target" "bool *z" .Ft void .Fn ck_pr_neg_char "char *target" .Ft void .Fn ck_pr_neg_char_zero "char *target" "bool *z" .Ft void .Fn ck_pr_neg_uint "unsigned int *target" .Ft void .Fn ck_pr_neg_uint_zero "unsigned int *target" "bool *z" .Ft void .Fn ck_pr_neg_int "int *target" .Ft void .Fn ck_pr_neg_int_zero "int *target" "bool *z" .Ft void .Fn ck_pr_neg_64 "uint64_t *target" .Ft void .Fn ck_pr_neg_64_zero "uint64_t *target" "bool *z" .Ft void .Fn ck_pr_neg_32 "uint32_t *target" .Ft void .Fn ck_pr_neg_32_zero "uint32_t *target" "bool *z" .Ft void .Fn ck_pr_neg_16 "uint16_t *target" .Ft void .Fn ck_pr_neg_16_zero "uint16_t *target" "bool *z" .Ft void .Fn ck_pr_neg_8 "uint8_t *target" .Ft void .Fn ck_pr_neg_8_zero "uint8_t *target" "bool *z" .Sh DESCRIPTION The .Fn ck_pr_neg 3 family of functions atomically negate the value pointed to by .Fa target . .Sh RETURN VALUES The ck_pr_neg_zero functions set the value pointed to by .Fa z if the result of the negation operation was 0. They set the pointed to value to false otherwise. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_not ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_not 3 .Sh NAME .Nm ck_pr_not_ptr , .Nm ck_pr_not_double , .Nm ck_pr_not_char , .Nm ck_pr_not_uint , .Nm ck_pr_not_int , .Nm ck_pr_not_64 , .Nm ck_pr_not_32 , .Nm ck_pr_not_16 , .Nm ck_pr_not_8 .Nd atomic complement operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_not_ptr "void *target" .Ft void .Fn ck_pr_not_double "double *target" .Ft void .Fn ck_pr_not_char "char *target" .Ft void .Fn ck_pr_not_uint "unsigned int *target" .Ft void .Fn ck_pr_not_int "int *target" .Ft void .Fn ck_pr_not_64 "uint64_t *target" .Ft void .Fn ck_pr_not_32 "uint32_t *target" .Ft void .Fn ck_pr_not_16 "uint16_t *target" .Ft void .Fn ck_pr_not_8 "uint8_t *target" .Sh DESCRIPTION The .Fn ck_pr_not 3 family of functions atomically complement the value pointed to by .Fa target . .Sh RETURN VALUES These functions have no return value. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_not 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_or ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 11, 2013 .Dt ck_pr_or 3 .Sh NAME .Nm ck_pr_or_ptr , .Nm ck_pr_or_char , .Nm ck_pr_or_uint , .Nm ck_pr_or_int , .Nm ck_pr_or_64 , .Nm ck_pr_or_32 , .Nm ck_pr_or_16 , .Nm ck_pr_or_8 .Nd atomic bitwise-or operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_or_ptr "void *target" "uintptr_t delta" .Ft void .Fn ck_pr_or_char "char *target" "char delta" .Ft void .Fn ck_pr_or_uint "unsigned int *target" "unsigned int delta" .Ft void .Fn ck_pr_or_int "int *target" "int delta" .Ft void .Fn ck_pr_or_64 "uint64_t *target" "uint64_t delta" .Ft void .Fn ck_pr_or_32 "uint32_t *target" "uint32_t delta" .Ft void .Fn ck_pr_or_16 "uint16_t *target" "uint16_t delta" .Ft void .Fn ck_pr_or_8 "uint8_t *target" "uint8_t delta" .Sh DESCRIPTION The .Fn ck_pr_or 3 family of functions atomically compute and store the result of a bitwise-or of the value pointed to by .Fa target and .Fa delta into the value pointed to by .Fa target . .Sh RETURN VALUES This family of functions does not have a return value. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_and 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_rtm ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd December 17, 2013 .Dt ck_pr_rtm 3 .Sh NAME .Nm ck_pr_rtm_begin , .Nm ck_pr_rtm_end , .Nm ck_pr_rtm_abort , .Nm ck_pr_rtm_test .Nd restricted transactional memory .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft unsigned int .Fn ck_pr_rtm_begin "void" .Ft void .Fn ck_pr_rtm_end "void" .Ft void .Fn ck_pr_rtm_abort "const unsigned int status" .Ft bool .Fn ck_pr_rtm_test "void" .Sh DESCRIPTION These family of functions implement support for restricted transactional memory, if available on the underlying platform. Currently, support is only provided for Intel Haswell and newer x86 microarchitectures that have the TSX-NI feature. .Pp The .Fn ck_pr_rtm_begin function returns CK_PR_RTM_STARTED if a transaction was successfully started. In case of an abort, either internal (through a ck_pr_rtm_abort) or external, program flow will return to the point which the function was called except the return value will consist of a bitmap with one or more of the following bits set: .Bl -tag -width indent .It CK_PR_RTM_EXPLICIT Set if the transactionally was explicitly aborted through .Fn ck_pr_rtm_abort . .It CK_PR_RTM_RETRY Set if the transaction failed but can still succeed if retried. .It CK_PR_RTM_CONFLICT The transaction failed due to a conflict in one of the memory addresses that are part of the working set of the transaction. .It CK_PR_RTM_CAPACITY Set if the architecture-defined transaction size limit was exceeded. .It CK_PR_RTM_DEBUG Set if a hardware breakpoint was triggered. .It CK_PR_RTM_NESTED Set if a nested transaction failed. .El .Pp The user is also able to specify a one byte abort status by calling .Fn ck_pr_rtm_abort . This status byte can be extracted by calling the .Fn CK_PR_RTM_CODE function with the return value of .Fn ck_pr_rtm_begin as an argument. The return value of .Fn CK_PR_RTM_CODE will be the value of this status byte. For additional information, please see the Intel instruction set manuals. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_add 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_stall ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 7, 2013 .Dt ck_pr_stall 3 .Sh NAME .Nm ck_pr_stall .Nd busy-wait primitive .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_stall void .Sh DESCRIPTION The .Fn ck_pr_stall 3 function should be used inside retry paths of busy-wait loops. It not only serves as a compiler barrier, but on some architectures it emits cycle-saving instructions. .Sh EXAMPLE .Bd -literal -offset indent #include static int ready = 0; void function(void) { /* Busy-wait until ready is non-zero. */ while (ck_pr_load_int(&ready) == 0) ck_pr_stall(); return; } .Ed .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_barrier 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_store ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 15, 2013 .Dt ck_pr_store 3 .Sh NAME .Nm ck_pr_store_ptr , .Nm ck_pr_store_double , .Nm ck_pr_store_uint , .Nm ck_pr_store_int , .Nm ck_pr_store_char , .Nm ck_pr_store_64 , .Nm ck_pr_store_32 , .Nm ck_pr_store_16 , .Nm ck_pr_store_8 .Nd atomic volatile store operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_store_ptr "void *target" "void *value" .Ft void .Fn ck_pr_store_double "double *target" "double value" .Ft void .Fn ck_pr_store_uint "unsigned int *target" "unsigned int value" .Ft void .Fn ck_pr_store_int "int *target" "int value" .Ft void .Fn ck_pr_store_char "char *target" "char value" .Ft void .Fn ck_pr_store_64 "uint64_t *target" "uint64_t value" .Ft void .Fn ck_pr_store_32 "uint32_t *target" "uint32_t value" .Ft void .Fn ck_pr_store_16 "uint16_t *target" "uint16_t value" .Ft void .Fn ck_pr_store_8 "uint8_t *target" "uint8_t value" .Sh DESCRIPTION The .Fn ck_pr_store 3 family of functions atomically stores the value specified by .Fa value into the location pointed to by .Fa target . This family of functions always serves as an implicit compiler barrier and is not susceptible to compiler re-ordering. .Sh RETURN VALUES This family of functions has no return value. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_add 3 , .Xr ck_pr_load 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_sub ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 11, 2013 .Dt ck_pr_sub 3 .Sh NAME .Nm ck_pr_sub_ptr , .Nm ck_pr_sub_double , .Nm ck_pr_sub_char , .Nm ck_pr_sub_uint , .Nm ck_pr_sub_int , .Nm ck_pr_sub_64 , .Nm ck_pr_sub_32 , .Nm ck_pr_sub_16 , .Nm ck_pr_sub_8 .Nd atomic subtraction operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_sub_ptr "void *target" "uintptr_t delta" .Ft void .Fn ck_pr_sub_double "double *target" "double delta" .Ft void .Fn ck_pr_sub_char "char *target" "char delta" .Ft void .Fn ck_pr_sub_uint "unsigned int *target" "unsigned int delta" .Ft void .Fn ck_pr_sub_int "int *target" "int delta" .Ft void .Fn ck_pr_sub_64 "uint64_t *target" "uint64_t delta" .Ft void .Fn ck_pr_sub_32 "uint32_t *target" "uint32_t delta" .Ft void .Fn ck_pr_sub_16 "uint16_t *target" "uint16_t delta" .Ft void .Fn ck_pr_sub_8 "uint8_t *target" "uint8_t delta" .Sh DESCRIPTION The .Fn ck_pr_sub 3 family of functions atomically subtract the value specified by .Fa delta from the value pointed to by .Fa target . .Sh RETURN VALUES This family of functions does not have a return value. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_and 3 , .Xr ck_pr_or 3 , .Xr ck_pr_xor 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_pr_xor ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 11, 2013 .Dt ck_pr_xor 3 .Sh NAME .Nm ck_pr_xor_ptr , .Nm ck_pr_xor_char , .Nm ck_pr_xor_uint , .Nm ck_pr_xor_int , .Nm ck_pr_xor_64 , .Nm ck_pr_xor_32 , .Nm ck_pr_xor_16 , .Nm ck_pr_xor_8 .Nd atomic bitwise-xor operations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_pr.h .Ft void .Fn ck_pr_xor_ptr "void *target" "uintptr_t delta" .Ft void .Fn ck_pr_xor_char "char *target" "char delta" .Ft void .Fn ck_pr_xor_uint "unsigned int *target" "unsigned int delta" .Ft void .Fn ck_pr_xor_int "int *target" "int delta" .Ft void .Fn ck_pr_xor_64 "uint64_t *target" "uint64_t delta" .Ft void .Fn ck_pr_xor_32 "uint32_t *target" "uint32_t delta" .Ft void .Fn ck_pr_xor_16 "uint16_t *target" "uint16_t delta" .Ft void .Fn ck_pr_xor_8 "uint8_t *target" "uint8_t delta" .Sh DESCRIPTION The .Fn ck_pr_xor 3 family of functions atomically compute and store the result of a bitwise-xor of the value pointed to by .Fa target and .Fa delta into the value pointed to by .Fa target . .Sh RETURN VALUES This family of functions does not have a return value. .Sh SEE ALSO .Xr ck_pr_fence_load 3 , .Xr ck_pr_fence_load_depends 3 , .Xr ck_pr_fence_store 3 , .Xr ck_pr_fence_memory 3 , .Xr ck_pr_load 3 , .Xr ck_pr_store 3 , .Xr ck_pr_fas 3 , .Xr ck_pr_faa 3 , .Xr ck_pr_inc 3 , .Xr ck_pr_dec 3 , .Xr ck_pr_neg 3 , .Xr ck_pr_not 3 , .Xr ck_pr_add 3 , .Xr ck_pr_sub 3 , .Xr ck_pr_or 3 , .Xr ck_pr_and 3 , .Xr ck_pr_cas 3 , .Xr ck_pr_btc 3 , .Xr ck_pr_bts 3 , .Xr ck_pr_btr 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_queue ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd July 28, 2013. .Dt ck_queue 3 .Sh NAME .Nm CK_LIST_EMPTY , .Nm CK_LIST_ENTRY , .Nm CK_LIST_FIRST , .Nm CK_LIST_FOREACH , .Nm CK_LIST_FOREACH_SAFE , .Nm CK_LIST_HEAD , .Nm CK_LIST_HEAD_INITIALIZER , .Nm CK_LIST_INIT , .Nm CK_LIST_INSERT_AFTER , .Nm CK_LIST_INSERT_BEFORE , .Nm CK_LIST_INSERT_HEAD , .Nm CK_LIST_MOVE , .Nm CK_LIST_NEXT , .Nm CK_LIST_REMOVE , .Nm CK_LIST_SWAP , .Nm CK_SLIST_EMPTY , .Nm CK_SLIST_ENTRY , .Nm CK_SLIST_FIRST , .Nm CK_SLIST_FOREACH , .Nm CK_SLIST_FOREACH_PREVPTR , .Nm CK_SLIST_FOREACH_SAFE , .Nm CK_SLIST_HEAD , .Nm CK_SLIST_HEAD_INITIALIZER , .Nm CK_SLIST_INIT , .Nm CK_SLIST_INSERT_AFTER , .Nm CK_SLIST_INSERT_HEAD , .Nm CK_SLIST_MOVE , .Nm CK_SLIST_NEXT , .Nm CK_SLIST_REMOVE , .Nm CK_SLIST_REMOVE_AFTER , .Nm CK_SLIST_REMOVE_HEAD , .Nm CK_SLIST_SWAP , .Nm CK_STAILQ_CONCAT , .Nm CK_STAILQ_EMPTY , .Nm CK_STAILQ_ENTRY , .Nm CK_STAILQ_FIRST , .Nm CK_STAILQ_FOREACH , .Nm CK_STAILQ_FOREACH_SAFE , .Nm CK_STAILQ_HEAD , .Nm CK_STAILQ_HEAD_INITIALIZER , .Nm CK_STAILQ_INIT , .Nm CK_STAILQ_INSERT_AFTER , .Nm CK_STAILQ_INSERT_HEAD , .Nm CK_STAILQ_INSERT_TAIL , .Nm CK_STAILQ_MOVE , .Nm CK_STAILQ_NEXT , .Nm CK_STAILQ_REMOVE , .Nm CK_STAILQ_REMOVE_AFTER , .Nm CK_STAILQ_REMOVE_HEAD , .Nm CK_STAILQ_SWAP .Nd multi-reader single-writer singly-linked lists, singly-linked tail queues and lists .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_queue.h .Fn CK_LIST_EMPTY .Fn CK_LIST_ENTRY .Fn CK_LIST_FIRST .Fn CK_LIST_FOREACH .Fn CK_LIST_FOREACH_SAFE .Fn CK_LIST_HEAD .Fn CK_LIST_HEAD_INITIALIZER .Fn CK_LIST_INIT .Fn CK_LIST_INSERT_AFTER .Fn CK_LIST_INSERT_BEFORE .Fn CK_LIST_INSERT_HEAD .Fn CK_LIST_MOVE .Fn CK_LIST_NEXT .Fn CK_LIST_REMOVE .Fn CK_LIST_SWAP .Fn CK_SLIST_EMPTY .Fn CK_SLIST_ENTRY .Fn CK_SLIST_FIRST .Fn CK_SLIST_FOREACH .Fn CK_SLIST_FOREACH_PREVPTR .Fn CK_SLIST_FOREACH_SAFE .Fn CK_SLIST_HEAD .Fn CK_SLIST_HEAD_INITIALIZER .Fn CK_SLIST_INIT .Fn CK_SLIST_INSERT_AFTER .Fn CK_SLIST_INSERT_HEAD .Fn CK_SLIST_MOVE .Fn CK_SLIST_NEXT .Fn CK_SLIST_REMOVE .Fn CK_SLIST_REMOVE_AFTER .Fn CK_SLIST_REMOVE_HEAD .Fn CK_SLIST_SWAP .Fn CK_STAILQ_CONCAT .Fn CK_STAILQ_EMPTY .Fn CK_STAILQ_ENTRY .Fn CK_STAILQ_FIRST .Fn CK_STAILQ_FOREACH .Fn CK_STAILQ_FOREACH_SAFE .Fn CK_STAILQ_HEAD .Fn CK_STAILQ_HEAD_INITIALIZER .Fn CK_STAILQ_INIT .Fn CK_STAILQ_INSERT_AFTER .Fn CK_STAILQ_INSERT_HEAD .Fn CK_STAILQ_INSERT_TAIL .Fn CK_STAILQ_MOVE .Fn CK_STAILQ_NEXT .Fn CK_STAILQ_REMOVE .Fn CK_STAILQ_REMOVE_AFTER .Fn CK_STAILQ_REMOVE_HEAD .Fn CK_STAILQ_SWAP .Sh DESCRIPTION See your system's manual page for .Xr queue for additional information. ck_queue is a queue.h-compatible implementation of many-reader-single-writer queues. It allows for safe concurrent iteration, peeking and read-side access in the presence of a single concurrent writer without any usage of locks. In many cases, adoption of ck_queue will simply require prefixing all queue operations with CK_. .Sh SEE ALSO .Xr queue .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_apply ================================================ .\" .\" Copyright 2014 Samy Al Bahra. .\" Copyright 2014 Backtrace I/O, Inc. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 1, 2014 .Dt CK_RHS_APPLY 3 .Sh NAME .Nm ck_rhs_apply .Nd apply a function to hash set value .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft void * .Fn ck_rhs_apply_fn_t "void *key" "void *closure" .Ft bool .Fn ck_rhs_apply "ck_rhs_t *hs" "unsigned long hash" "const void *key" "ck_rhs_apply_fn_t *function" "void *argument" .Sh DESCRIPTION The .Fn ck_rhs_apply 3 function will lookup the hash set slot associated with .Fa key and pass it to function pointed to by .Fa function for further action. This callback may remove or replace the value by respectively returning NULL or a pointer to another object with an identical key. The first argument passed to .Fa function is a pointer to the object found in the hash set and the second argument is the .Fa argument pointer passed to .Fn ck_rhs_apply 3 . If the pointer returned by .Fa function is equivalent to the first argument then no modification is made to the hash set. .Sh RETURN VALUES Upon successful completion, .Fn ck_rhs_apply 3 returns true and otherwise returns false on failure. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr ck_rhs_fas 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_count ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_COUNT 3 .Sh NAME .Nm ck_rhs_count .Nd returns number of entries in hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft unsigned long .Fn ck_rhs_count "ck_rhs_t *hs" .Sh DESCRIPTION The .Fn ck_rhs_count 3 function returns the number of keys currently stored in .Fa hs . .Sh ERRORS Behavior is undefined if .Fa hs is uninitialized. Behavior is undefined if this function is called by a non-writer thread. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_destroy ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_DESTROY 3 .Sh NAME .Nm ck_rhs_destroy .Nd destroy hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft void .Fn ck_rhs_destroy "ck_rhs_t *hs" .Sh DESCRIPTION The .Fn ck_rhs_destroy 3 function will request that the underlying allocator, as specified by the .Xr ck_rhs_init 3 function, immediately destroy the object pointed to by the .Fa hs argument. The user must guarantee that no threads are accessing the object pointed to by .Fa hs when .Fn ck_rhs_destroy 3 is called. .Sh RETURN VALUES .Fn ck_rhs_destroy 3 has no return value. .Sh ERRORS This function is guaranteed not to fail. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_fas ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd June 20, 2013 .Dt CK_RHS_FAS 3 .Sh NAME .Nm ck_rhs_fas .Nd fetch and store key in hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_fas "ck_rhs_t *hs" "unsigned long hash" "const void *key" "void **previous" .Sh DESCRIPTION The .Fn ck_rhs_fas 3 function will fetch and store the key specified by the .Fa key argument in the hash set pointed to by the .Fa hs argument. The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which was previously generated using the .Xr CK_RHS_HASH 3 macro). .Pp If the call to .Fn ck_rhs_fas 3 was successful then the key specified by .Fa key was successfully stored in the hash set pointed to by .Fa hs . The key must already exist in the hash set, and is replaced by .Fa key and the previous value is stored into the void pointer pointed to by the .Fa previous argument. If the key does not exist in the hash set then the function will return false and the hash set is unchanged. This function is guaranteed to be stable with respect to memory usage. .Sh RETURN VALUES Upon successful completion, .Fn ck_rhs_fas 3 returns true and otherwise returns false on failure. .Sh ERRORS Behavior is undefined if .Fa key or .Fa hs are uninitialized. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_gc ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd December 17, 2013 .Dt CK_RHS_GC 3 .Sh NAME .Nm ck_rhs_gc .Nd perform maintenance on a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_gc "ck_rhs_t *hs" .Sh DESCRIPTION The .Fn ck_rhs_gc 3 function will perform various maintenance routines on the hash set pointed to by .Fa hs , including recalculating the maximum number of probes. .Sh RETURN VALUES Upon successful completion, .Fn ck_rhs_gc 3 returns true and otherwise returns false on failure due to memory allocation failure. .Sh ERRORS This function will only return false if there are internal memory allocation failures. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_get ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_GET 3 .Sh NAME .Nm ck_rhs_get .Nd load a key from a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft void * .Fn ck_rhs_get "ck_rhs_t *hs" "unsigned long hash" "const void *key" .Sh DESCRIPTION The .Fn ck_rhs_get 3 function will return a pointer to a key in the hash set .Fa hs that is of equivalent value to the object pointed to by .Fa key . The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which is to have been previously generated using the .Xr CK_RHS_HASH 3 macro). .Sh RETURN VALUES If the provided key is a member of .Fa hs then a pointer to the key as stored in .Fa hs is returned. If the key was not found in .Fa hs then a value of .Dv NULL is returned. .Sh ERRORS Behavior is undefined if .Fa entry or .Fa hs are uninitialized. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_grow ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_GROW 3 .Sh NAME .Nm ck_rhs_grow .Nd enlarge hash set capacity .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_grow "ck_rhs_t *hs" "unsigned long capacity" .Sh DESCRIPTION The .Fn ck_rhs_grow 3 function will resize the hash set in order to be able to store at least the number of entries specified by .Fa capacity at a load factor of one. The default hash set load factor is 0.5. If you wish to minimize the likelihood of memory allocations for a hash set meant to store n entries, then specify a .Fa capacity of 2n. The default behavior of ck_rhs is to round .Fa capacity to the next power of two if it is not already a power of two. .Sh RETURN VALUES Upon successful completion, .Fn ck_rhs_grow 3 returns true and otherwise returns false on failure. .Sh ERRORS Behavior is undefined if .Fa hs is uninitialized. This function will only return false if there are internal memory allocation failures. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_init ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_INIT 3 .Sh NAME .Nm ck_rhs_init .Nd initialize a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft typedef unsigned long .Fn ck_rhs_hash_cb_t "const void *key" "unsigned long seed" .Ft typedef bool .Fn ck_rhs_compare_cb_t "const void *c1" "const void *c2" .Ft bool .Fn ck_rhs_init "ck_rhs_t *hs" "unsigned int mode" "ck_rhs_hash_cb_t *hash_function" "ck_rhs_compare_cb_t *compare" "struct ck_malloc *allocator" "unsigned long capacity" "unsigned long seed" .Sh DESCRIPTION The .Fn ck_rhs_init function initializes the hash set pointed to by the .Fa hs pointer. .Pp The argument .Fa mode specifies the type of key-value pairs to be stored in the hash set as well as the expected concurrent access model. The value of .Fa mode consists of a bitfield of one of the following: .Bl -tag -width indent .It CK_RHS_MODE_OBJECT The hash set is meant to store pointers to objects. This provides a hint that only CK_MD_VMA_BITS are necessary to encode the key argument. Any unused pointer bits are leveraged for internal optimizations. .It CK_RHS_MODE_DIRECT The hash set is meant to directly store key values and that all bits of the key are used to encode values. .It CK_RHS_MODE_READ_MOSTLY Optimize read operations over put/delete. .El .Pp The concurrent access model is specified by: .Bl -tag -width indent .It CK_RHS_MODE_SPMC The hash set should allow for concurrent readers in the presence of a single writer. .It CK_RHS_MODE_MPMC The hash set should allow for concurrent readers in the presence of concurrent writers. This is currently unsupported. .El .Pp The developer is free to specify additional workload hints. These hints are one of: .Bl -tag -width indent .El .Pp The argument .Fa hash_function is a mandatory pointer to a user-specified hash function. A user-specified hash function takes two arguments. The .Fa key argument is a pointer to a key. The .Fa seed argument is the initial seed associated with the hash set. This initial seed is specified by the user in .Xr ck_rhs_init 3 . .Pp The .Fa compare argument is an optional pointer to a user-specified key comparison function. If NULL is specified in this argument, then pointer equality will be used to determine key equality. A user-specified comparison function takes two arguments representing pointers to the objects being compared for equality. It is expected to return true if the keys are of equal value and false otherwise. .Pp The .Fa allocator argument is a pointer to a structure containing .Fa malloc and .Fa free function pointers which respectively define the memory allocation and destruction functions to be used by the hash set being initialized. .Pp The argument .Fa capacity represents the initial number of keys the hash set is expected to contain. This argument is simply a hint and the underlying implementation is free to allocate more or less memory than necessary to contain the number of entries .Fa capacity specifies. .Pp The argument .Fa seed specifies the initial seed used by the underlying hash function. The user is free to choose a value of their choice. .Sh RETURN VALUES Upon successful completion .Fn ck_rhs_init returns a value of .Dv true and otherwise returns a value of .Dv false to indicate an error. .Sh ERRORS .Bl -tag -width Er .Pp The behavior of .Fn ck_rhs_init is undefined if .Fa hs is not a pointer to a .Tn ck_rhs_t object. .El .Sh SEE ALSO .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_iterator_init ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_ITERATOR_INIT 3 .Sh NAME .Nm ck_rhs_iterator_init .Nd initialize hash set iterator .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Pp .Dv ck_rhs_iterator_t iterator = CK_RHS_ITERATOR_INITIALIZER .Pp .Ft void .Fn ck_rhs_iterator_init "ck_rhs_iterator_t *iterator" .Sh DESCRIPTION The .Fn ck_rhs_iterator_init 3 function will initialize the object pointed to by the .Fa iterator argument. Alternatively, an iterator may be statically initialized by assigning it to the CK_RHS_ITERATOR_INITIALIZER value. .Pp An iterator is used to iterate through hash set entries with the .Xr ck_rhs_next 3 function. .Sh RETURN VALUES .Fn ck_rhs_iterator_init 3 has no return value. .Sh ERRORS This function will not fail. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_move ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd July 18, 2013 .Dt CK_RHS_MOVE 3 .Sh NAME .Nm ck_rhs_move .Nd move one from hash set to another .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_move "ck_rhs_t *destination" "ck_rhs_t *source" "ck_rhs_hash_cb_t *hash_cb" "ck_rhs_compare_cb_t *compare_cb" "struct ck_malloc *m" .Sh DESCRIPTION The .Fn ck_rhs_move 3 function will initialize .Fa source from .Fa destination . The hash function is set to .Fa hash_cb , comparison function to .Fa compare_cb and the allocator callbacks to .Fa m . Further modifications to .Fa source will result in undefined behavior. Concurrent .Xr ck_rhs_get 3 and .Xr ck_rhs_fas 3 operations to .Fa source are legal until the next write operation to .Fa destination . .Pp This operation moves ownership from one hash set object to another and re-assigns callback functions to developer-specified values. This allows for dynamic configuration of allocation callbacks and is necessary for use-cases involving executable code which may be unmapped underneath the hash set. .Sh RETURN VALUES Upon successful completion .Fn ck_rhs_move 3 returns true and otherwise returns false to indicate an error. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_next ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_NEXT 3 .Sh NAME .Nm ck_rhs_next .Nd iterate to next entry in hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_next "ck_rhs_t *hs" "ck_rhs_iterator_t *iterator" "void **entry" .Sh DESCRIPTION The .Fn ck_rhs_next 3 function will increment the iterator object pointed to by .Fa iterator to point to the next non-empty hash set entry. If .Fn ck_rhs_next 3 returns true then the pointer pointed to by .Fa entry is initialized to the current hash set key pointed to by the .Fa iterator object. .Pp It is expected that .Fa iterator has been initialized using the .Xr ck_rhs_iterator_init 3 function or statically initialized using CK_RHS_ITERATOR_INITIALIZER. .Sh RETURN VALUES If .Fn ck_rhs_next 3 returns true then the object pointed to by .Fa entry points to a valid hash set key. If .Fn ck_rhs_next 3 returns false then the value of the object pointed to by .Fa entry is undefined. .Sh ERRORS Behavior is undefined if .Fa iterator or .Fa hs are uninitialized. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_put ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_PUT 3 .Sh NAME .Nm ck_rhs_put .Nd store unique key into a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_put "ck_rhs_t *hs" "unsigned long hash" "const void *key" .Sh DESCRIPTION The .Fn ck_rhs_put 3 function will store the key specified by the .Fa key argument in the hash set pointed to by the .Fa hs argument. The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which was previously generated using the .Xr CK_RHS_HASH 3 macro). .Pp If the call to .Fn ck_rhs_put 3 was successful then the key specified by .Fa key was successfully stored in the hash set pointed to by .Fa hs . The function will fail if a key with an equivalent value to .Fa key is already present in the hash set. For replacement semantics, please see the .Xr ck_rhs_set 3 function. .Sh RETURN VALUES Upon successful completion, .Fn ck_rhs_put 3 returns true and otherwise returns false on failure. .Sh ERRORS Behavior is undefined if .Fa key or .Fa hs are uninitialized. The function will also return false if the hash set could not be enlarged to accomodate key insertion. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_put_unique ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd December 7, 2013 .Dt CK_RHS_PUT_UNIQUE 3 .Sh NAME .Nm ck_rhs_put_unique .Nd unconditionally store unique key into a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_put_unique "ck_rhs_t *hs" "unsigned long hash" "const void *key" .Sh DESCRIPTION The .Fn ck_rhs_put_unique 3 function will store the key specified by the .Fa key argument in the hash set pointed to by the .Fa hs argument. The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which was previously generated using the .Xr CK_RHS_HASH 3 macro). .Pp If the call to .Fn ck_rhs_put 3 was successful then the key specified by .Fa key was successfully stored in the hash set pointed to by .Fa hs . The function will cause undefined behavior if a key with an equivalent value is already present in the hash set. For replacement semantics, please see the .Xr ck_rhs_set 3 function. .Sh RETURN VALUES Upon successful completion, .Fn ck_rhs_put_unique 3 returns true and otherwise returns false on failure. .Sh ERRORS Behavior is undefined if .Fa key or .Fa hs are uninitialized. The function will also return false if the hash set could not be enlarged to accomodate key insertion. The function will result in undefined behavior if called for an already inserted key value. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_rebuild ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd December 7, 2013 .Dt CK_RHS_REBUILD 3 .Sh NAME .Nm ck_rhs_rebuild .Nd rebuild a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_rebuild "ck_rhs_t *hs" .Sh DESCRIPTION The .Fn ck_rhs_rebuild 3 function will regenerate the hash set pointed to by .Fa hs . This has the side-effect of pruning degradatory side-effects of workloads that are delete heavy. The regenerated hash set should have shorter probe sequences on average. This operation will require a significant amount of memory and is free to allocate a duplicate hash set in the rebuild process. .Sh RETURN VALUES Upon successful completion, .Fn ck_rhs_rebuild 3 returns true and otherwise returns false on failure. .Sh ERRORS This function will only return false if there are internal memory allocation failures. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_remove ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_REMOVE 3 .Sh NAME .Nm ck_rhs_remove .Nd remove key from a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft void * .Fn ck_rhs_remove "ck_rhs_t *hs" "unsigned long hash" "const void *key" .Sh DESCRIPTION The .Fn ck_rhs_remove 3 function will attempt to remove the key specified by the .Fa key argument in the hash set pointed to by the .Fa hs argument. The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which was previously generated using the .Xr CK_RHS_HASH 3 macro). .Pp If the call to .Fn ck_rhs_remove 3 was successful then the key contained in the hash set is returned. If the key was not a member of the hash set then .Dv NULL is returned. .Sh RETURN VALUES Upon successful completion, .Fn ck_rhs_remove 3 returns a pointer to a key and otherwise returns .Dv NULL on failure. .Sh ERRORS Behavior is undefined if .Fa key or .Fa hs are uninitialized. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_reset ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_RESET 3 .Sh NAME .Nm ck_rhs_reset .Nd remove all keys from a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_reset "ck_rhs_t *hs" .Sh DESCRIPTION The .Fn ck_rhs_reset 3 function will remove all keys stored in the hash set pointed to by the .Fa hs argument. .Sh RETURN VALUES If successful, .Fn ck_rhs_reset 3 will return true and will otherwise return false on failure. This function will only fail if a replacement hash set could not be allocated internally. .Sh ERRORS Behavior is undefined if .Fa hs is uninitialized. Behavior is undefined if this function is called by a non-writer thread. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_reset_size ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 5, 2013 .Dt CK_RHS_RESET_SIZE 3 .Sh NAME .Nm ck_rhs_reset_size .Nd remove all keys from a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_reset_size "ck_rhs_t *hs" "unsigned long size" .Sh DESCRIPTION The .Fn ck_rhs_reset_size 3 function will remove all keys stored in the hash set pointed to by the .Fa hs argument and create a new generation of the hash set that is preallocated for .Fa size entries. .Sh RETURN VALUES If successful, .Fn ck_rhs_reset_size 3 will return true and will otherwise return false on failure. This function will only fail if a replacement hash set could not be allocated internally. .Sh ERRORS Behavior is undefined if .Fa hs is uninitialized. Behavior is undefined if this function is called by a non-writer thread. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_set ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_SET 3 .Sh NAME .Nm ck_rhs_set .Nd store key into a hash set .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_set "ck_rhs_t *hs" "unsigned long hash" "const void *key" "void **previous" .Sh DESCRIPTION The .Fn ck_rhs_set 3 function will store the key specified by the .Fa key argument in the hash set pointed to by the .Fa hs argument. The key specified by .Fa key is expected to have the hash value specified by the .Fa hash argument (which was previously generated using the .Xr CK_RHS_HASH 3 macro). .Pp If the call to .Fn ck_rhs_set 3 was successful then the key specified by .Fa key was successfully stored in the hash set pointed to by .Fa hs . If the key already exists in the hash set, then it is replaced by .Fa key and the previous value is stored into the void pointer pointed to by the .Fa previous argument. If previous is set to .Dv NULL then .Fa key was not a replacement for an existing entry in the hash set. .Sh RETURN VALUES Upon successful completion, .Fn ck_rhs_set 3 returns true and otherwise returns false on failure. .Sh ERRORS Behavior is undefined if .Fa key or .Fa hs are uninitialized. The function will also return false if the hash set could not be enlarged to accomodate key insertion. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 , .Xr ck_rhs_stat 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_set_load_factor ================================================ .\" .\" Copyright 2015 Olivier Houchard. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd May 16, 2015 .Dt CK_RHS_SET_LOAD_FACTOR 3 .Sh NAME .Nm ck_rhs_set_load_factor .Nd change the hash set load factor .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft bool .Fn ck_rhs_set_load_factor "ck_rhs_t *hs" "unsigned int load_factor" .Sh DESCRIPTION The .Fn ck_rhs_set_load_factor 3 function will change the load factor of the hash set. The hash set will grow if it is load_factor% filled. .Ed .Sh RETURN VALUES .Fn ck_rhs_set_load_factor 3 returns true on success, or false if either the load factor is invalid (0 or > 100), or if growing was required, but failed. .Sh ERRORS Behavior is undefined if .Fa hs is uninitialized. Behavior is undefined if this function is called by a non-writer thread. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rhs_stat ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd September 17, 2012 .Dt CK_RHS_STAT 3 .Sh NAME .Nm ck_rhs_stat .Nd get hash set status .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rhs.h .Ft void .Fn ck_rhs_stat "ck_rhs_t *hs" "struct ck_rhs_stat *st" .Sh DESCRIPTION The .Fn ck_rhs_stat 3 function will store various hash set statistics in the object pointed to by .Fa st . The ck_rhs_stat structure is defined as follows: .Bd -literal -offset indent struct ck_rhs_stat { unsigned long n_entries; /* Current number of keys in hash set. */ unsigned int probe_maximum; /* Longest read-side probe sequence. */ }; .Ed .Sh RETURN VALUES .Fn ck_rhs_stat 3 has no return value. .Sh ERRORS Behavior is undefined if .Fa hs is uninitialized. Behavior is undefined if this function is called by a non-writer thread. .Sh SEE ALSO .Xr ck_rhs_init 3 , .Xr ck_rhs_move 3 , .Xr ck_rhs_destroy 3 , .Xr CK_RHS_HASH 3 , .Xr ck_rhs_iterator_init 3 , .Xr ck_rhs_next 3 , .Xr ck_rhs_get 3 , .Xr ck_rhs_put 3 , .Xr ck_rhs_put_unique 3 , .Xr ck_rhs_set 3 , .Xr ck_rhs_fas 3 , .Xr ck_rhs_remove 3 , .Xr ck_rhs_grow 3 , .Xr ck_rhs_gc 3 , .Xr ck_rhs_rebuild 3 , .Xr ck_rhs_count 3 , .Xr ck_rhs_reset 3 , .Xr ck_rhs_reset_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ring_capacity ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 20, 2013 .Dt CK_RING_CAPACITY 3 .Sh NAME .Nm ck_ring_capacity .Nd returns number of pointer slots in bounded FIFO .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ring.h .Ft unsigned int .Fn ck_ring_capacity "ck_ring_t *ring" .Sh DESCRIPTION The .Fn ck_ring_capacity 3 function returns the number of pointers that can be held in the buffer pointed to by .Fa ring . Note that a ring can only hold .Fn ck_ring_capacity 3 minus one entries at a time. .Sh SEE ALSO .Xr ck_ring_init 3 , .Xr ck_ring_enqueue_spmc 3 , .Xr ck_ring_dequeue_spmc 3 , .Xr ck_ring_trydequeue_spmc 3 , .Xr ck_ring_enqueue_spmc_size 3 , .Xr ck_ring_dequeue_spsc 3 , .Xr ck_ring_enqueue_spsc 3 , .Xr ck_ring_enqueue_spsc_size 3 , .Xr ck_ring_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ring_dequeue_spmc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 20, 2013 .Dt CK_RING_DEQUEUE_SPMC 3 .Sh NAME .Nm ck_ring_dequeue_spmc .Nd dequeue pointer from bounded FIFO .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ring.h .Ft bool .Fn ck_ring_dequeue_spmc "ck_ring_t *ring" "ck_ring_buffer_t *buffer" "void *result" .Sh DESCRIPTION The .Fn ck_ring_dequeue_spmc 3 function dequeues a pointer from the bounded buffer pointed to by .Fa ring in FIFO fashion. The pointer is stored in the pointer pointed to by .Fa result . The buffer pointed to by .Fa buffer must be unique to .Fa ring . The decoupling of the ring from the buffer serves to address use-cases involving multiple address spaces and DMA, among others. If you are on non-POSIX platforms or wish for strict compliance with C, then it is recommended to pass a pointer of type void ** for .Fa result . This function is safe to call without locking for UINT_MAX concurrent invocations of .Fn ck_ring_dequeue_spmc 3 or .Fn ck_ring_trydequeue_spmc 3 and up to one concurrent .Fn ck_ring_enqueue_spmc 3 or .Fn ck_ring_tryenqueue_spmc 3 invocation. This function provides lock-free progress guarantees. .Sh EXAMPLE .Bd -literal -offset indent #include /* This ring was previously initialized with ck_ring_init. */ ck_ring_t ring; /* The ring was initialized for 1023 elements. */ ck_ring_buffer_t buffer[1024]; void dequeue(void) { void *result; /* Dequeue from ring until it is empty. */ while (ck_ring_dequeue_spmc(&ring, &buffer, &result) == true) { /* * Results contains the oldest pointer in ring * since the dequeue operation returned true. */ operation(result); } /* An empty ring was encountered, leave. */ return; } .Ed .Sh RETURN VALUES The function returns true if the buffer was non-empty. The result of the dequeue operation is stored in the value pointed to by .Fa result . The function will return false if the buffer was empty and the value in .Fa result will be undefined. .Sh SEE ALSO .Xr ck_ring_init 3 , .Xr ck_ring_trydequeue_spmc 3 , .Xr ck_ring_enqueue_spmc 3 , .Xr ck_ring_enqueue_spmc_size 3 , .Xr ck_ring_dequeue_spsc 3 , .Xr ck_ring_enqueue_spsc 3 , .Xr ck_ring_enqueue_spsc_size 3 , .Xr ck_ring_capacity 3 , .Xr ck_ring_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ring_dequeue_spsc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 20, 2013 .Dt CK_RING_DEQUEUE_SPSC 3 .Sh NAME .Nm ck_ring_dequeue_spsc .Nd dequeue pointer from bounded FIFO .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ring.h .Ft bool .Fn ck_ring_dequeue_spsc "ck_ring_t *ring" "ck_ring_buffer_t *buffer" "void *result" .Sh DESCRIPTION The .Fn ck_ring_dequeue_spsc 3 function dequeues a pointer from the bounded buffer pointed to by .Fa ring in FIFO fashion. The pointer is stored in the pointer pointed to by .Fa result . The buffer pointed to by .Fa buffer must be unique to .Fa ring and point to an array of ck_ring_buffer_t of sufficient length (according to the power-of-2 elements in the buffer). The decoupling of the ring from the buffer serves to address use-cases involving multiple address spaces and DMA, among others. If you are on non-POSIX platforms or wish for strict compliance with C, then it is recommended to pass a pointer of type void ** for .Fa result . This function is safe to call without locking for one concurrent invocation of .Fn ck_ring_dequeue_spsc 3 and up to one concurrent .Fn ck_ring_enqueue_spsc 3 invocation. This function provides wait-free progress guarantees. .Sh EXAMPLE .Bd -literal -offset indent #include /* This ring was previously initialized with ck_ring_init. */ ck_ring_t ring; /* The ring was initialized for 1023 elements. */ ck_ring_buffer_t buffer[1024]; void dequeue(void) { void *result; /* Dequeue from ring until it is empty. */ while (ck_ring_dequeue_spsc(&ring, &buffer, &result) == true) { /* * Results contains the oldest pointer in ring * since the dequeue operation returned true. */ operation(result); } /* An empty ring was encountered, leave. */ return; } .Ed .Sh RETURN VALUES The function returns true if the buffer was non-empty. The result of the dequeue operation is stored in the value pointed to by .Fa result . The function will return false if the buffer was empty and the value in .Fa result will be undefined. .Sh SEE ALSO .Xr ck_ring_init 3 , .Xr ck_ring_trydequeue_spmc 3 , .Xr ck_ring_enqueue_spmc 3 , .Xr ck_ring_enqueue_spmc_size 3 , .Xr ck_ring_dequeue_spmc 3 , .Xr ck_ring_enqueue_spsc 3 , .Xr ck_ring_enqueue_spsc_size 3 , .Xr ck_ring_capacity 3 , .Xr ck_ring_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ring_enqueue_spmc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 20, 2013 .Dt CK_RING_ENQUEUE_SPMC 3 .Sh NAME .Nm ck_ring_enqueue_spmc .Nd enqueue pointer into bounded FIFO .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ring.h .Ft bool .Fn ck_ring_enqueue_spmc "ck_ring_t *ring" "ck_ring_buffer_t *buffer" "void *entry" .Sh DESCRIPTION The .Fn ck_ring_enqueue_spmc 3 function enqueues the pointer .Fa entry into the bounded buffer pointed to by .Fa ring in FIFO fashion. The buffer pointed to by .Fa buffer must be unique to .Fa ring and point to an array of ck_ring_buffer_t of sufficient length (according to the power-of-2 elements in the buffer). The decoupling of the ring from the buffer serves to address use-cases involving multiple address spaces and DMA, among others. If you are on non-POSIX platforms or wish for strict compliance with C, then it is recommended to pass a pointer of type void ** for .Fa entry . This function is safe to call without locking for UINT_MAX concurrent invocations of .Fn ck_ring_dequeue_spmc 3 or .Fn ck_ring_trydequeue_spmc 3 . This function provides wait-free progress guarantees for one active invocation. .Sh EXAMPLE .Bd -literal -offset indent #include /* This ring was previously initialized with ck_ring_init. */ ck_ring_t ring; /* The ring was initialized for 1023 elements. */ ck_ring_buffer_t buffer[1024]; void enqueue(void) { void *entry = some_object; /* Attempt to enqueue pointer to some_object into buffer. */ if (ck_ring_enqueue_spmc(&ring, &buffer, &entry) == false) { /* * The buffer was full and the enqueue operation * has failed. */ return; } /* Enqueue operation completed successfully. */ return; } .Ed .Sh RETURN VALUES The function returns true if the value of .Fa entry was successfully enqueued into .Fa ring . The function will return false if the value of .Fa entry could not be enqueued which only occurs if .Fa ring was full. .Sh SEE ALSO .Xr ck_ring_init 3 , .Xr ck_ring_dequeue_spmc 3 , .Xr ck_ring_trydequeue_spmc 3 , .Xr ck_ring_enqueue_spmc_size 3 , .Xr ck_ring_dequeue_spsc 3 , .Xr ck_ring_enqueue_spsc 3 , .Xr ck_ring_enqueue_spsc_size 3 , .Xr ck_ring_capacity 3 , .Xr ck_ring_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ring_enqueue_spmc_size ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 20, 2013 .Dt CK_RING_ENQUEUE_SPMC_SIZE 3 .Sh NAME .Nm ck_ring_enqueue_spmc_size .Nd enqueue pointer into bounded FIFO and return size of buffer .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ring.h .Ft bool .Fn ck_ring_enqueue_spmc_size "ck_ring_t *ring" "ck_ring_buffer_t *buffer" "void *entry" "unsigned int *length" .Sh DESCRIPTION The .Fn ck_ring_enqueue_spmc 3 function enqueues the pointer .Fa entry into the bounded buffer pointed to by .Fa ring in FIFO fashion. The buffer pointed to by .Fa buffer must be unique to .Fa ring and point to an array of ck_ring_buffer_t of sufficient length (according to the power-of-2 elements in the buffer). The decoupling of the ring from the buffer serves to address use-cases involving multiple address spaces and DMA, among others. If you are on non-POSIX platforms or wish for strict compliance with C, then it is recommended to pass a pointer of type void ** for .Fa entry . This function is safe to call without locking for UINT_MAX concurrent invocations of .Fn ck_ring_dequeue_spmc 3 or .Fn ck_ring_trydequeue_spmc 3 . This function provides wait-free progress guarantees for one active invocation. .Sh EXAMPLE .Bd -literal -offset indent #include /* This ring was previously initialized with ck_ring_init. */ ck_ring_t ring; /* The ring was initialized for 1023 elements. */ ck_ring_buffer_t buffer[1024]; void enqueue(void) { void *entry = some_object; unsigned int length; /* Attempt to enqueue pointer to some_object into buffer. */ if (ck_ring_enqueue_spmc_size(&ring, &buffer, &entry, &length) == false) { /* * The buffer was full and the enqueue operation * has failed. */ return; } /* * If entry was the 101st or greater pointer in the buffer, * do something. */ if (length > 100) { do_something; } return; } .Ed .Sh RETURN VALUES The function returns true if the value of .Fa entry was successfully enqueued into .Fa ring . The function will return false if the value of .Fa entry could not be enqueued which only occurs if .Fa ring was full. The number of entries in the buffer with respect to the point in time that .Fa entry is enqueued is stored in the integer pointed to by .Fa length . .Sh SEE ALSO .Xr ck_ring_init 3 , .Xr ck_ring_dequeue_spmc 3 , .Xr ck_ring_trydequeue_spmc 3 , .Xr ck_ring_enqueue_spmc 3 , .Xr ck_ring_dequeue_spsc 3 , .Xr ck_ring_enqueue_spsc 3 , .Xr ck_ring_enqueue_spsc_size 3 , .Xr ck_ring_capacity 3 , .Xr ck_ring_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ring_enqueue_spsc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 20, 2013 .Dt CK_RING_ENQUEUE_SPSC 3 .Sh NAME .Nm ck_ring_enqueue_spsc .Nd enqueue pointer into bounded FIFO .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ring.h .Ft bool .Fn ck_ring_enqueue_spsc "ck_ring_t *ring" "ck_ring_buffer_t *buffer" "void *entry" .Sh DESCRIPTION The .Fn ck_ring_enqueue_spsc 3 function enqueues the pointer .Fa entry into the bounded buffer pointed to by .Fa ring in FIFO fashion. The buffer pointed to by .Fa buffer must be unique to .Fa ring and point to an array of ck_ring_buffer_t of sufficient length (according to the power-of-2 elements in the buffer). The decoupling of the ring from the buffer serves to address use-cases involving multiple address spaces and DMA, among others. If you are on non-POSIX platforms or wish for strict compliance with C, then it is recommended to pass a pointer of type void ** for .Fa entry . This function is safe to call without locking for up to one concurrent invocation of .Fn ck_ring_dequeue_spsc 3 . This function provides wait-free progress guarantees. .Sh EXAMPLE .Bd -literal -offset indent #include /* This ring was previously initialized with ck_ring_init. */ ck_ring_t ring; /* The ring was initialized for 1023 elements. */ ck_ring_buffer_t buffer[1024]; void enqueue(void) { void *entry = some_object; /* Attempt to enqueue pointer to some_object into buffer. */ if (ck_ring_enqueue_spsc(&ring, &buffer, &entry) == false) { /* * The buffer was full and the enqueue operation * has failed. */ return; } /* Enqueue operation completed successfully. */ return; } .Ed .Sh RETURN VALUES The function returns true if the value of .Fa entry was successfully enqueued into .Fa ring . The function will return false if the value of .Fa entry could not be enqueued which only occurs if .Fa ring was full. .Sh SEE ALSO .Xr ck_ring_init 3 , .Xr ck_ring_dequeue_spmc 3 , .Xr ck_ring_trydequeue_spmc 3 , .Xr ck_ring_enqueue_spmc 3 , .Xr ck_ring_enqueue_spmc_size 3 , .Xr ck_ring_dequeue_spsc 3 , .Xr ck_ring_enqueue_spsc_size 3 , .Xr ck_ring_capacity 3 , .Xr ck_ring_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ring_enqueue_spsc_size ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 20, 2013 .Dt CK_RING_ENQUEUE_SPSC_SIZE 3 .Sh NAME .Nm ck_ring_enqueue_spsc_size .Nd enqueue pointer into bounded FIFO and return size of buffer .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ring.h .Ft bool .Fn ck_ring_enqueue_spsc_size "ck_ring_t *ring" "ck_ring_buffer_t *buffer" "void *entry" "unsigned int *size" .Sh DESCRIPTION The .Fn ck_ring_enqueue_spsc_size 3 function enqueues the pointer .Fa entry into the bounded buffer pointed to by .Fa ring in FIFO fashion. The buffer pointed to by .Fa buffer must be unique to .Fa ring and point to an array of ck_ring_buffer_t of sufficient length (according to the power-of-2 elements in the buffer). The decoupling of the ring from the buffer serves to address use-cases involving multiple address spaces and DMA, among others. If you are on non-POSIX platforms or wish for strict compliance with C, then it is recommended to pass a pointer of type void ** for .Fa entry . This function is safe to call without locking for up to one concurrent invocation of .Fn ck_ring_dequeue_spsc 3 . This function provides wait-free progress guarantees. .Sh EXAMPLE .Bd -literal -offset indent #include /* This ring was previously initialized with ck_ring_init. */ ck_ring_t ring; /* The ring was initialized for 1023 elements. */ ck_ring_buffer_t buffer[1024]; void enqueue(void) { void *entry = some_object; unsigned int length; /* Attempt to enqueue pointer to some_object into buffer. */ if (ck_ring_enqueue_spsc(&ring, &buffer, &entry, &length) == false) { /* * The buffer was full and the enqueue operation * has failed. */ return; } /* * If buffer length was 100 items or more at the time entry was * enqueued, do something. */ if (length > 100) { do_something; } return; } .Ed .Sh RETURN VALUES The function returns true if the value of .Fa entry was successfully enqueued into .Fa ring . This function will return the number of items in .Fa ring with respect to the linearization point (the point in item that .Fa entry is enqueued). The function will return false if the value of .Fa entry could not be enqueued which only occurs if .Fa ring was full. .Sh SEE ALSO .Xr ck_ring_init 3 , .Xr ck_ring_dequeue_spmc 3 , .Xr ck_ring_trydequeue_spmc 3 , .Xr ck_ring_enqueue_spmc 3 , .Xr ck_ring_enqueue_spmc_size 3 , .Xr ck_ring_dequeue_spsc 3 , .Xr ck_ring_enqueue_spsc 3 , .Xr ck_ring_capacity 3 , .Xr ck_ring_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ring_init ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 20, 2013 .Dt CK_RING_INIT 3 .Sh NAME .Nm ck_ring_init .Nd initialize bounded FIFO .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ring.h .Ft void .Fn ck_ring_init "ck_ring_t *ring" "unsigned int size" .Sh DESCRIPTION The .Fn ck_ring_init function initializes a bounded FIFO buffer pointed to by .Fa ring for the storage of up to .Fa size number of pointers. The .Fa size argument must be a power-of-two greater than or equal to 4. .Sh RETURN VALUES This function has no return value. .Sh SEE ALSO .Xr ck_ring_dequeue_spmc 3 , .Xr ck_ring_trydequeue_spmc 3 , .Xr ck_ring_enqueue_spmc 3 , .Xr ck_ring_enqueue_spmc_size 3 , .Xr ck_ring_dequeue_spsc 3 , .Xr ck_ring_enqueue_spsc 3 , .Xr ck_ring_enqueue_spsc_size 3 , .Xr ck_ring_capacity 3 , .Xr ck_ring_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ring_size ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 20, 2013 .Dt CK_RING_SIZE 3 .Sh NAME .Nm ck_ring_size .Nd return number of pointers enqueued in bounded FIFO .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ring.h .Ft unsigned int .Fn ck_ring_size "ck_ring_t *ring" .Sh DESCRIPTION The .Fn ck_ring_size 3 function returns the number of pointers currently enqueued in the buffer pointed to by .Fa ring . .Sh SEE ALSO .Xr ck_ring_init 3 , .Xr ck_ring_enqueue_spmc 3 , .Xr ck_ring_dequeue_spmc 3 , .Xr ck_ring_trydequeue_spmc 3 , .Xr ck_ring_enqueue_spmc_size 3 , .Xr ck_ring_dequeue_spsc 3 , .Xr ck_ring_enqueue_spsc 3 , .Xr ck_ring_enqueue_spsc_size 3 , .Xr ck_ring_capacity 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_ring_trydequeue_spmc ================================================ .\" .\" Copyright 2012-2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 20, 2013 .Dt CK_RING_TRYDEQUEUE_SPMC 3 .Sh NAME .Nm ck_ring_trydequeue_spmc .Nd dequeue from bounded FIFO and allow for spurious failure .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_ring.h .Ft bool .Fn ck_ring_trydequeue_spmc "ck_ring_t *ring" "ck_ring_buffer_t *buffer" "void *result" .Sh DESCRIPTION The .Fn ck_ring_trydequeue_spmc 3 function attempts to dequeue a pointer from the bounded buffer pointed to by .Fa ring in FIFO fashion. The pointer is stored in the pointer pointed to by .Fa result . The buffer pointed to by .Fa buffer must be unique to .Fa ring and point to an array of ck_ring_buffer_t of sufficient length (according to the power-of-2 elements in the buffer). The decoupling of the ring from the buffer serves to address use-cases involving multiple address spaces and DMA, among others. If you are on non-POSIX platforms or wish for strict compliance with C, then it is recommended to pass a pointer of type void ** for .Fa result . This function is safe to call without locking for UINT_MAX concurrent .Fn ck_ring_dequeue_spmc 3 or .Fn ck_ring_trydequeue_spmc 3 invocations and up to one concurrent .Fn ck_ring_enqueue_spmc 3 or .Fn ck_ring_tryenqueue_spmc 3 invocation. This operation will always complete in a bounded number of steps. It is possible for the function to return false even if .Fa ring is non-empty. This .Sh EXAMPLE .Bd -literal -offset indent #include /* This ring was previously initialized with ck_ring_init. */ ck_ring_t ring; /* The ring was initialized for 1023 elements. */ ck_ring_buffer_t buffer[1024]; void dequeue(void) { void *result; /* Dequeue from ring until contention is actively observed. */ while (ck_ring_trydequeue_spmc(&ring, &buffer, &result) == true) { /* * Results contains the oldest pointer in ring * since the dequeue operation returned true. */ operation(result); } /* An empty ring was encountered, leave. */ return; } .Ed .Sh RETURN VALUES The function returns true if the dequeue operation completely successfully in a bounded number of steps. The result of the dequeue operation is stored in the value pointed to by .Fa result . Otherwise, the function will return false if the buffer was empty or if the operation could not be completed in a bounded number of steps. If the function returns false, then the contents of .Fa result are undefined. .Sh SEE ALSO .Xr ck_ring_init 3 , .Xr ck_ring_dequeue_spmc 3 , .Xr ck_ring_enqueue_spmc 3 , .Xr ck_ring_enqueue_spmc_size 3 , .Xr ck_ring_dequeue_spsc 3 , .Xr ck_ring_enqueue_spsc 3 , .Xr ck_ring_enqueue_spsc_size 3 , .Xr ck_ring_capacity 3 , .Xr ck_ring_size 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rwcohort ================================================ .\" .\" Copyright 2013 Brendon Scheinman. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 23, 2013. .Dt ck_rwcohort 3 .Sh NAME .Nm ck_rwcohort .Nd generalized interface for reader-writer locks using cohort locks .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rwcohort.h In each of the following macros, "STRATEGY" should be replaced with either "NEUTRAL", "RP", or "WP" depending on which locking strategy the user prefers. RP and WP represent reader preference and writer preference, respectively, while NEUTRAL represents a strategy neutral to reads vs. writes. .Fn CK_RWCOHORT_STRATEGY_PROTOTYPE "COHORT_NAME cohort_name" .Fn CK_RWCOHORT_STRATEGY_NAME "COHORT_NAME cohort_name" .Fn CK_RWCOHORT_STRATEGY_INSTANCE "COHORT_NAME cohort_name" .Fn CK_RWCOHORT_STRATEGY_INIT "COHORT_NAME cohort_name" "RWCOHORT lock" "unsigned int wait_limit" Note: the wait_limit argument should be omitted for locks using the neutral strategy .Fn CK_RWCOHORT_STRATEGY_READ_LOCK "COHORT_NAME cohort_name" "RWCOHORT lock" "COHORT cohort" \ "void *global_context" "void *local_context" .Fn CK_RWCOHORT_STRATEGY_READ_UNLOCK "COHORT_NAME cohort_name" "RWCOHORT lock" "COHORT cohort" \ "void *global_context" "void *local_context" .Fn CK_RWCOHORT_STRATEGY_WRITE_LOCK "COHORT_NAME cohort_name" "RWCOHORT lock" "COHORT cohort" \ "void *global_context" "void *local_context" .Fn CK_RWCOHORT_STRATEGY_WRITE_UNLOCK "COHORT_NAME cohort_name" "RWCOHORT lock" "COHORT cohort" \ "void *global_context" "void *local_context" .Pp Arguments of type RWCOHORT must be pointers to structs defined using the .Xr CK_RWCOHORT_STRATEGY_PROTOTYPE 3 macro with the same strategy and cohort name as the current call. .Pp Arguments of type COHORT must be pointers to structs defined using the .Xr CK_COHORT_PROTOTYPE 3 macro. .Sh DESCRIPTION ck_rwcohort.h provides an interface for defining reader-writer locks that use cohort locks internally to increase performance on NUMA architectures. See .Xr ck_cohort 3 for more information about cohort locks. .Pp Before using a reader-writer cohort lock, the user must define a cohort type using either the .Xr CK_COHORT_PROTOTYPE 3 or the .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 macros, and define a reader-writer lock type using the .Xr CK_RWCOHORT_PROTOTYPE 3 macro. .Pp .Sh EXAMPLE .Bd -literal -offset indent #include #include #include #include #include #include /* Create cohort methods with signatures that match the required signature */ static void ck_spinlock_lock_with_context(ck_spinlock_t *lock, void *context) { (void)context; ck_spinlock_lock(lock); return; } static void ck_spinlock_unlock_with_context(ck_spinlock_t *lock, void *context) { (void)context; ck_spinlock_unlock(lock); return; } static bool ck_spinlock_locked_with_context(ck_spinlock_t *lock, void *context) { (void)context; return ck_spinlock_locked(lock); } /* * define a cohort type named "test_cohort" that will use * the above methods for both its global and local locks */ CK_COHORT_PROTOTYPE(test_cohort, ck_spinlock_lock_with_context, ck_spinlock_unlock_with_context, ck_spinlock_locked_with_context, ck_spinlock_lock_with_context, ck_spinlock_unlock_with_context, ck_spinlock_locked_with_context) /* define a reader-writer type using the same cohort type */ CK_RWCOHORT_WP_PROTOTYPE(test_cohort) static ck_spinlock_t global_lock = CK_SPINLOCK_INITIALIZER; static CK_COHORT_INSTANCE(test_cohort) *cohorts; static CK_RWCOHORT_WP_INSTANCE(test_cohort) rw_cohort = CK_RWCOHORT_WP_INITIALIZER; static unsigned int ready; static void * function(void *context) { CK_COHORT_INSTANCE(test_cohort) *cohort = context; while (ck_pr_load_uint(&ready) == 0); while (ck_pr_load_uint(&ready) > 0) { /* * acquire the cohort lock before performing critical section. * note that we pass NULL for both the global and local context * arguments because neither the lock nor unlock functions * will use them. */ CK_COHORT_LOCK(test_cohort, cohort, NULL, NULL); /* perform critical section */ /* relinquish cohort lock */ CK_COHORT_UNLOCK(test_cohort, cohort, NULL, NULL); } return NULL; } int main(void) { unsigned int nthr = 4; unsigned int n_cohorts = 2; unsigned int i; /* allocate 2 cohorts of the defined type */ CK_COHORT_INSTANCE(test_cohort) *cohorts = calloc(n_cohorts, sizeof(CK_COHORT_INSTANCE(test_cohort))); /* create local locks to use with each cohort */ ck_spinlock_t *local_locks = calloc(n_cohorts, sizeof(ck_spinlock_t)); pthread_t *threads = calloc(nthr, sizeof(pthread_t)); /* initialize each of the cohorts before using them */ for (i = 0 ; i < n_cohorts ; ++i) { CK_COHORT_INIT(test_cohort, cohorts + i, &global_lock, local_locks + i, CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT); } /* start each thread and assign cohorts equally */ for (i = 0 ; i < nthr ; ++i) { pthread_create(threads + i, NULL, function, cohorts + (i % n_cohorts)); } ck_pr_store_uint(&ready, 1); sleep(10); ck_pr_store_uint(&ready, 0); for (i = 0 ; i < nthr ; ++i) { pthread_join(threads[i], NULL); } return 0; } .Ed .Sh SEE ALSO .Xr CK_COHORT_PROTOTYPE 3 , .Xr CK_COHORT_TRYLOCK_PROTOTYPE 3 , .Xr CK_COHORT_INSTANCE 3 , .Xr CK_COHORT_INITIALIZER 3 , .Xr CK_COHORT_INIT 3 , .Xr CK_COHORT_LOCK 3 , .Xr CK_COHORT_UNLOCK 3 , .Xr CK_COHORT_LOCKED 3 , .Xr CK_COHORT_TRYLOCK 3 , .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_rwlock ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd July 26, 2013. .Dt ck_rwlock 3 .Sh NAME .Nm ck_rwlock_init , .Nm ck_rwlock_write_lock , .Nm ck_rwlock_write_unlock , .Nm ck_rwlock_write_trylock , .Nm ck_rwlock_write_downgrade , .Nm ck_rwlock_locked_writer , .Nm ck_rwlock_read_lock , .Nm ck_rwlock_read_trylock , .Nm ck_rwlock_read_unlock , .Nm ck_rwlock_locked_reader , .Nm ck_rwlock_recursive_write_lock , .Nm ck_rwlock_recursive_write_trylock , .Nm ck_rwlock_recurisve_write_unlock , .Nm ck_rwlock_recursive_read_lock , .Nm ck_rwlock_recursive_read_trylock , .Nm ck_rwlock_recursive_read_unlock .Nd centralized write-biased reader-writer locks .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_rwlock.h .Pp .Dv ck_rwlock_t lock = CK_RWLOCK_INITIALIZER; .Pp .Ft void .Fn ck_rwlock_init "ck_rwlock_t *lock" .Ft void .Fn ck_rwlock_write_lock "ck_rwlock_t *lock" .Ft void .Fn ck_rwlock_write_unlock "ck_rwlock_t *lock" .Ft bool .Fn ck_rwlock_write_trylock "ck_rwlock_t *lock" .Ft bool .Fn ck_rwlock_write_downgrade "ck_rwlock_t *lock" .Ft bool .Fn ck_rwlock_locked_writer "ck_rwlock_t *lock" .Ft void .Fn ck_rwlock_read_lock "ck_rwlock_t *lock" .Ft bool .Fn ck_rwlock_read_trylock "ck_rwlock_t *lock" .Ft void .Fn ck_rwlock_read_unlock "ck_rwlock_t *lock" .Ft bool .Fn ck_rwlock_locked_reader "ck_rwlock_t *lock" .Pp .Dv ck_rwlock_recursive_t lock = CK_RWLOCK_RECURSIVE_INITIALIZER; .Pp .Ft void .Fn ck_rwlock_recursive_write_lock "ck_rwlock_recursive_t *lock" "unsigned int tid" .Ft bool .Fn ck_rwlock_recursive_write_trylock "ck_rwlock_recursive_t *lock" "unsigned int tid" .Ft void .Fn ck_rwlock_recurisve_write_unlock "ck_rwlock_recursive_t *lock" .Ft void .Fn ck_rwlock_recursive_read_lock "ck_rwlock_recursive_t *lock" .Ft bool .Fn ck_rwlock_recursive_read_trylock "ck_rwlock_recursive_t *lock" .Ft void .Fn ck_rwlock_recursive_read_unlock "ck_rwlock_recursive_t *lock" .Sh DESCRIPTION This is a centralized write-biased reader-writer lock. It requires very little space overhead and has a low latency fast path. Write-side recursion requires usage of ck_rwlock_recursive. Read-side recursion is disallowed. The .Fn ck_rwlock_write_downgrade function degrades the caller's write-side acquisition to a read-side acquisition without forfeit of current critical section. .Sh EXAMPLE .Bd -literal -offset indent #include static ck_rwlock_t lock = CK_RWLOCK_INITIALIZER; static void reader(void) { for (;;) { ck_rwlock_read_lock(&lock); /* Read-side critical section. */ ck_rwlock_read_unlock(&lock); if (ck_rwlock_read_trylock(&lock) == true) { /* Read-side critical section. */ ck_rwlock_read_unlock(&lock); } } return; } static void writer(void) { for (;;) { ck_rwlock_write_lock(&lock); /* Write-side critical section. */ ck_rwlock_write_unlock(&lock); if (ck_rwlock_write_trylock(&lock, 1) == true) { /* Write-side critical section. */ ck_rwlock_write_unlock(&lock); } } return; } .Ed .Sh SEE ALSO .Xr ck_brlock 3 , .Xr ck_elide 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_sequence ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd July 26, 2013. .Dt ck_sequence 3 .Sh NAME .Nm ck_sequence_init , .Nm ck_sequence_read_begin , .Nm ck_sequence_read_retry , .Nm ck_sequence_write_begin , .Nm ck_sequence_write_end .Nd sequence locks .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_sequence.h .Pp .Dv ck_sequence_t seqlock = CK_SEQUENCE_INITIALIZER; .Pp .Ft void .Fn ck_sequence_init "ck_sequence_t *sq" .Ft unsigned int .Fn ck_sequence_read_begin "const ck_sequence_t *sq" .Ft bool .Fn ck_sequence_read_retry "const ck_sequence_t *sq" "unsigned int version" .Ft void .Fn ck_sequence_write_begin "ck_sequence_t *sq" .Ft void .Fn ck_sequence_write_end "ck_sequence_t *sq" .Sh DESCRIPTION It is recommended to use ck_sequence when a small amount of data that cannot be accessed atomically has to be synchronized with readers in a fashion that does not block any writer. Readers are able to execute their read-side critical sections without any atomic operations. A ck_sequence_t must be initialized before use. It may be initialized using either a static initializer (CK_SEQUENCE_INITIALIZER) or using .Fn ck_sequence_init . Before readers attempt to read data that may be concurrently modified they must first save the return value of .Fn ck_sequence_read_begin . While or after a reader has completed copying the data associated with a ck_sequence_t it must pass the earlier return value of .Fn ck_sequence_read_begin to .Fn "ck_sequence_read_retry". If .Fn ck_sequence_read_retry returns true then the copy of data may be inconsistent and the read process must be retried. Writers must rely on their own synchronization primitives. Once a writer has entered its respective critical section, it must call .Fn ck_sequence_write_begin to signal intent to update the data protected by the ck_sequence_t. Before the writer leaves its critical section it must execute .Fn ck_sequence_write_end to indicate that the updates have left respective objects in a consistent state. .Sh EXAMPLE .Bd -literal -offset indent #include #include static struct example { int a; int b; int c; } global; static ck_sequence_t seqlock = CK_SEQUENCE_INITIALIZER; void reader(void) { struct example copy; unsigned int version; /* * Attempt a read of the data structure. If the structure * has been modified between ck_sequence_read_begin and * ck_sequence_read_retry then attempt another read since * the data may be in an inconsistent state. */ do { version = ck_sequence_read_begin(&seqlock); copy = global; } while (ck_sequence_read_retry(&seqlock, version)); /* * The previous may also be expressed using CK_SEQUENCE_READ. * Generally recommend to only use ck_sequence_read_retry * if you would like to detect a conflicting write at some * higher granularity. */ CK_SEQUENCE_READ(&seqlock, &version) { copy = global; } return; } void writer(void) { for (;;) { ck_sequence_write_begin(&seqlock); global.a = rand(); global.b = global.a + global.b; global.c = global.b + global.c; ck_sequence_write_end(&seqlock); } return; } .Ed .Sh SEE ALSO .Xr ck_brlock 3 , .Xr ck_bytelock 3 , .Xr ck_rwlock 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_spinlock ================================================ .\" .\" Copyright 2013 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd July 26, 2013. .Dt ck_spinlock 3 .Sh NAME .Nm ck_spinlock_init , .Nm ck_spinlock_lock , .Nm ck_spinlock_unlock , .Nm ck_spinlock_locked , .Nm ck_spinlock_trylock , .Nm ck_spinlock_anderson_init , .Nm ck_spinlock_anderson_locked , .Nm ck_spinlock_anderson_lock , .Nm ck_spinlock_anderson_unlock , .Nm ck_spinlock_cas_init , .Nm ck_spinlock_cas_locked , .Nm ck_spinlock_cas_lock , .Nm ck_spinlock_cas_lock_eb , .Nm ck_spinlock_cas_trylock , .Nm ck_spinlock_cas_unlock , .Nm ck_spinlock_clh_init , .Nm ck_spinlock_clh_locked , .Nm ck_spinlock_clh_lock , .Nm ck_spinlock_clh_unlock , .Nm ck_spinlock_dec_init , .Nm ck_spinlock_dec_locked , .Nm ck_spinlock_dec_lock , .Nm ck_spinlock_dec_lock_eb , .Nm ck_spinlock_dec_trylock , .Nm ck_spinlock_dec_unlock , .Nm ck_spinlock_fas_init , .Nm ck_spinlock_fas_lock , .Nm ck_spinlock_fas_lock_eb , .Nm ck_spinlock_fas_locked , .Nm ck_spinlock_fas_trylock , .Nm ck_spinlock_fas_unlock , .Nm ck_spinlock_hclh_init , .Nm ck_spinlock_hclh_locked , .Nm ck_spinlock_hclh_lock , .Nm ck_spinlock_hclh_unlock , .Nm ck_spinlock_mcs_init , .Nm ck_spinlock_mcs_locked , .Nm ck_spinlock_mcs_lock , .Nm ck_spinlock_mcs_trylock , .Nm ck_spinlock_mcs_unlock , .Nm ck_spinlock_ticket_init , .Nm ck_spinlock_ticket_locked , .Nm ck_spinlock_ticket_lock , .Nm ck_spinlock_ticket_lock_pb , .Nm ck_spinlock_ticket_trylock , .Nm ck_spinlock_ticket_unlock .Nd spinlock implementations .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_spinlock.h .Pp .Dv ck_spinlock_t spinlock = CK_SPINLOCK_INITIALIZER; .Ft void .Fn ck_spinlock_init "ck_spinlock_t *lock" .Ft void .Fn ck_spinlock_lock "ck_spinlock_t *lock" .Ft void .Fn ck_spinlock_unlock "ck_spinlock_t *lock" .Ft bool .Fn ck_spinlock_locked "ck_spinlock_t *lock" .Ft bool .Fn ck_spinlock_trylock "ck_spinlock_t *lock" .Ft void .Fn ck_spinlock_anderson_init "ck_spinlock_anderson_t *lock" "ck_spinlock_anderson_thread_t *slots" "unsigned int count" .Ft bool .Fn ck_spinlock_anderson_locked "ck_spinlock_anderson_t *lock" .Ft void .Fn ck_spinlock_anderson_lock "ck_spinlock_anderson_t *lock" "ck_spinlock_anderson_thread_t **slot" .Ft void .Fn ck_spinlock_anderson_unlock "ck_spinlock_anderson_t *lock" "ck_spinlock_anderson_thread_t *slot" .Pp .Dv ck_spinlock_cas_t spinlock = CK_SPINLOCK_CAS_INITIALIZER; .Ft void .Fn ck_spinlock_cas_init "ck_spinlock_cas_t *lock" .Ft bool .Fn ck_spinlock_cas_locked "ck_spinlock_cas_t *lock" .Ft void .Fn ck_spinlock_cas_lock "ck_spinlock_cas_t *lock" .Ft void .Fn ck_spinlock_cas_lock_eb "ck_spinlock_cas_t *lock" .Ft bool .Fn ck_spinlock_cas_trylock "ck_spinlock_cas_t *lock" .Ft void .Fn ck_spinlock_cas_unlock "ck_spinlock_cas_t *lock" .Ft void .Fn ck_spinlock_clh_init "ck_spinlock_clh_t **lock" "ck_spinlock_clh_t *unowned" .Ft bool .Fn ck_spinlock_clh_locked "ck_spinlock_clh_t **lock" .Ft void .Fn ck_spinlock_clh_lock "ck_spinlock_clh_t **lock" "ck_spinlock_clh_t *node" .Ft void .Fn ck_spinlock_clh_unlock "ck_spinlock_clh_t **node" .Pp .Dv ck_spinlock_dec_t spinlock = CK_SPINLOCK_DEC_INITIALIZER; .Ft void .Fn ck_spinlock_dec_init "ck_spinlock_dec_t *lock" .Ft bool .Fn ck_spinlock_dec_locked "ck_spinlock_dec_t *lock" .Ft void .Fn ck_spinlock_dec_lock "ck_spinlock_dec_t *lock" .Ft void .Fn ck_spinlock_dec_lock_eb "ck_spinlock_dec_t *lock" .Ft bool .Fn ck_spinlock_dec_trylock "ck_spinlock_dec_t *lock" .Ft void .Fn ck_spinlock_dec_unlock "ck_spinlock_dec_t *lock" .Pp .Dv ck_spinlock_fas_t spinlock = CK_SPINLOCK_FAS_INITIALIZER; .Ft void .Fn ck_spinlock_fas_init "ck_spinlock_fas_t *lock" .Ft void .Fn ck_spinlock_fas_lock "ck_spinlock_fas_t *lock" .Ft void .Fn ck_spinlock_fas_lock_eb "ck_spinlock_fas_t *lock" .Ft bool .Fn ck_spinlock_fas_locked "ck_spinlock_fas_t *lock" .Ft bool .Fn ck_spinlock_fas_trylock "ck_spinlock_fas_t *lock" .Ft void .Fn ck_spinlock_fas_unlock "ck_spinlock_fas_t *lock" .Pp .Ft void .Fn ck_spinlock_hclh_init "ck_spinlock_hclh_t **lock" "ck_spinlock_hclh_t *unowned" .Ft bool .Fn ck_spinlock_hclh_locked "ck_spinlock_hclh_t **lock" .Ft void .Fn ck_spinlock_hclh_lock "ck_spinlock_hclh_t **lock" "ck_spinlock_hclh_t *node" .Ft void .Fn ck_spinlock_hclh_unlock "ck_spinlock_hclh_t **node" .Pp .Dv ck_spinlock_mcs_t spinlock = CK_SPINLOCK_MCS_INITIALIZER; .Ft void .Fn ck_spinlock_mcs_init "ck_spinlock_mcs_t **lock" .Ft bool .Fn ck_spinlock_mcs_locked "ck_spinlock_mcs_t **lock" .Ft void .Fn ck_spinlock_mcs_lock "ck_spinlock_mcs_t **lock" "ck_spinlock_mcs_t *node" .Ft bool .Fn ck_spinlock_mcs_trylock "ck_spinlock_mcs_t **lock" "ck_spinlock_mcs_t *node" .Ft void .Fn ck_spinlock_mcs_unlock "ck_spinlock_mcs_t **lock" "ck_spinlock_mcs_t *node" .Pp .Dv ck_spinlock_ticket_t spinlock = CK_SPINLOCK_TICKET_INITIALIZER; .Ft void .Fn ck_spinlock_ticket_init "ck_spinlock_ticket_t *lock" .Ft bool .Fn ck_spinlock_ticket_locked "ck_spinlock_ticket_t *lock" .Ft void .Fn ck_spinlock_ticket_lock "ck_spinlock_ticket_t *lock" .Ft void .Fn ck_spinlock_ticket_lock_pb "ck_spinlock_ticket_t *lock" "unsigned int period" .Ft bool .Fn ck_spinlock_ticket_trylock "ck_spinlock_ticket_t *lock" .Ft void .Fn ck_spinlock_ticket_unlock "ck_spinlock_ticket_t *lock" .Sh DESCRIPTION A family of busy-wait spinlock implementations. The ck_spinlock_t implementation is simply a wrapper around the fetch-and-swap (ck_spinlock_fas_t) implementation. The table below provides a summary of the current implementations. .Bd -literal | Namespace | Algorithm | Type | Restrictions | Fair | \'----------------------|-----------------------------|---------------|-------------------------|--------' ck_spinlock_anderson Anderson Array Fixed number of threads Yes ck_spinlock_cas Compare-and-Swap Centralized None No ck_spinlock_clh Craig, Landin and Hagersten Queue Lifetime requirements Yes ck_spinlock_dec Decrement (Linux kernel) Centralized UINT_MAX concurrency No ck_spinlock_fas Fetch-and-store Centralized None No ck_spinlock_hclh Hierarchical CLH Queue Lifetime requirements Yes * ck_spinlock_mcs Mellor-Crummey and Scott Queue None Yes ck_spinlock_ticket Ticket Centralized None Yes .Ed .Pp * Hierarchical CLH only offers weak fairness for threads accross cluster nodes. .Pp If contention is low and there is no hard requirement for starvation-freedom then a centralized greedy (unfair) spinlock is recommended. If contention is high and there is no requirement for starvation-freedom then a centralized greedy spinlock is recommended to be used with an exponential backoff mechanism. If contention is generally low and there is a hard requirement for starvation-freedom then the ticket lock is recommended. If contention is high and there is a hard requirement for starvation-freedom then the Craig and Landin and Hagersten queue spinlock is recommended unless stack allocation is necessary or NUMA factor is high, in which case the Mellor-Crummey and Scott spinlock is recommended. If you cannot afford O(n) space-usage from array or queue spinlocks but still require fairness under high contention then the ticket lock with proportional back-off is recommended. If NUMA factor is high but prefer a greedy lock, then please see .Xr ck_cohort 3 . .Sh EXAMPLE .Bd -literal -offset indent #include #include /* * Alternatively, the mutex may be initialized at run-time with * ck_spinlock_init(&mutex). */ ck_spinlock_t mutex = CK_SPINLOCK_INITIALIZER; void example(void) { ck_spinlock_lock(&mutex); /* * Critical section. */ ck_spinlock_unlock(&mutex); ck_spinlock_lock_eb(&mutex); /* * Critical section. */ ck_spinlock_unlock(&mutex); if (ck_spinlock_trylock(&mutex) == true) { /* * Critical section. */ ck_spinlock_unlock(&mutex); } } .Ed .Sh SEE ALSO .Xr ck_cohort 3 , .Xr ck_elide 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_swlock ================================================ .\" .\" Copyright 2014 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2014. .Dt ck_swlock 3 .Sh NAME .Nm ck_swlock_init , .Nm ck_swlock_write_latch , .Nm ck_swlock_write_unlatch , .Nm ck_swlock_write_lock , .Nm ck_swlock_write_unlock , .Nm ck_swlock_write_trylock , .Nm ck_swlock_write_downgrade , .Nm ck_swlock_locked_writer , .Nm ck_swlock_read_lock , .Nm ck_swlock_read_trylock , .Nm ck_swlock_read_unlock , .Nm ck_swlock_locked_reader .Nd centralized copy-safe write-biased single-writer read-write locks .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_swlock.h .Pp .Dv ck_swlock_t lock = CK_SWLOCK_INITIALIZER; .Pp .Ft void .Fn ck_swlock_init "ck_swlock_t *lock" .Ft void .Fn ck_swlock_write_lock "ck_swlock_t *lock" .Ft void .Fn ck_swlock_write_unlock "ck_swlock_t *lock" .Ft void .Fn ck_swlatch_write_latch "ck_swlatch_t *latch" .Ft void .Fn ck_swlatch_write_unlatch "ck_swlatch_t *latch" .Ft bool .Fn ck_swlock_write_trylock "ck_swlock_t *lock" .Ft bool .Fn ck_swlock_write_downgrade "ck_swlock_t *lock" .Ft bool .Fn ck_swlock_locked_writer "ck_swlock_t *lock" .Ft void .Fn ck_swlock_read_lock "ck_swlock_t *lock" .Ft bool .Fn ck_swlock_read_trylock "ck_swlock_t *lock" .Ft void .Fn ck_swlock_read_unlock "ck_swlock_t *lock" .Ft bool .Fn ck_swlock_locked_reader "ck_swlock_t *lock" .Sh DESCRIPTION This is a centralized write-biased single-writer reader-writer lock. It requires half the space that ck_rwlock does and has a low latency fast path. The lock supports latch and unlatch operations that allow it to be used in a copy-safe manner (reader-bits may be over-written safely). .Sh EXAMPLE .Bd -literal -offset indent #include static ck_swlock_t lock = CK_SWLOCK_INITIALIZER; static void reader(void) { for (;;) { ck_swlock_read_lock(&lock); /* Read-side critical section. */ ck_swlock_read_unlock(&lock); if (ck_swlock_read_trylock(&lock) == true) { /* Read-side critical section. */ ck_swlock_read_unlock(&lock); } } return; } static void writer(void) { ck_swlock_t contrived; for (;;) { ck_swlock_write_lock(&lock); /* Write-side critical section. */ ck_swlock_write_unlock(&lock); if (ck_swlock_write_trylock(&lock) == true) { /* Write-side critical section. */ ck_swlock_write_unlock(&lock); } ck_swlock_write_latch(&lock); /* Write-side critical section. */ /* This is safe to do with-in a latch. */ contrived = lock; lock = contrived; ck_swlock_write_unlatch(&lock); } return; } .Ed .Sh SEE ALSO .Xr ck_brlock 3 , .Xr ck_elide 3 , .Xr ck_pflock 3 , .Xr ck_rwlock 3 , .Xr ck_tflock 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/ck_tflock ================================================ .\" .\" Copyright 2014 Samy Al Bahra. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .Dd April 22, 2014. .Dt ck_tflock 3 .Sh NAME .Nm ck_tflock_ticket_init , .Nm ck_tflock_ticket_write_lock , .Nm ck_tflock_ticket_write_unlock , .Nm ck_tflock_ticket_read_lock , .Nm ck_tflock_ticket_read_unlock , .Nd centralized task-fair reader-writer locks .Sh LIBRARY Concurrency Kit (libck, \-lck) .Sh SYNOPSIS .In ck_tflock.h .Pp .Dv ck_tflock_ticket_t lock = CK_TFLOCK_TICKET_INITIALIZER; .Pp .Ft void .Fn ck_tflock_ticket_init "ck_tflock_ticket_t *lock" .Ft void .Fn ck_tflock_ticket_write_lock "ck_tflock_ticket_t *lock" .Ft void .Fn ck_tflock_ticket_write_unlock "ck_tflock_ticket_t *lock" .Ft void .Fn ck_tflock_ticket_read_lock "ck_tflock_ticket_t *lock" .Ft void .Fn ck_tflock_ticket_read_unlock "ck_tflock_ticket_t *lock" .Sh DESCRIPTION This is a centralized task-fair reader-writer lock. It requires little space overhead and has a low latency fast path. .Sh EXAMPLE .Bd -literal -offset indent #include static ck_tflock_ticket_t lock = CK_TFLOCK_INITIALIZER; static void reader(void) { for (;;) { ck_tflock_ticket_read_lock(&lock); /* Read-side critical section. */ ck_tflock_ticket_read_unlock(&lock); } return; } static void writer(void) { for (;;) { ck_tflock_ticket_write_lock(&lock); /* Write-side critical section. */ ck_tflock_ticket_write_unlock(&lock); } return; } .Ed .Sh SEE ALSO .Xr ck_brlock 3 , .Xr ck_rwlock 3 , .Xr ck_pflock 3 , .Xr ck_swlock 3 .Pp Additional information available at http://concurrencykit.org/ ================================================ FILE: third_party/concurrency_kit/ck/doc/refcheck.pl ================================================ #!/usr/bin/perl use warnings; use strict; my @files = @ARGV; my $h; foreach my $file (@files) { $h->{$file} = 1; } foreach my $file (@files) { open(my $fh, "<", $file) or die "cannot open < $file: $!"; while (<$fh>) { chomp; if ($_ =~ /\.Xr ((ck|CK)_[a-zA-Z_]+) ([0-9])/) { my $name = $1; my $section = $3; if (!$h->{$name}) { print STDERR "$file: ref to missing ${name}($section)\n"; } } } close($fh) or die("cannot close $file: $!"); } ================================================ FILE: third_party/concurrency_kit/ck/include/ck_array.h ================================================ /* * Copyright 2013-2015 Samy Al Bahra * Copyright 2013-2014 AppNexus, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_ARRAY_H #define CK_ARRAY_H #include #include #include #include #include struct _ck_array { unsigned int n_committed; unsigned int length; void *values[]; }; struct ck_array { struct ck_malloc *allocator; struct _ck_array *active; unsigned int n_entries; struct _ck_array *transaction; }; typedef struct ck_array ck_array_t; struct ck_array_iterator { struct _ck_array *snapshot; }; typedef struct ck_array_iterator ck_array_iterator_t; #define CK_ARRAY_MODE_SPMC 0U #define CK_ARRAY_MODE_MPMC (void) /* Unsupported. */ bool ck_array_init(ck_array_t *, unsigned int, struct ck_malloc *, unsigned int); bool ck_array_commit(ck_array_t *); bool ck_array_put(ck_array_t *, void *); int ck_array_put_unique(ck_array_t *, void *); bool ck_array_remove(ck_array_t *, void *); void ck_array_deinit(ck_array_t *, bool); CK_CC_INLINE static unsigned int ck_array_length(struct ck_array *array) { struct _ck_array *a = ck_pr_load_ptr(&array->active); ck_pr_fence_load(); return ck_pr_load_uint(&a->n_committed); } CK_CC_INLINE static void * ck_array_buffer(struct ck_array *array, unsigned int *length) { struct _ck_array *a = ck_pr_load_ptr(&array->active); ck_pr_fence_load(); *length = ck_pr_load_uint(&a->n_committed); return a->values; } CK_CC_INLINE static bool ck_array_initialized(struct ck_array *array) { return ck_pr_load_ptr(&array->active) != NULL; } #define CK_ARRAY_FOREACH(a, i, b) \ (i)->snapshot = ck_pr_load_ptr(&(a)->active); \ ck_pr_fence_load(); \ for (unsigned int _ck_i = 0; \ _ck_i < (a)->active->n_committed && \ ((*b) = (a)->active->values[_ck_i], 1); \ _ck_i++) #endif /* CK_ARRAY_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_backoff.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_BACKOFF_H #define CK_BACKOFF_H #include #include #ifndef CK_BACKOFF_CEILING #define CK_BACKOFF_CEILING ((1 << 20) - 1) #endif #define CK_BACKOFF_INITIALIZER (1 << 9) typedef unsigned int ck_backoff_t; /* * This is a exponential back-off implementation. */ CK_CC_INLINE static void ck_backoff_eb(unsigned int *c) { unsigned int i, ceiling; ceiling = *c; for (i = 0; i < ceiling; i++) ck_pr_barrier(); *c = ceiling <<= ceiling < CK_BACKOFF_CEILING; return; } #endif /* CK_BACKOFF_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_barrier.h ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_BARRIER_H #define CK_BARRIER_H #include struct ck_barrier_centralized { unsigned int value; unsigned int sense; }; typedef struct ck_barrier_centralized ck_barrier_centralized_t; struct ck_barrier_centralized_state { unsigned int sense; }; typedef struct ck_barrier_centralized_state ck_barrier_centralized_state_t; #define CK_BARRIER_CENTRALIZED_INITIALIZER {0, 0} #define CK_BARRIER_CENTRALIZED_STATE_INITIALIZER {0} void ck_barrier_centralized(ck_barrier_centralized_t *, ck_barrier_centralized_state_t *, unsigned int); struct ck_barrier_combining_group { unsigned int k; unsigned int count; unsigned int sense; struct ck_barrier_combining_group *parent; struct ck_barrier_combining_group *left; struct ck_barrier_combining_group *right; struct ck_barrier_combining_group *next; } CK_CC_CACHELINE; typedef struct ck_barrier_combining_group ck_barrier_combining_group_t; struct ck_barrier_combining_state { unsigned int sense; }; typedef struct ck_barrier_combining_state ck_barrier_combining_state_t; #define CK_BARRIER_COMBINING_STATE_INITIALIZER {~0} struct ck_barrier_combining { struct ck_barrier_combining_group *root; ck_spinlock_fas_t mutex; }; typedef struct ck_barrier_combining ck_barrier_combining_t; void ck_barrier_combining_init(ck_barrier_combining_t *, ck_barrier_combining_group_t *); void ck_barrier_combining_group_init(ck_barrier_combining_t *, ck_barrier_combining_group_t *, unsigned int); void ck_barrier_combining(ck_barrier_combining_t *, ck_barrier_combining_group_t *, ck_barrier_combining_state_t *); struct ck_barrier_dissemination_flag { unsigned int tflag; unsigned int *pflag; }; typedef struct ck_barrier_dissemination_flag ck_barrier_dissemination_flag_t; struct ck_barrier_dissemination { unsigned int nthr; unsigned int size; unsigned int tid; struct ck_barrier_dissemination_flag *flags[2]; }; typedef struct ck_barrier_dissemination ck_barrier_dissemination_t; struct ck_barrier_dissemination_state { int parity; unsigned int sense; unsigned int tid; }; typedef struct ck_barrier_dissemination_state ck_barrier_dissemination_state_t; void ck_barrier_dissemination_init(ck_barrier_dissemination_t *, ck_barrier_dissemination_flag_t **, unsigned int); void ck_barrier_dissemination_subscribe(ck_barrier_dissemination_t *, ck_barrier_dissemination_state_t *); unsigned int ck_barrier_dissemination_size(unsigned int); void ck_barrier_dissemination(ck_barrier_dissemination_t *, ck_barrier_dissemination_state_t *); struct ck_barrier_tournament_round { int role; unsigned int *opponent; unsigned int flag; }; typedef struct ck_barrier_tournament_round ck_barrier_tournament_round_t; struct ck_barrier_tournament { unsigned int tid; unsigned int size; struct ck_barrier_tournament_round **rounds; }; typedef struct ck_barrier_tournament ck_barrier_tournament_t; struct ck_barrier_tournament_state { unsigned int sense; unsigned int vpid; }; typedef struct ck_barrier_tournament_state ck_barrier_tournament_state_t; void ck_barrier_tournament_subscribe(ck_barrier_tournament_t *, ck_barrier_tournament_state_t *); void ck_barrier_tournament_init(ck_barrier_tournament_t *, ck_barrier_tournament_round_t **, unsigned int); unsigned int ck_barrier_tournament_size(unsigned int); void ck_barrier_tournament(ck_barrier_tournament_t *, ck_barrier_tournament_state_t *); struct ck_barrier_mcs { unsigned int tid; unsigned int *children[2]; unsigned int childnotready[4]; unsigned int dummy; unsigned int havechild[4]; unsigned int *parent; unsigned int parentsense; }; typedef struct ck_barrier_mcs ck_barrier_mcs_t; struct ck_barrier_mcs_state { unsigned int sense; unsigned int vpid; }; typedef struct ck_barrier_mcs_state ck_barrier_mcs_state_t; void ck_barrier_mcs_init(ck_barrier_mcs_t *, unsigned int); void ck_barrier_mcs_subscribe(ck_barrier_mcs_t *, ck_barrier_mcs_state_t *); void ck_barrier_mcs(ck_barrier_mcs_t *, ck_barrier_mcs_state_t *); #endif /* CK_BARRIER_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_bitmap.h ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * Copyright 2012-2014 AppNexus, Inc. * Copyright 2014 Paul Khuong. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_BITMAP_H #define CK_BITMAP_H #include #include #include #include #include #include #include #include #include #if !defined(CK_F_PR_LOAD_UINT) || !defined(CK_F_PR_STORE_UINT) || \ !defined(CK_F_PR_AND_UINT) || !defined(CK_F_PR_OR_UINT) || \ !defined(CK_F_CC_CTZ) #error "ck_bitmap is not supported on your platform." #endif #define CK_BITMAP_BLOCK (sizeof(unsigned int) * CHAR_BIT) #define CK_BITMAP_OFFSET(i) ((i) % CK_BITMAP_BLOCK) #define CK_BITMAP_BIT(i) (1U << CK_BITMAP_OFFSET(i)) #define CK_BITMAP_PTR(x, i) ((x) + ((i) / CK_BITMAP_BLOCK)) #define CK_BITMAP_BLOCKS(n) (((n) + CK_BITMAP_BLOCK - 1) / CK_BITMAP_BLOCK) #define CK_BITMAP_INSTANCE(n_entries) \ union { \ struct { \ unsigned int n_bits; \ unsigned int map[CK_BITMAP_BLOCKS(n_entries)]; \ } content; \ struct ck_bitmap bitmap; \ } #define CK_BITMAP_ITERATOR_INIT(a, b) \ ck_bitmap_iterator_init((a), &(b)->bitmap) #define CK_BITMAP_INIT(a, b, c) \ ck_bitmap_init(&(a)->bitmap, (b), (c)) #define CK_BITMAP_NEXT(a, b, c) \ ck_bitmap_next(&(a)->bitmap, (b), (c)) #define CK_BITMAP_SET(a, b) \ ck_bitmap_set(&(a)->bitmap, (b)) #define CK_BITMAP_BTS(a, b) \ ck_bitmap_bts(&(a)->bitmap, (b)) #define CK_BITMAP_RESET(a, b) \ ck_bitmap_reset(&(a)->bitmap, (b)) #define CK_BITMAP_TEST(a, b) \ ck_bitmap_test(&(a)->bitmap, (b)) #define CK_BITMAP_UNION(a, b) \ ck_bitmap_union(&(a)->bitmap, &(b)->bitmap) #define CK_BITMAP_INTERSECTION(a, b) \ ck_bitmap_intersection(&(a)->bitmap, &(b)->bitmap) #define CK_BITMAP_INTERSECTION_NEGATE(a, b) \ ck_bitmap_intersection_negate(&(a)->bitmap, &(b)->bitmap) #define CK_BITMAP_CLEAR(a) \ ck_bitmap_clear(&(a)->bitmap) #define CK_BITMAP_EMPTY(a, b) \ ck_bitmap_empty(&(a)->bitmap, b) #define CK_BITMAP_FULL(a, b) \ ck_bitmap_full(&(a)->bitmap, b) #define CK_BITMAP_COUNT(a, b) \ ck_bitmap_count(&(a)->bitmap, b) #define CK_BITMAP_COUNT_INTERSECT(a, b, c) \ ck_bitmap_count_intersect(&(a)->bitmap, b, c) #define CK_BITMAP_BITS(a) \ ck_bitmap_bits(&(a)->bitmap) #define CK_BITMAP_BUFFER(a) \ ck_bitmap_buffer(&(a)->bitmap) #define CK_BITMAP(a) \ (&(a)->bitmap) struct ck_bitmap { unsigned int n_bits; unsigned int map[]; }; typedef struct ck_bitmap ck_bitmap_t; struct ck_bitmap_iterator { unsigned int cache; unsigned int n_block; unsigned int n_limit; }; typedef struct ck_bitmap_iterator ck_bitmap_iterator_t; CK_CC_INLINE static unsigned int ck_bitmap_base(unsigned int n_bits) { return CK_BITMAP_BLOCKS(n_bits) * sizeof(unsigned int); } /* * Returns the required number of bytes for a ck_bitmap_t object supporting the * specified number of bits. */ CK_CC_INLINE static unsigned int ck_bitmap_size(unsigned int n_bits) { return ck_bitmap_base(n_bits) + sizeof(struct ck_bitmap); } /* * Returns total number of bits in specified bitmap. */ CK_CC_INLINE static unsigned int ck_bitmap_bits(const struct ck_bitmap *bitmap) { return bitmap->n_bits; } /* * Returns a pointer to the bit buffer associated * with the specified bitmap. */ CK_CC_INLINE static void * ck_bitmap_buffer(struct ck_bitmap *bitmap) { return bitmap->map; } /* * Sets the bit at the offset specified in the second argument. */ CK_CC_INLINE static void ck_bitmap_set(struct ck_bitmap *bitmap, unsigned int n) { ck_pr_or_uint(CK_BITMAP_PTR(bitmap->map, n), CK_BITMAP_BIT(n)); return; } /* * Performs a test-and-set operation at the offset specified in the * second argument. * Returns true if the bit at the specified offset was already set, * false otherwise. */ CK_CC_INLINE static bool ck_bitmap_bts(struct ck_bitmap *bitmap, unsigned int n) { return ck_pr_bts_uint(CK_BITMAP_PTR(bitmap->map, n), CK_BITMAP_OFFSET(n)); } /* * Resets the bit at the offset specified in the second argument. */ CK_CC_INLINE static void ck_bitmap_reset(struct ck_bitmap *bitmap, unsigned int n) { ck_pr_and_uint(CK_BITMAP_PTR(bitmap->map, n), ~CK_BITMAP_BIT(n)); return; } /* * Determines whether the bit at offset specified in the * second argument is set. */ CK_CC_INLINE static bool ck_bitmap_test(const struct ck_bitmap *bitmap, unsigned int n) { unsigned int block; block = ck_pr_load_uint(CK_BITMAP_PTR(bitmap->map, n)); return block & CK_BITMAP_BIT(n); } /* * Combines bits from second bitmap into the first bitmap. This is not a * linearized operation with respect to the complete bitmap. */ CK_CC_INLINE static void ck_bitmap_union(struct ck_bitmap *dst, const struct ck_bitmap *src) { unsigned int n; unsigned int n_buckets = dst->n_bits; if (src->n_bits < dst->n_bits) n_buckets = src->n_bits; n_buckets = CK_BITMAP_BLOCKS(n_buckets); for (n = 0; n < n_buckets; n++) { ck_pr_or_uint(&dst->map[n], ck_pr_load_uint(&src->map[n])); } return; } /* * Intersects bits from second bitmap into the first bitmap. This is * not a linearized operation with respect to the complete bitmap. * Any trailing bit in dst is cleared. */ CK_CC_INLINE static void ck_bitmap_intersection(struct ck_bitmap *dst, const struct ck_bitmap *src) { unsigned int n; unsigned int n_buckets = dst->n_bits; unsigned int n_intersect = n_buckets; if (src->n_bits < n_intersect) n_intersect = src->n_bits; n_buckets = CK_BITMAP_BLOCKS(n_buckets); n_intersect = CK_BITMAP_BLOCKS(n_intersect); for (n = 0; n < n_intersect; n++) { ck_pr_and_uint(&dst->map[n], ck_pr_load_uint(&src->map[n])); } for (; n < n_buckets; n++) ck_pr_store_uint(&dst->map[n], 0); return; } /* * Intersects the complement of bits from second bitmap into the first * bitmap. This is not a linearized operation with respect to the * complete bitmap. Any trailing bit in dst is left as is. */ CK_CC_INLINE static void ck_bitmap_intersection_negate(struct ck_bitmap *dst, const struct ck_bitmap *src) { unsigned int n; unsigned int n_intersect = dst->n_bits; if (src->n_bits < n_intersect) n_intersect = src->n_bits; n_intersect = CK_BITMAP_BLOCKS(n_intersect); for (n = 0; n < n_intersect; n++) { ck_pr_and_uint(&dst->map[n], (~ck_pr_load_uint(&src->map[n]))); } return; } /* * Resets all bits in the provided bitmap. This is not a linearized * operation in ck_bitmap. */ CK_CC_INLINE static void ck_bitmap_clear(struct ck_bitmap *bitmap) { unsigned int i; unsigned int n_buckets = ck_bitmap_base(bitmap->n_bits) / sizeof(unsigned int); for (i = 0; i < n_buckets; i++) ck_pr_store_uint(&bitmap->map[i], 0); return; } /* * Returns true if the first limit bits in bitmap are cleared. If * limit is greater than the bitmap size, limit is truncated to that * size. */ CK_CC_INLINE static bool ck_bitmap_empty(const ck_bitmap_t *bitmap, unsigned int limit) { unsigned int i, words, slop; if (limit > bitmap->n_bits) limit = bitmap->n_bits; words = limit / CK_BITMAP_BLOCK; slop = limit % CK_BITMAP_BLOCK; for (i = 0; i < words; i++) { if (ck_pr_load_uint(&bitmap->map[i]) != 0) { return false; } } if (slop > 0) { unsigned int word; word = ck_pr_load_uint(&bitmap->map[i]); if ((word & ((1U << slop) - 1)) != 0) return false; } return true; } /* * Returns true if the first limit bits in bitmap are set. If limit * is greater than the bitmap size, limit is truncated to that size. */ CK_CC_UNUSED static bool ck_bitmap_full(const ck_bitmap_t *bitmap, unsigned int limit) { unsigned int i, slop, words; if (limit > bitmap->n_bits) { limit = bitmap->n_bits; } words = limit / CK_BITMAP_BLOCK; slop = limit % CK_BITMAP_BLOCK; for (i = 0; i < words; i++) { if (ck_pr_load_uint(&bitmap->map[i]) != -1U) return false; } if (slop > 0) { unsigned int word; word = ~ck_pr_load_uint(&bitmap->map[i]); if ((word & ((1U << slop) - 1)) != 0) return false; } return true; } /* * Returns the number of set bit in bitmap, upto (and excluding) * limit. If limit is greater than the bitmap size, it is truncated * to that size. */ CK_CC_INLINE static unsigned int ck_bitmap_count(const ck_bitmap_t *bitmap, unsigned int limit) { unsigned int count, i, slop, words; if (limit > bitmap->n_bits) limit = bitmap->n_bits; words = limit / CK_BITMAP_BLOCK; slop = limit % CK_BITMAP_BLOCK; for (i = 0, count = 0; i < words; i++) count += ck_cc_popcount(ck_pr_load_uint(&bitmap->map[i])); if (slop > 0) { unsigned int word; word = ck_pr_load_uint(&bitmap->map[i]); count += ck_cc_popcount(word & ((1U << slop) - 1)); } return count; } /* * Returns the number of set bit in the intersection of two bitmaps, * upto (and excluding) limit. If limit is greater than either bitmap * size, it is truncated to the smallest. */ CK_CC_INLINE static unsigned int ck_bitmap_count_intersect(const ck_bitmap_t *x, const ck_bitmap_t *y, unsigned int limit) { unsigned int count, i, slop, words; if (limit > x->n_bits) limit = x->n_bits; if (limit > y->n_bits) limit = y->n_bits; words = limit / CK_BITMAP_BLOCK; slop = limit % CK_BITMAP_BLOCK; for (i = 0, count = 0; i < words; i++) { unsigned int xi, yi; xi = ck_pr_load_uint(&x->map[i]); yi = ck_pr_load_uint(&y->map[i]); count += ck_cc_popcount(xi & yi); } if (slop > 0) { unsigned int word, xi, yi; xi = ck_pr_load_uint(&x->map[i]); yi = ck_pr_load_uint(&y->map[i]); word = xi & yi; count += ck_cc_popcount(word & ((1U << slop) - 1)); } return count; } /* * Initializes a ck_bitmap pointing to a region of memory with * ck_bitmap_size(n_bits) bytes. Third argument determines whether * default bit value is 1 (true) or 0 (false). */ CK_CC_INLINE static void ck_bitmap_init(struct ck_bitmap *bitmap, unsigned int n_bits, bool set) { unsigned int base = ck_bitmap_base(n_bits); bitmap->n_bits = n_bits; memset(bitmap->map, -(int)set, base); if (set == true) { unsigned int b = n_bits % CK_BITMAP_BLOCK; if (b == 0) return; *CK_BITMAP_PTR(bitmap->map, n_bits - 1) &= (1U << b) - 1U; } return; } /* * Initialize iterator for use with provided bitmap. */ CK_CC_INLINE static void ck_bitmap_iterator_init(struct ck_bitmap_iterator *i, const struct ck_bitmap *bitmap) { i->n_block = 0; i->n_limit = CK_BITMAP_BLOCKS(bitmap->n_bits); if (i->n_limit > 0) { i->cache = ck_pr_load_uint(&bitmap->map[0]); } else { i->cache = 0; } return; } /* * Iterate to next bit. */ CK_CC_INLINE static bool ck_bitmap_next(const struct ck_bitmap *bitmap, struct ck_bitmap_iterator *i, unsigned int *bit) { unsigned int cache = i->cache; unsigned int n_block = i->n_block; unsigned int n_limit = i->n_limit; if (cache == 0) { if (n_block >= n_limit) return false; for (n_block++; n_block < n_limit; n_block++) { cache = ck_pr_load_uint(&bitmap->map[n_block]); if (cache != 0) goto non_zero; } i->cache = 0; i->n_block = n_block; return false; } non_zero: *bit = CK_BITMAP_BLOCK * n_block + ck_cc_ctz(cache); i->cache = cache & (cache - 1); i->n_block = n_block; return true; } #endif /* CK_BITMAP_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_brlock.h ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_BRLOCK_H #define CK_BRLOCK_H /* * Big reader spinlocks provide cache-local contention-free read * lock acquisition in the absence of writers. This comes at the * cost of O(n) write lock acquisition. They were first implemented * in the Linux kernel by Ingo Molnar and David S. Miller around the * year 2000. * * This implementation is thread-agnostic which comes at the cost * of larger reader objects due to necessary linkage overhead. In * order to cut down on TLB pressure, it is recommended to allocate * these objects on the same page. */ #include #include #include struct ck_brlock_reader { unsigned int n_readers; struct ck_brlock_reader *previous; struct ck_brlock_reader *next; }; typedef struct ck_brlock_reader ck_brlock_reader_t; #define CK_BRLOCK_READER_INITIALIZER {0} struct ck_brlock { struct ck_brlock_reader *readers; unsigned int writer; }; typedef struct ck_brlock ck_brlock_t; #define CK_BRLOCK_INITIALIZER {NULL, false} CK_CC_INLINE static void ck_brlock_init(struct ck_brlock *br) { br->readers = NULL; br->writer = false; ck_pr_barrier(); return; } CK_CC_INLINE static void ck_brlock_write_lock(struct ck_brlock *br) { struct ck_brlock_reader *cursor; /* * As the frequency of write acquisitions should be low, * there is no point to more advanced contention avoidance. */ while (ck_pr_fas_uint(&br->writer, true) == true) ck_pr_stall(); ck_pr_fence_atomic_load(); /* The reader list is protected under the writer br. */ for (cursor = br->readers; cursor != NULL; cursor = cursor->next) { while (ck_pr_load_uint(&cursor->n_readers) != 0) ck_pr_stall(); } ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_brlock_write_unlock(struct ck_brlock *br) { ck_pr_fence_unlock(); ck_pr_store_uint(&br->writer, false); return; } CK_CC_INLINE static bool ck_brlock_write_trylock(struct ck_brlock *br, unsigned int factor) { struct ck_brlock_reader *cursor; unsigned int steps = 0; while (ck_pr_fas_uint(&br->writer, true) == true) { if (++steps >= factor) return false; ck_pr_stall(); } /* * We do not require a strict fence here as atomic RMW operations * are serializing. */ ck_pr_fence_atomic_load(); for (cursor = br->readers; cursor != NULL; cursor = cursor->next) { while (ck_pr_load_uint(&cursor->n_readers) != 0) { if (++steps >= factor) { ck_brlock_write_unlock(br); return false; } ck_pr_stall(); } } ck_pr_fence_lock(); return true; } CK_CC_INLINE static void ck_brlock_read_register(struct ck_brlock *br, struct ck_brlock_reader *reader) { reader->n_readers = 0; reader->previous = NULL; /* Implicit compiler barrier. */ ck_brlock_write_lock(br); reader->next = ck_pr_load_ptr(&br->readers); if (reader->next != NULL) reader->next->previous = reader; ck_pr_store_ptr(&br->readers, reader); ck_brlock_write_unlock(br); return; } CK_CC_INLINE static void ck_brlock_read_unregister(struct ck_brlock *br, struct ck_brlock_reader *reader) { ck_brlock_write_lock(br); if (reader->next != NULL) reader->next->previous = reader->previous; if (reader->previous != NULL) reader->previous->next = reader->next; else br->readers = reader->next; ck_brlock_write_unlock(br); return; } CK_CC_INLINE static void ck_brlock_read_lock(struct ck_brlock *br, struct ck_brlock_reader *reader) { if (reader->n_readers >= 1) { ck_pr_store_uint(&reader->n_readers, reader->n_readers + 1); return; } for (;;) { while (ck_pr_load_uint(&br->writer) == true) ck_pr_stall(); #if defined(__x86__) || defined(__x86_64__) ck_pr_fas_uint(&reader->n_readers, 1); /* * Serialize reader counter update with respect to load of * writer. */ ck_pr_fence_atomic_load(); #else ck_pr_store_uint(&reader->n_readers, 1); /* * Serialize reader counter update with respect to load of * writer. */ ck_pr_fence_store_load(); #endif if (ck_pr_load_uint(&br->writer) == false) break; ck_pr_store_uint(&reader->n_readers, 0); } ck_pr_fence_lock(); return; } CK_CC_INLINE static bool ck_brlock_read_trylock(struct ck_brlock *br, struct ck_brlock_reader *reader, unsigned int factor) { unsigned int steps = 0; if (reader->n_readers >= 1) { ck_pr_store_uint(&reader->n_readers, reader->n_readers + 1); return true; } for (;;) { while (ck_pr_load_uint(&br->writer) == true) { if (++steps >= factor) return false; ck_pr_stall(); } #if defined(__x86__) || defined(__x86_64__) ck_pr_fas_uint(&reader->n_readers, 1); /* * Serialize reader counter update with respect to load of * writer. */ ck_pr_fence_atomic_load(); #else ck_pr_store_uint(&reader->n_readers, 1); /* * Serialize reader counter update with respect to load of * writer. */ ck_pr_fence_store_load(); #endif if (ck_pr_load_uint(&br->writer) == false) break; ck_pr_store_uint(&reader->n_readers, 0); if (++steps >= factor) return false; } ck_pr_fence_lock(); return true; } CK_CC_INLINE static void ck_brlock_read_unlock(struct ck_brlock_reader *reader) { ck_pr_fence_unlock(); ck_pr_store_uint(&reader->n_readers, reader->n_readers - 1); return; } #endif /* CK_BRLOCK_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_bytelock.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_BYTELOCK_H #define CK_BYTELOCK_H /* * The implementations here are derived from the work described in: * Dice, D. and Shavit, N. 2010. TLRW: return of the read-write lock. * In Proceedings of the 22nd ACM Symposium on Parallelism in Algorithms * and Architectures (Thira, Santorini, Greece, June 13 - 15, 2010). * SPAA '10. ACM, New York, NY, 284-293. */ #include #include #include #include #include #include struct ck_bytelock { unsigned int owner; unsigned int n_readers; uint8_t readers[CK_MD_CACHELINE - sizeof(unsigned int) * 2] CK_CC_ALIGN(8); }; typedef struct ck_bytelock ck_bytelock_t; #define CK_BYTELOCK_INITIALIZER { 0, 0, {0} } #define CK_BYTELOCK_UNSLOTTED UINT_MAX CK_CC_INLINE static void ck_bytelock_init(struct ck_bytelock *bytelock) { unsigned int i; bytelock->owner = 0; bytelock->n_readers = 0; for (i = 0; i < sizeof bytelock->readers; i++) bytelock->readers[i] = false; ck_pr_barrier(); return; } #ifdef CK_F_PR_LOAD_64 #define CK_BYTELOCK_LENGTH sizeof(uint64_t) #define CK_BYTELOCK_LOAD ck_pr_load_64 #define CK_BYTELOCK_TYPE uint64_t #elif defined(CK_F_PR_LOAD_32) #define CK_BYTELOCK_LENGTH sizeof(uint32_t) #define CK_BYTELOCK_LOAD ck_pr_load_32 #define CK_BYTELOCK_TYPE uint32_t #else #error Unsupported platform. #endif CK_CC_INLINE static void ck_bytelock_write_lock(struct ck_bytelock *bytelock, unsigned int slot) { CK_BYTELOCK_TYPE *readers = (void *)bytelock->readers; unsigned int i; /* Announce upcoming writer acquisition. */ while (ck_pr_cas_uint(&bytelock->owner, 0, slot) == false) ck_pr_stall(); /* If we are slotted, we might be upgrading from a read lock. */ if (slot <= sizeof bytelock->readers) ck_pr_store_8(&bytelock->readers[slot - 1], false); /* * Wait for slotted readers to drain out. This also provides the * lock acquire semantics. */ ck_pr_fence_atomic_load(); for (i = 0; i < sizeof(bytelock->readers) / CK_BYTELOCK_LENGTH; i++) { while (CK_BYTELOCK_LOAD(&readers[i]) != false) ck_pr_stall(); } /* Wait for unslotted readers to drain out. */ while (ck_pr_load_uint(&bytelock->n_readers) != 0) ck_pr_stall(); ck_pr_fence_lock(); return; } #undef CK_BYTELOCK_LENGTH #undef CK_BYTELOCK_LOAD #undef CK_BYTELOCK_TYPE CK_CC_INLINE static void ck_bytelock_write_unlock(struct ck_bytelock *bytelock) { ck_pr_fence_unlock(); ck_pr_store_uint(&bytelock->owner, 0); return; } CK_CC_INLINE static void ck_bytelock_read_lock(struct ck_bytelock *bytelock, unsigned int slot) { if (ck_pr_load_uint(&bytelock->owner) == slot) { ck_pr_store_8(&bytelock->readers[slot - 1], true); ck_pr_fence_strict_store(); ck_pr_store_uint(&bytelock->owner, 0); return; } /* Unslotted threads will have to use the readers counter. */ if (slot > sizeof bytelock->readers) { for (;;) { ck_pr_inc_uint(&bytelock->n_readers); ck_pr_fence_atomic_load(); if (ck_pr_load_uint(&bytelock->owner) == 0) break; ck_pr_dec_uint(&bytelock->n_readers); while (ck_pr_load_uint(&bytelock->owner) != 0) ck_pr_stall(); } ck_pr_fence_lock(); return; } slot -= 1; for (;;) { #ifdef CK_F_PR_FAA_8 ck_pr_fas_8(&bytelock->readers[slot], true); ck_pr_fence_atomic_load(); #else ck_pr_store_8(&bytelock->readers[slot], true); ck_pr_fence_store_load(); #endif /* * If there is no owner at this point, our slot has * already been published and it is guaranteed no * write acquisition will succeed until we drain out. */ if (ck_pr_load_uint(&bytelock->owner) == 0) break; ck_pr_store_8(&bytelock->readers[slot], false); while (ck_pr_load_uint(&bytelock->owner) != 0) ck_pr_stall(); } ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_bytelock_read_unlock(struct ck_bytelock *bytelock, unsigned int slot) { ck_pr_fence_unlock(); if (slot > sizeof bytelock->readers) ck_pr_dec_uint(&bytelock->n_readers); else ck_pr_store_8(&bytelock->readers[slot - 1], false); return; } #endif /* CK_BYTELOCK_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_cc.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * Copyright 2014 Paul Khuong. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_CC_H #define CK_CC_H #if defined(__GNUC__) || defined(__SUNPRO_C) #include "gcc/ck_cc.h" #endif #ifndef CK_CC_RESTRICT #define CK_CC_RESTRICT #endif #ifndef CK_CC_INLINE #define CK_CC_INLINE inline #endif #ifndef CK_CC_FORCE_INLINE #define CK_CC_FORCE_INLINE inline #endif #define CK_CC_DECONST_PTR(X) ((void *)(uintptr_t)(X)) /* * Container function. * This relies on (compiler) implementation-defined behavior. */ #define CK_CC_CONTAINER(F, T, M, N) \ CK_CC_INLINE static T * \ N(F *p) \ { \ F *n = p; \ return (T *)(void *)(((char *)n) - ((size_t)&((T *)0)->M)); \ } #define CK_CC_PAD(x) union { char pad[x]; } #ifndef CK_CC_ALIASED #define CK_CC_ALIASED #endif #ifndef CK_CC_UNUSED #define CK_CC_UNUSED #endif #ifndef CK_CC_USED #define CK_CC_USED #endif #ifndef CK_CC_IMM #define CK_CC_IMM #endif #ifndef CK_CC_PACKED #define CK_CC_PACKED #endif #ifndef CK_CC_WEAKREF #define CK_CC_WEAKREF #endif #ifndef CK_CC_ALIGN #define CK_CC_ALIGN(X) #endif #ifndef CK_CC_CACHELINE #define CK_CC_CACHELINE #endif #ifndef CK_CC_LIKELY #define CK_CC_LIKELY(x) x #endif #ifndef CK_CC_UNLIKELY #define CK_CC_UNLIKELY(x) x #endif #ifndef CK_CC_TYPEOF #define CK_CC_TYPEOF(X, DEFAULT) (DEFAULT) #endif #ifndef CK_F_CC_FFS #define CK_F_CC_FFS CK_CC_INLINE static int ck_cc_ffs(unsigned int x) { unsigned int i; if (x == 0) return 0; for (i = 1; (x & 1) == 0; i++, x >>= 1); return i; } #endif #ifndef CK_F_CC_CLZ #define CK_F_CC_CLZ #include CK_CC_INLINE static int ck_cc_clz(unsigned int x) { unsigned int count, i; for (count = 0, i = sizeof(unsigned int) * CHAR_BIT; i > 0; count++) { unsigned int bit = 1U << --i; if (x & bit) break; } return count; } #endif #ifndef CK_F_CC_CTZ #define CK_F_CC_CTZ CK_CC_INLINE static int ck_cc_ctz(unsigned int x) { unsigned int i; if (x == 0) return 0; for (i = 0; (x & 1) == 0; i++, x >>= 1); return i; } #endif #ifndef CK_F_CC_POPCOUNT #define CK_F_CC_POPCOUNT CK_CC_INLINE static int ck_cc_popcount(unsigned int x) { unsigned int acc; for (acc = 0; x != 0; x >>= 1) acc += x & 1; return acc; } #endif #ifdef __cplusplus #define CK_CPP_CAST(type, arg) static_cast(arg) #else #define CK_CPP_CAST(type, arg) arg #endif #endif /* CK_CC_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_cohort.h ================================================ /* * Copyright 2013-2015 Samy Al Bahra. * Copyright 2013 Brendon Scheinman. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_COHORT_H #define CK_COHORT_H /* * This is an implementation of lock cohorts as described in: * Dice, D.; Marathe, V.; and Shavit, N. 2012. * Lock Cohorting: A General Technique for Designing NUMA Locks */ #include #include #include enum ck_cohort_state { CK_COHORT_STATE_GLOBAL = 0, CK_COHORT_STATE_LOCAL = 1 }; #define CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT 10 #define CK_COHORT_NAME(N) ck_cohort_##N #define CK_COHORT_INSTANCE(N) struct CK_COHORT_NAME(N) #define CK_COHORT_INIT(N, C, GL, LL, P) ck_cohort_##N##_init(C, GL, LL, P) #define CK_COHORT_LOCK(N, C, GC, LC) ck_cohort_##N##_lock(C, GC, LC) #define CK_COHORT_UNLOCK(N, C, GC, LC) ck_cohort_##N##_unlock(C, GC, LC) #define CK_COHORT_TRYLOCK(N, C, GLC, LLC, LUC) ck_cohort_##N##_trylock(C, GLC, LLC, LUC) #define CK_COHORT_LOCKED(N, C, GC, LC) ck_cohort_##N##_locked(C, GC, LC) #define CK_COHORT_PROTOTYPE(N, GL, GU, GI, LL, LU, LI) \ CK_COHORT_INSTANCE(N) { \ void *global_lock; \ void *local_lock; \ enum ck_cohort_state release_state; \ unsigned int waiting_threads; \ unsigned int acquire_count; \ unsigned int local_pass_limit; \ }; \ \ CK_CC_INLINE static void \ ck_cohort_##N##_init(struct ck_cohort_##N *cohort, \ void *global_lock, void *local_lock, unsigned int pass_limit) \ { \ cohort->global_lock = global_lock; \ cohort->local_lock = local_lock; \ cohort->release_state = CK_COHORT_STATE_GLOBAL; \ cohort->waiting_threads = 0; \ cohort->acquire_count = 0; \ cohort->local_pass_limit = pass_limit; \ ck_pr_barrier(); \ return; \ } \ \ CK_CC_INLINE static void \ ck_cohort_##N##_lock(CK_COHORT_INSTANCE(N) *cohort, \ void *global_context, void *local_context) \ { \ \ ck_pr_inc_uint(&cohort->waiting_threads); \ LL(cohort->local_lock, local_context); \ ck_pr_dec_uint(&cohort->waiting_threads); \ \ if (cohort->release_state == CK_COHORT_STATE_GLOBAL) { \ GL(cohort->global_lock, global_context); \ } \ \ ++cohort->acquire_count; \ return; \ } \ \ CK_CC_INLINE static void \ ck_cohort_##N##_unlock(CK_COHORT_INSTANCE(N) *cohort, \ void *global_context, void *local_context) \ { \ \ if (ck_pr_load_uint(&cohort->waiting_threads) > 0 \ && cohort->acquire_count < cohort->local_pass_limit) { \ cohort->release_state = CK_COHORT_STATE_LOCAL; \ } else { \ GU(cohort->global_lock, global_context); \ cohort->release_state = CK_COHORT_STATE_GLOBAL; \ cohort->acquire_count = 0; \ } \ \ ck_pr_fence_release(); \ LU(cohort->local_lock, local_context); \ \ return; \ } \ \ CK_CC_INLINE static bool \ ck_cohort_##N##_locked(CK_COHORT_INSTANCE(N) *cohort, \ void *global_context, void *local_context) \ { \ return GI(cohort->local_lock, local_context) || \ LI(cohort->global_lock, global_context); \ } #define CK_COHORT_TRYLOCK_PROTOTYPE(N, GL, GU, GI, GTL, LL, LU, LI, LTL) \ CK_COHORT_PROTOTYPE(N, GL, GU, GI, LL, LU, LI) \ CK_CC_INLINE static bool \ ck_cohort_##N##_trylock(CK_COHORT_INSTANCE(N) *cohort, \ void *global_context, void *local_context, \ void *local_unlock_context) \ { \ \ bool trylock_result; \ \ ck_pr_inc_uint(&cohort->waiting_threads); \ trylock_result = LTL(cohort->local_lock, local_context); \ ck_pr_dec_uint(&cohort->waiting_threads); \ if (trylock_result == false) { \ return false; \ } \ \ if (cohort->release_state == CK_COHORT_STATE_GLOBAL && \ GTL(cohort->global_lock, global_context) == false) { \ LU(cohort->local_lock, local_unlock_context); \ return false; \ } \ \ ++cohort->acquire_count; \ return true; \ } #define CK_COHORT_INITIALIZER { \ .global_lock = NULL, \ .local_lock = NULL, \ .release_state = CK_COHORT_STATE_GLOBAL, \ .waiting_threads = 0, \ .acquire_count = 0, \ .local_pass_limit = CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT \ } #endif /* CK_COHORT_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_elide.h ================================================ /* * Copyright 2013-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_ELIDE_H #define CK_ELIDE_H /* * As RTM is currently only supported on TSO x86 architectures, * fences have been omitted. They will be necessary for other * non-TSO architectures with TM support. */ #include #include #include /* * skip_-prefixed counters represent the number of consecutive * elisions to forfeit. retry_-prefixed counters represent the * number of elision retries to attempt before forfeit. * * _busy: Lock was busy * _other: Unknown explicit abort * _conflict: Data conflict in elision section */ struct ck_elide_config { unsigned short skip_busy; short retry_busy; unsigned short skip_other; short retry_other; unsigned short skip_conflict; short retry_conflict; }; #define CK_ELIDE_CONFIG_DEFAULT_INITIALIZER { \ .skip_busy = 5, \ .retry_busy = 256, \ .skip_other = 3, \ .retry_other = 3, \ .skip_conflict = 2, \ .retry_conflict = 5 \ } struct ck_elide_stat { unsigned int n_fallback; unsigned int n_elide; unsigned short skip; }; typedef struct ck_elide_stat ck_elide_stat_t; #define CK_ELIDE_STAT_INITIALIZER { 0, 0, 0 } CK_CC_INLINE static void ck_elide_stat_init(ck_elide_stat_t *st) { memset(st, 0, sizeof(*st)); return; } #ifdef CK_F_PR_RTM enum _ck_elide_hint { CK_ELIDE_HINT_RETRY = 0, CK_ELIDE_HINT_SPIN, CK_ELIDE_HINT_STOP }; #define CK_ELIDE_LOCK_BUSY 0xFF static enum _ck_elide_hint _ck_elide_fallback(int *retry, struct ck_elide_stat *st, struct ck_elide_config *c, unsigned int status) { st->n_fallback++; if (*retry > 0) return CK_ELIDE_HINT_RETRY; if (st->skip != 0) return CK_ELIDE_HINT_STOP; if (status & CK_PR_RTM_EXPLICIT) { if (CK_PR_RTM_CODE(status) == CK_ELIDE_LOCK_BUSY) { st->skip = c->skip_busy; *retry = c->retry_busy; return CK_ELIDE_HINT_SPIN; } st->skip = c->skip_other; return CK_ELIDE_HINT_STOP; } if ((status & CK_PR_RTM_RETRY) && (status & CK_PR_RTM_CONFLICT)) { st->skip = c->skip_conflict; *retry = c->retry_conflict; return CK_ELIDE_HINT_RETRY; } /* * Capacity, debug and nesting abortions are likely to be * invariant conditions for the acquisition, execute regular * path instead. If retry bit is not set, then take the hint. */ st->skip = USHRT_MAX; return CK_ELIDE_HINT_STOP; } /* * Defines an elision implementation according to the following variables: * N - Namespace of elision implementation. * T - Typename of mutex. * L_P - Lock predicate, returns false if resource is available. * L - Function to call if resource is unavailable of transaction aborts. * U_P - Unlock predicate, returns false if elision failed. * U - Function to call if transaction failed. */ #define CK_ELIDE_PROTOTYPE(N, T, L_P, L, U_P, U) \ CK_CC_INLINE static void \ ck_elide_##N##_lock_adaptive(T *lock, \ struct ck_elide_stat *st, \ struct ck_elide_config *c) \ { \ enum _ck_elide_hint hint; \ int retry; \ \ if (CK_CC_UNLIKELY(st->skip != 0)) { \ st->skip--; \ goto acquire; \ } \ \ retry = c->retry_conflict; \ do { \ unsigned int status = ck_pr_rtm_begin(); \ if (status == CK_PR_RTM_STARTED) { \ if (L_P(lock) == true) \ ck_pr_rtm_abort(CK_ELIDE_LOCK_BUSY); \ \ return; \ } \ \ hint = _ck_elide_fallback(&retry, st, c, status); \ if (hint == CK_ELIDE_HINT_RETRY) \ continue; \ \ if (hint == CK_ELIDE_HINT_SPIN) { \ while (--retry != 0) { \ if (L_P(lock) == false) \ break; \ \ ck_pr_stall(); \ } \ \ continue; \ } \ \ if (hint == CK_ELIDE_HINT_STOP) \ break; \ } while (CK_CC_LIKELY(--retry > 0)); \ \ acquire: \ L(lock); \ return; \ } \ CK_CC_INLINE static void \ ck_elide_##N##_unlock_adaptive(struct ck_elide_stat *st, T *lock) \ { \ \ if (U_P(lock) == false) { \ ck_pr_rtm_end(); \ st->skip = 0; \ st->n_elide++; \ } else { \ U(lock); \ } \ \ return; \ } \ CK_CC_INLINE static void \ ck_elide_##N##_lock(T *lock) \ { \ \ if (ck_pr_rtm_begin() != CK_PR_RTM_STARTED) { \ L(lock); \ return; \ } \ \ if (L_P(lock) == true) \ ck_pr_rtm_abort(CK_ELIDE_LOCK_BUSY); \ \ return; \ } \ CK_CC_INLINE static void \ ck_elide_##N##_unlock(T *lock) \ { \ \ if (U_P(lock) == false) { \ ck_pr_rtm_end(); \ } else { \ U(lock); \ } \ \ return; \ } #define CK_ELIDE_TRYLOCK_PROTOTYPE(N, T, TL_P, TL) \ CK_CC_INLINE static bool \ ck_elide_##N##_trylock(T *lock) \ { \ \ if (ck_pr_rtm_begin() != CK_PR_RTM_STARTED) \ return false; \ \ if (TL_P(lock) == true) \ ck_pr_rtm_abort(CK_ELIDE_LOCK_BUSY); \ \ return true; \ } #else /* * If RTM is not enabled on the target platform (CK_F_PR_RTM) then these * elision wrappers directly calls into the user-specified lock operations. * Unfortunately, the storage cost of both ck_elide_config and ck_elide_stat * are paid (typically a storage cost that is a function of lock objects and * thread count). */ #define CK_ELIDE_PROTOTYPE(N, T, L_P, L, U_P, U) \ CK_CC_INLINE static void \ ck_elide_##N##_lock_adaptive(T *lock, \ struct ck_elide_stat *st, \ struct ck_elide_config *c) \ { \ \ (void)st; \ (void)c; \ L(lock); \ return; \ } \ CK_CC_INLINE static void \ ck_elide_##N##_unlock_adaptive(struct ck_elide_stat *st, \ T *lock) \ { \ \ (void)st; \ U(lock); \ return; \ } \ CK_CC_INLINE static void \ ck_elide_##N##_lock(T *lock) \ { \ \ L(lock); \ return; \ } \ CK_CC_INLINE static void \ ck_elide_##N##_unlock(T *lock) \ { \ \ U(lock); \ return; \ } #define CK_ELIDE_TRYLOCK_PROTOTYPE(N, T, TL_P, TL) \ CK_CC_INLINE static bool \ ck_elide_##N##_trylock(T *lock) \ { \ \ return TL_P(lock); \ } #endif /* !CK_F_PR_RTM */ /* * Best-effort elision lock operations. First argument is name (N) * associated with implementation and the second is a pointer to * the type specified above (T). * * Unlike the adaptive variant, this interface does not have any retry * semantics. In environments where jitter is low, this may yield a tighter * fast path. */ #define CK_ELIDE_LOCK(NAME, LOCK) ck_elide_##NAME##_lock(LOCK) #define CK_ELIDE_UNLOCK(NAME, LOCK) ck_elide_##NAME##_unlock(LOCK) #define CK_ELIDE_TRYLOCK(NAME, LOCK) ck_elide_##NAME##_trylock(LOCK) /* * Adaptive elision lock operations. In addition to name and pointer * to the lock, you must pass in a pointer to an initialized * ck_elide_config structure along with a per-thread stat structure. */ #define CK_ELIDE_LOCK_ADAPTIVE(NAME, STAT, CONFIG, LOCK) \ ck_elide_##NAME##_lock_adaptive(LOCK, STAT, CONFIG) #define CK_ELIDE_UNLOCK_ADAPTIVE(NAME, STAT, LOCK) \ ck_elide_##NAME##_unlock_adaptive(STAT, LOCK) #endif /* CK_ELIDE_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_epoch.h ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_EPOCH_H #define CK_EPOCH_H /* * The implementation here is inspired from the work described in: * Fraser, K. 2004. Practical Lock-Freedom. PhD Thesis, University * of Cambridge Computing Laboratory. */ #include #include #include #include #include #ifndef CK_EPOCH_LENGTH #define CK_EPOCH_LENGTH 4 #endif /* * This is used for sense detection with-respect to concurrent * epoch sections. */ #define CK_EPOCH_SENSE (2) struct ck_epoch_entry; typedef struct ck_epoch_entry ck_epoch_entry_t; typedef void ck_epoch_cb_t(ck_epoch_entry_t *); /* * This should be embedded into objects you wish to be the target of * ck_epoch_cb_t functions (with ck_epoch_call). */ struct ck_epoch_entry { ck_epoch_cb_t *function; ck_stack_entry_t stack_entry; }; /* * A section object may be passed to every begin-end pair to allow for * forward progress guarantees with-in prolonged active sections. */ struct ck_epoch_section { unsigned int bucket; }; typedef struct ck_epoch_section ck_epoch_section_t; /* * Return pointer to ck_epoch_entry container object. */ #define CK_EPOCH_CONTAINER(T, M, N) \ CK_CC_CONTAINER(struct ck_epoch_entry, T, M, N) struct ck_epoch_ref { unsigned int epoch; unsigned int count; }; struct ck_epoch_record { ck_stack_entry_t record_next; struct ck_epoch *global; unsigned int state; unsigned int epoch; unsigned int active; struct { struct ck_epoch_ref bucket[CK_EPOCH_SENSE]; } local CK_CC_CACHELINE; unsigned int n_pending; unsigned int n_peak; unsigned int n_dispatch; void *ct; ck_stack_t pending[CK_EPOCH_LENGTH]; } CK_CC_CACHELINE; typedef struct ck_epoch_record ck_epoch_record_t; struct ck_epoch { unsigned int epoch; unsigned int n_free; ck_stack_t records; }; typedef struct ck_epoch ck_epoch_t; /* * Internal functions. */ void _ck_epoch_addref(ck_epoch_record_t *, ck_epoch_section_t *); bool _ck_epoch_delref(ck_epoch_record_t *, ck_epoch_section_t *); CK_CC_FORCE_INLINE static void * ck_epoch_record_ct(const ck_epoch_record_t *record) { return ck_pr_load_ptr(&record->ct); } /* * Marks the beginning of an epoch-protected section. */ CK_CC_FORCE_INLINE static void ck_epoch_begin(ck_epoch_record_t *record, ck_epoch_section_t *section) { struct ck_epoch *epoch = record->global; /* * Only observe new epoch if thread is not recursing into a read * section. */ if (record->active == 0) { unsigned int g_epoch; /* * It is possible for loads to be re-ordered before the store * is committed into the caller's epoch and active fields. * For this reason, store to load serialization is necessary. */ #if defined(CK_MD_TSO) ck_pr_fas_uint(&record->active, 1); ck_pr_fence_atomic_load(); #else ck_pr_store_uint(&record->active, 1); ck_pr_fence_memory(); #endif /* * This load is allowed to be re-ordered prior to setting * active flag due to monotonic nature of the global epoch. * However, stale values lead to measurable performance * degradation in some torture tests so we disallow early load * of global epoch. */ g_epoch = ck_pr_load_uint(&epoch->epoch); ck_pr_store_uint(&record->epoch, g_epoch); } else { ck_pr_store_uint(&record->active, record->active + 1); } if (section != NULL) _ck_epoch_addref(record, section); return; } /* * Marks the end of an epoch-protected section. Returns true if no more * sections exist for the caller. */ CK_CC_FORCE_INLINE static bool ck_epoch_end(ck_epoch_record_t *record, ck_epoch_section_t *section) { ck_pr_fence_release(); ck_pr_store_uint(&record->active, record->active - 1); if (section != NULL) return _ck_epoch_delref(record, section); return record->active == 0; } /* * Defers the execution of the function pointed to by the "cb" * argument until an epoch counter loop. This allows for a * non-blocking deferral. * * We can get away without a fence here due to the monotonic nature * of the epoch counter. Worst case, this will result in some delays * before object destruction. */ CK_CC_FORCE_INLINE static void ck_epoch_call(ck_epoch_record_t *record, ck_epoch_entry_t *entry, ck_epoch_cb_t *function) { struct ck_epoch *epoch = record->global; unsigned int e = ck_pr_load_uint(&epoch->epoch); unsigned int offset = e & (CK_EPOCH_LENGTH - 1); record->n_pending++; entry->function = function; ck_stack_push_spnc(&record->pending[offset], &entry->stack_entry); return; } /* * Same as ck_epoch_call, but allows for records to be shared and is reentrant. */ CK_CC_FORCE_INLINE static void ck_epoch_call_strict(ck_epoch_record_t *record, ck_epoch_entry_t *entry, ck_epoch_cb_t *function) { struct ck_epoch *epoch = record->global; unsigned int e = ck_pr_load_uint(&epoch->epoch); unsigned int offset = e & (CK_EPOCH_LENGTH - 1); ck_pr_inc_uint(&record->n_pending); entry->function = function; /* Store fence is implied by push operation. */ ck_stack_push_upmc(&record->pending[offset], &entry->stack_entry); return; } /* * This callback is used for synchronize_wait to allow for custom blocking * behavior. */ typedef void ck_epoch_wait_cb_t(ck_epoch_t *, ck_epoch_record_t *, void *); /* * Return latest epoch value. This operation provides load ordering. */ CK_CC_FORCE_INLINE static unsigned int ck_epoch_value(const ck_epoch_t *ep) { ck_pr_fence_load(); return ck_pr_load_uint(&ep->epoch); } void ck_epoch_init(ck_epoch_t *); /* * Attempts to recycle an unused epoch record. If one is successfully * allocated, the record context pointer is also updated. */ ck_epoch_record_t *ck_epoch_recycle(ck_epoch_t *, void *); /* * Registers an epoch record. An optional context pointer may be passed that * is retrievable with ck_epoch_record_ct. */ void ck_epoch_register(ck_epoch_t *, ck_epoch_record_t *, void *); /* * Marks a record as available for re-use by a subsequent recycle operation. * Note that the record cannot be physically destroyed. */ void ck_epoch_unregister(ck_epoch_record_t *); bool ck_epoch_poll(ck_epoch_record_t *); void ck_epoch_synchronize(ck_epoch_record_t *); void ck_epoch_synchronize_wait(ck_epoch_t *, ck_epoch_wait_cb_t *, void *); void ck_epoch_barrier(ck_epoch_record_t *); void ck_epoch_barrier_wait(ck_epoch_record_t *, ck_epoch_wait_cb_t *, void *); /* * Reclaim entries associated with a record. This is safe to call only on * the caller's record or records that are using call_strict. */ void ck_epoch_reclaim(ck_epoch_record_t *); #endif /* CK_EPOCH_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_fifo.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_FIFO_H #define CK_FIFO_H #include #include #include #include #include #ifndef CK_F_FIFO_SPSC #define CK_F_FIFO_SPSC struct ck_fifo_spsc_entry { void *value; struct ck_fifo_spsc_entry *next; }; typedef struct ck_fifo_spsc_entry ck_fifo_spsc_entry_t; struct ck_fifo_spsc { ck_spinlock_t m_head; struct ck_fifo_spsc_entry *head; char pad[CK_MD_CACHELINE - sizeof(struct ck_fifo_spsc_entry *) - sizeof(ck_spinlock_t)]; ck_spinlock_t m_tail; struct ck_fifo_spsc_entry *tail; struct ck_fifo_spsc_entry *head_snapshot; struct ck_fifo_spsc_entry *garbage; }; typedef struct ck_fifo_spsc ck_fifo_spsc_t; CK_CC_INLINE static bool ck_fifo_spsc_enqueue_trylock(struct ck_fifo_spsc *fifo) { return ck_spinlock_trylock(&fifo->m_tail); } CK_CC_INLINE static void ck_fifo_spsc_enqueue_lock(struct ck_fifo_spsc *fifo) { ck_spinlock_lock(&fifo->m_tail); return; } CK_CC_INLINE static void ck_fifo_spsc_enqueue_unlock(struct ck_fifo_spsc *fifo) { ck_spinlock_unlock(&fifo->m_tail); return; } CK_CC_INLINE static bool ck_fifo_spsc_dequeue_trylock(struct ck_fifo_spsc *fifo) { return ck_spinlock_trylock(&fifo->m_head); } CK_CC_INLINE static void ck_fifo_spsc_dequeue_lock(struct ck_fifo_spsc *fifo) { ck_spinlock_lock(&fifo->m_head); return; } CK_CC_INLINE static void ck_fifo_spsc_dequeue_unlock(struct ck_fifo_spsc *fifo) { ck_spinlock_unlock(&fifo->m_head); return; } CK_CC_INLINE static void ck_fifo_spsc_init(struct ck_fifo_spsc *fifo, struct ck_fifo_spsc_entry *stub) { ck_spinlock_init(&fifo->m_head); ck_spinlock_init(&fifo->m_tail); stub->next = NULL; fifo->head = fifo->tail = fifo->head_snapshot = fifo->garbage = stub; return; } CK_CC_INLINE static void ck_fifo_spsc_deinit(struct ck_fifo_spsc *fifo, struct ck_fifo_spsc_entry **garbage) { *garbage = fifo->head; fifo->head = fifo->tail = NULL; return; } CK_CC_INLINE static void ck_fifo_spsc_enqueue(struct ck_fifo_spsc *fifo, struct ck_fifo_spsc_entry *entry, void *value) { entry->value = value; entry->next = NULL; /* If stub->next is visible, guarantee that entry is consistent. */ ck_pr_fence_store(); ck_pr_store_ptr(&fifo->tail->next, entry); fifo->tail = entry; return; } CK_CC_INLINE static bool ck_fifo_spsc_dequeue(struct ck_fifo_spsc *fifo, void *value) { struct ck_fifo_spsc_entry *entry; /* * The head pointer is guaranteed to always point to a stub entry. * If the stub entry does not point to an entry, then the queue is * empty. */ entry = ck_pr_load_ptr(&fifo->head->next); if (entry == NULL) return false; /* If entry is visible, guarantee store to value is visible. */ ck_pr_store_ptr_unsafe(value, entry->value); ck_pr_fence_store(); ck_pr_store_ptr(&fifo->head, entry); return true; } /* * Recycle a node. This technique for recycling nodes is based on * Dmitriy Vyukov's work. */ CK_CC_INLINE static struct ck_fifo_spsc_entry * ck_fifo_spsc_recycle(struct ck_fifo_spsc *fifo) { struct ck_fifo_spsc_entry *garbage; if (fifo->head_snapshot == fifo->garbage) { fifo->head_snapshot = ck_pr_load_ptr(&fifo->head); if (fifo->head_snapshot == fifo->garbage) return NULL; } garbage = fifo->garbage; fifo->garbage = garbage->next; return garbage; } CK_CC_INLINE static bool ck_fifo_spsc_isempty(struct ck_fifo_spsc *fifo) { struct ck_fifo_spsc_entry *head = ck_pr_load_ptr(&fifo->head); return ck_pr_load_ptr(&head->next) == NULL; } #define CK_FIFO_SPSC_ISEMPTY(f) ((f)->head->next == NULL) #define CK_FIFO_SPSC_FIRST(f) ((f)->head->next) #define CK_FIFO_SPSC_NEXT(m) ((m)->next) #define CK_FIFO_SPSC_SPARE(f) ((f)->head) #define CK_FIFO_SPSC_FOREACH(fifo, entry) \ for ((entry) = CK_FIFO_SPSC_FIRST(fifo); \ (entry) != NULL; \ (entry) = CK_FIFO_SPSC_NEXT(entry)) #define CK_FIFO_SPSC_FOREACH_SAFE(fifo, entry, T) \ for ((entry) = CK_FIFO_SPSC_FIRST(fifo); \ (entry) != NULL && ((T) = (entry)->next, 1); \ (entry) = (T)) #endif /* CK_F_FIFO_SPSC */ #ifdef CK_F_PR_CAS_PTR_2 #ifndef CK_F_FIFO_MPMC #define CK_F_FIFO_MPMC struct ck_fifo_mpmc_entry; struct ck_fifo_mpmc_pointer { struct ck_fifo_mpmc_entry *pointer; char *generation CK_CC_PACKED; } CK_CC_ALIGN(16); struct ck_fifo_mpmc_entry { void *value; struct ck_fifo_mpmc_pointer next; }; typedef struct ck_fifo_mpmc_entry ck_fifo_mpmc_entry_t; struct ck_fifo_mpmc { struct ck_fifo_mpmc_pointer head; char pad[CK_MD_CACHELINE - sizeof(struct ck_fifo_mpmc_pointer)]; struct ck_fifo_mpmc_pointer tail; }; typedef struct ck_fifo_mpmc ck_fifo_mpmc_t; CK_CC_INLINE static void ck_fifo_mpmc_init(struct ck_fifo_mpmc *fifo, struct ck_fifo_mpmc_entry *stub) { stub->next.pointer = NULL; stub->next.generation = NULL; fifo->head.pointer = fifo->tail.pointer = stub; fifo->head.generation = fifo->tail.generation = NULL; return; } CK_CC_INLINE static void ck_fifo_mpmc_deinit(struct ck_fifo_mpmc *fifo, struct ck_fifo_mpmc_entry **garbage) { *garbage = fifo->head.pointer; fifo->head.pointer = fifo->tail.pointer = NULL; return; } CK_CC_INLINE static void ck_fifo_mpmc_enqueue(struct ck_fifo_mpmc *fifo, struct ck_fifo_mpmc_entry *entry, void *value) { struct ck_fifo_mpmc_pointer tail, next, update; /* * Prepare the upcoming node and make sure to commit the updates * before publishing. */ entry->value = value; entry->next.pointer = NULL; entry->next.generation = 0; ck_pr_fence_store_atomic(); for (;;) { tail.generation = ck_pr_load_ptr(&fifo->tail.generation); ck_pr_fence_load(); tail.pointer = ck_pr_load_ptr(&fifo->tail.pointer); next.generation = ck_pr_load_ptr(&tail.pointer->next.generation); ck_pr_fence_load(); next.pointer = ck_pr_load_ptr(&tail.pointer->next.pointer); if (ck_pr_load_ptr(&fifo->tail.generation) != tail.generation) continue; if (next.pointer != NULL) { /* * If the tail pointer has an entry following it then * it needs to be forwarded to the next entry. This * helps us guarantee we are always operating on the * last entry. */ update.pointer = next.pointer; update.generation = tail.generation + 1; ck_pr_cas_ptr_2(&fifo->tail, &tail, &update); } else { /* * Attempt to commit new entry to the end of the * current tail. */ update.pointer = entry; update.generation = next.generation + 1; if (ck_pr_cas_ptr_2(&tail.pointer->next, &next, &update) == true) break; } } ck_pr_fence_atomic(); /* After a successful insert, forward the tail to the new entry. */ update.generation = tail.generation + 1; ck_pr_cas_ptr_2(&fifo->tail, &tail, &update); return; } CK_CC_INLINE static bool ck_fifo_mpmc_tryenqueue(struct ck_fifo_mpmc *fifo, struct ck_fifo_mpmc_entry *entry, void *value) { struct ck_fifo_mpmc_pointer tail, next, update; entry->value = value; entry->next.pointer = NULL; entry->next.generation = 0; ck_pr_fence_store_atomic(); tail.generation = ck_pr_load_ptr(&fifo->tail.generation); ck_pr_fence_load(); tail.pointer = ck_pr_load_ptr(&fifo->tail.pointer); next.generation = ck_pr_load_ptr(&tail.pointer->next.generation); ck_pr_fence_load(); next.pointer = ck_pr_load_ptr(&tail.pointer->next.pointer); if (ck_pr_load_ptr(&fifo->tail.generation) != tail.generation) return false; if (next.pointer != NULL) { /* * If the tail pointer has an entry following it then * it needs to be forwarded to the next entry. This * helps us guarantee we are always operating on the * last entry. */ update.pointer = next.pointer; update.generation = tail.generation + 1; ck_pr_cas_ptr_2(&fifo->tail, &tail, &update); return false; } else { /* * Attempt to commit new entry to the end of the * current tail. */ update.pointer = entry; update.generation = next.generation + 1; if (ck_pr_cas_ptr_2(&tail.pointer->next, &next, &update) == false) return false; } ck_pr_fence_atomic(); /* After a successful insert, forward the tail to the new entry. */ update.generation = tail.generation + 1; ck_pr_cas_ptr_2(&fifo->tail, &tail, &update); return true; } CK_CC_INLINE static bool ck_fifo_mpmc_dequeue(struct ck_fifo_mpmc *fifo, void *value, struct ck_fifo_mpmc_entry **garbage) { struct ck_fifo_mpmc_pointer head, tail, next, update; for (;;) { head.generation = ck_pr_load_ptr(&fifo->head.generation); ck_pr_fence_load(); head.pointer = ck_pr_load_ptr(&fifo->head.pointer); tail.generation = ck_pr_load_ptr(&fifo->tail.generation); ck_pr_fence_load(); tail.pointer = ck_pr_load_ptr(&fifo->tail.pointer); next.generation = ck_pr_load_ptr(&head.pointer->next.generation); ck_pr_fence_load(); next.pointer = ck_pr_load_ptr(&head.pointer->next.pointer); update.pointer = next.pointer; if (head.pointer == tail.pointer) { /* * The head is guaranteed to always point at a stub * entry. If the stub entry has no references then the * queue is empty. */ if (next.pointer == NULL) return false; /* Forward the tail pointer if necessary. */ update.generation = tail.generation + 1; ck_pr_cas_ptr_2(&fifo->tail, &tail, &update); } else { /* * It is possible for head snapshot to have been * re-used. Avoid deferencing during enqueue * re-use. */ if (next.pointer == NULL) continue; /* Save value before commit. */ *(void **)value = ck_pr_load_ptr(&next.pointer->value); /* Forward the head pointer to the next entry. */ update.generation = head.generation + 1; if (ck_pr_cas_ptr_2(&fifo->head, &head, &update) == true) break; } } *garbage = head.pointer; return true; } CK_CC_INLINE static bool ck_fifo_mpmc_trydequeue(struct ck_fifo_mpmc *fifo, void *value, struct ck_fifo_mpmc_entry **garbage) { struct ck_fifo_mpmc_pointer head, tail, next, update; head.generation = ck_pr_load_ptr(&fifo->head.generation); ck_pr_fence_load(); head.pointer = ck_pr_load_ptr(&fifo->head.pointer); tail.generation = ck_pr_load_ptr(&fifo->tail.generation); ck_pr_fence_load(); tail.pointer = ck_pr_load_ptr(&fifo->tail.pointer); next.generation = ck_pr_load_ptr(&head.pointer->next.generation); ck_pr_fence_load(); next.pointer = ck_pr_load_ptr(&head.pointer->next.pointer); update.pointer = next.pointer; if (head.pointer == tail.pointer) { /* * The head is guaranteed to always point at a stub * entry. If the stub entry has no references then the * queue is empty. */ if (next.pointer == NULL) return false; /* Forward the tail pointer if necessary. */ update.generation = tail.generation + 1; ck_pr_cas_ptr_2(&fifo->tail, &tail, &update); return false; } else { /* * It is possible for head snapshot to have been * re-used. Avoid deferencing during enqueue. */ if (next.pointer == NULL) return false; /* Save value before commit. */ *(void **)value = ck_pr_load_ptr(&next.pointer->value); /* Forward the head pointer to the next entry. */ update.generation = head.generation + 1; if (ck_pr_cas_ptr_2(&fifo->head, &head, &update) == false) return false; } *garbage = head.pointer; return true; } #define CK_FIFO_MPMC_ISEMPTY(f) ((f)->head.pointer->next.pointer == NULL) #define CK_FIFO_MPMC_FIRST(f) ((f)->head.pointer->next.pointer) #define CK_FIFO_MPMC_NEXT(m) ((m)->next.pointer) #define CK_FIFO_MPMC_FOREACH(fifo, entry) \ for ((entry) = CK_FIFO_MPMC_FIRST(fifo); \ (entry) != NULL; \ (entry) = CK_FIFO_MPMC_NEXT(entry)) #define CK_FIFO_MPMC_FOREACH_SAFE(fifo, entry, T) \ for ((entry) = CK_FIFO_MPMC_FIRST(fifo); \ (entry) != NULL && ((T) = (entry)->next.pointer, 1); \ (entry) = (T)) #endif /* CK_F_FIFO_MPMC */ #endif /* CK_F_PR_CAS_PTR_2 */ #endif /* CK_FIFO_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_hp.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_HP_H #define CK_HP_H #include #include #include #include #ifndef CK_HP_CACHE #define CK_HP_CACHE 512 #endif struct ck_hp_hazard; typedef void (*ck_hp_destructor_t)(void *); struct ck_hp { ck_stack_t subscribers; unsigned int n_subscribers; unsigned int n_free; unsigned int threshold; unsigned int degree; ck_hp_destructor_t destroy; }; typedef struct ck_hp ck_hp_t; struct ck_hp_hazard { void *pointer; void *data; ck_stack_entry_t pending_entry; }; typedef struct ck_hp_hazard ck_hp_hazard_t; enum { CK_HP_USED = 0, CK_HP_FREE = 1 }; struct ck_hp_record { int state; void **pointers; void *cache[CK_HP_CACHE]; struct ck_hp *global; ck_stack_t pending; unsigned int n_pending; ck_stack_entry_t global_entry; unsigned int n_peak; uint64_t n_reclamations; } CK_CC_CACHELINE; typedef struct ck_hp_record ck_hp_record_t; CK_CC_INLINE static void ck_hp_set(struct ck_hp_record *record, unsigned int i, void *pointer) { ck_pr_store_ptr(&record->pointers[i], pointer); return; } CK_CC_INLINE static void ck_hp_set_fence(struct ck_hp_record *record, unsigned int i, void *pointer) { #ifdef CK_MD_TSO ck_pr_fas_ptr(&record->pointers[i], pointer); #else ck_pr_store_ptr(&record->pointers[i], pointer); ck_pr_fence_memory(); #endif return; } CK_CC_INLINE static void ck_hp_clear(struct ck_hp_record *record) { void **pointers = record->pointers; unsigned int i; for (i = 0; i < record->global->degree; i++) *pointers++ = NULL; return; } void ck_hp_init(ck_hp_t *, unsigned int, unsigned int, ck_hp_destructor_t); void ck_hp_set_threshold(ck_hp_t *, unsigned int); void ck_hp_register(ck_hp_t *, ck_hp_record_t *, void **); void ck_hp_unregister(ck_hp_record_t *); ck_hp_record_t *ck_hp_recycle(ck_hp_t *); void ck_hp_reclaim(ck_hp_record_t *); void ck_hp_free(ck_hp_record_t *, ck_hp_hazard_t *, void *, void *); void ck_hp_retire(ck_hp_record_t *, ck_hp_hazard_t *, void *, void *); void ck_hp_purge(ck_hp_record_t *); #endif /* CK_HP_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_hp_fifo.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_HP_FIFO_H #define CK_HP_FIFO_H #include #include #include #include #define CK_HP_FIFO_SLOTS_COUNT (2) #define CK_HP_FIFO_SLOTS_SIZE (sizeof(void *) * CK_HP_FIFO_SLOTS_COUNT) /* * Though it is possible to embed the data structure, measurements need * to be made for the cost of this. If we were to embed the hazard pointer * state into the data structure, this means every deferred reclamation * will also include a cache invalidation when linking into the hazard pointer * pending queue. This may lead to terrible cache line bouncing. */ struct ck_hp_fifo_entry { void *value; ck_hp_hazard_t hazard; struct ck_hp_fifo_entry *next; }; typedef struct ck_hp_fifo_entry ck_hp_fifo_entry_t; struct ck_hp_fifo { struct ck_hp_fifo_entry *head; struct ck_hp_fifo_entry *tail; }; typedef struct ck_hp_fifo ck_hp_fifo_t; CK_CC_INLINE static void ck_hp_fifo_init(struct ck_hp_fifo *fifo, struct ck_hp_fifo_entry *stub) { fifo->head = fifo->tail = stub; stub->next = NULL; return; } CK_CC_INLINE static void ck_hp_fifo_deinit(struct ck_hp_fifo *fifo, struct ck_hp_fifo_entry **stub) { *stub = fifo->head; fifo->head = fifo->tail = NULL; return; } CK_CC_INLINE static void ck_hp_fifo_enqueue_mpmc(ck_hp_record_t *record, struct ck_hp_fifo *fifo, struct ck_hp_fifo_entry *entry, void *value) { struct ck_hp_fifo_entry *tail, *next; entry->value = value; entry->next = NULL; ck_pr_fence_store_atomic(); for (;;) { tail = ck_pr_load_ptr(&fifo->tail); ck_hp_set_fence(record, 0, tail); if (tail != ck_pr_load_ptr(&fifo->tail)) continue; next = ck_pr_load_ptr(&tail->next); if (next != NULL) { ck_pr_cas_ptr(&fifo->tail, tail, next); continue; } else if (ck_pr_cas_ptr(&fifo->tail->next, next, entry) == true) break; } ck_pr_fence_atomic(); ck_pr_cas_ptr(&fifo->tail, tail, entry); return; } CK_CC_INLINE static bool ck_hp_fifo_tryenqueue_mpmc(ck_hp_record_t *record, struct ck_hp_fifo *fifo, struct ck_hp_fifo_entry *entry, void *value) { struct ck_hp_fifo_entry *tail, *next; entry->value = value; entry->next = NULL; ck_pr_fence_store_atomic(); tail = ck_pr_load_ptr(&fifo->tail); ck_hp_set_fence(record, 0, tail); if (tail != ck_pr_load_ptr(&fifo->tail)) return false; next = ck_pr_load_ptr(&tail->next); if (next != NULL) { ck_pr_cas_ptr(&fifo->tail, tail, next); return false; } else if (ck_pr_cas_ptr(&fifo->tail->next, next, entry) == false) return false; ck_pr_fence_atomic(); ck_pr_cas_ptr(&fifo->tail, tail, entry); return true; } CK_CC_INLINE static struct ck_hp_fifo_entry * ck_hp_fifo_dequeue_mpmc(ck_hp_record_t *record, struct ck_hp_fifo *fifo, void *value) { struct ck_hp_fifo_entry *head, *tail, *next; for (;;) { head = ck_pr_load_ptr(&fifo->head); ck_pr_fence_load(); tail = ck_pr_load_ptr(&fifo->tail); ck_hp_set_fence(record, 0, head); if (head != ck_pr_load_ptr(&fifo->head)) continue; next = ck_pr_load_ptr(&head->next); ck_hp_set_fence(record, 1, next); if (head != ck_pr_load_ptr(&fifo->head)) continue; if (head == tail) { if (next == NULL) return NULL; ck_pr_cas_ptr(&fifo->tail, tail, next); continue; } else if (ck_pr_cas_ptr(&fifo->head, head, next) == true) break; } ck_pr_store_ptr_unsafe(value, next->value); return head; } CK_CC_INLINE static struct ck_hp_fifo_entry * ck_hp_fifo_trydequeue_mpmc(ck_hp_record_t *record, struct ck_hp_fifo *fifo, void *value) { struct ck_hp_fifo_entry *head, *tail, *next; head = ck_pr_load_ptr(&fifo->head); ck_pr_fence_load(); tail = ck_pr_load_ptr(&fifo->tail); ck_hp_set_fence(record, 0, head); if (head != ck_pr_load_ptr(&fifo->head)) return NULL; next = ck_pr_load_ptr(&head->next); ck_hp_set_fence(record, 1, next); if (head != ck_pr_load_ptr(&fifo->head)) return NULL; if (head == tail) { if (next == NULL) return NULL; ck_pr_cas_ptr(&fifo->tail, tail, next); return NULL; } else if (ck_pr_cas_ptr(&fifo->head, head, next) == false) return NULL; ck_pr_store_ptr_unsafe(value, next->value); return head; } #define CK_HP_FIFO_ISEMPTY(f) ((f)->head->next == NULL) #define CK_HP_FIFO_FIRST(f) ((f)->head->next) #define CK_HP_FIFO_NEXT(m) ((m)->next) #define CK_HP_FIFO_FOREACH(fifo, entry) \ for ((entry) = CK_HP_FIFO_FIRST(fifo); \ (entry) != NULL; \ (entry) = CK_HP_FIFO_NEXT(entry)) #define CK_HP_FIFO_FOREACH_SAFE(fifo, entry, T) \ for ((entry) = CK_HP_FIFO_FIRST(fifo); \ (entry) != NULL && ((T) = (entry)->next, 1); \ (entry) = (T)) #endif /* CK_HP_FIFO_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_hp_stack.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_HP_STACK_H #define CK_HP_STACK_H #include #include #include #include #include #define CK_HP_STACK_SLOTS_COUNT 1 #define CK_HP_STACK_SLOTS_SIZE sizeof(void *) CK_CC_INLINE static void ck_hp_stack_push_mpmc(struct ck_stack *target, struct ck_stack_entry *entry) { ck_stack_push_upmc(target, entry); return; } CK_CC_INLINE static bool ck_hp_stack_trypush_mpmc(struct ck_stack *target, struct ck_stack_entry *entry) { return ck_stack_trypush_upmc(target, entry); } CK_CC_INLINE static struct ck_stack_entry * ck_hp_stack_pop_mpmc(ck_hp_record_t *record, struct ck_stack *target) { struct ck_stack_entry *entry, *update; do { entry = ck_pr_load_ptr(&target->head); if (entry == NULL) return NULL; ck_hp_set_fence(record, 0, entry); } while (entry != ck_pr_load_ptr(&target->head)); while (ck_pr_cas_ptr_value(&target->head, entry, entry->next, &entry) == false) { if (entry == NULL) return NULL; ck_hp_set_fence(record, 0, entry); update = ck_pr_load_ptr(&target->head); while (entry != update) { ck_hp_set_fence(record, 0, update); entry = update; update = ck_pr_load_ptr(&target->head); if (update == NULL) return NULL; } } return entry; } CK_CC_INLINE static bool ck_hp_stack_trypop_mpmc(ck_hp_record_t *record, struct ck_stack *target, struct ck_stack_entry **r) { struct ck_stack_entry *entry; entry = ck_pr_load_ptr(&target->head); if (entry == NULL) return false; ck_hp_set_fence(record, 0, entry); if (entry != ck_pr_load_ptr(&target->head)) goto leave; if (ck_pr_cas_ptr_value(&target->head, entry, entry->next, &entry) == false) goto leave; *r = entry; return true; leave: ck_hp_set(record, 0, NULL); return false; } #endif /* CK_HP_STACK_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_hs.h ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_HS_H #define CK_HS_H #include #include #include #include #include #include #include /* * Indicates a single-writer many-reader workload. Mutually * exclusive with CK_HS_MODE_MPMC */ #define CK_HS_MODE_SPMC 1 /* * Indicates that values to be stored are not pointers but * values. Allows for full precision. Mutually exclusive * with CK_HS_MODE_OBJECT. */ #define CK_HS_MODE_DIRECT 2 /* * Indicates that the values to be stored are pointers. * Allows for space optimizations in the presence of pointer * packing. Mutually exclusive with CK_HS_MODE_DIRECT. */ #define CK_HS_MODE_OBJECT 8 /* * Indicates a delete-heavy workload. This will reduce the * need for garbage collection at the cost of approximately * 12% to 20% increased memory usage. */ #define CK_HS_MODE_DELETE 16 /* Currently unsupported. */ #define CK_HS_MODE_MPMC (void) /* * Hash callback function. */ typedef unsigned long ck_hs_hash_cb_t(const void *, unsigned long); /* * Returns pointer to object if objects are equivalent. */ typedef bool ck_hs_compare_cb_t(const void *, const void *); #if defined(CK_MD_POINTER_PACK_ENABLE) && defined(CK_MD_VMA_BITS) #define CK_HS_PP #define CK_HS_KEY_MASK ((1U << ((sizeof(void *) * 8) - CK_MD_VMA_BITS)) - 1) #endif struct ck_hs_map; struct ck_hs { struct ck_malloc *m; struct ck_hs_map *map; unsigned int mode; unsigned long seed; ck_hs_hash_cb_t *hf; ck_hs_compare_cb_t *compare; }; typedef struct ck_hs ck_hs_t; struct ck_hs_stat { unsigned long tombstones; unsigned long n_entries; unsigned int probe_maximum; }; struct ck_hs_iterator { void **cursor; unsigned long offset; struct ck_hs_map *map; }; typedef struct ck_hs_iterator ck_hs_iterator_t; #define CK_HS_ITERATOR_INITIALIZER { NULL, 0, NULL } /* Convenience wrapper to table hash function. */ #define CK_HS_HASH(T, F, K) F((K), (T)->seed) typedef void *ck_hs_apply_fn_t(void *, void *); bool ck_hs_apply(ck_hs_t *, unsigned long, const void *, ck_hs_apply_fn_t *, void *); void ck_hs_iterator_init(ck_hs_iterator_t *); bool ck_hs_next(ck_hs_t *, ck_hs_iterator_t *, void **); bool ck_hs_next_spmc(ck_hs_t *, ck_hs_iterator_t *, void **); bool ck_hs_move(ck_hs_t *, ck_hs_t *, ck_hs_hash_cb_t *, ck_hs_compare_cb_t *, struct ck_malloc *); bool ck_hs_init(ck_hs_t *, unsigned int, ck_hs_hash_cb_t *, ck_hs_compare_cb_t *, struct ck_malloc *, unsigned long, unsigned long); void ck_hs_destroy(ck_hs_t *); void *ck_hs_get(ck_hs_t *, unsigned long, const void *); bool ck_hs_put(ck_hs_t *, unsigned long, const void *); bool ck_hs_put_unique(ck_hs_t *, unsigned long, const void *); bool ck_hs_set(ck_hs_t *, unsigned long, const void *, void **); bool ck_hs_fas(ck_hs_t *, unsigned long, const void *, void **); void *ck_hs_remove(ck_hs_t *, unsigned long, const void *); bool ck_hs_grow(ck_hs_t *, unsigned long); bool ck_hs_rebuild(ck_hs_t *); bool ck_hs_gc(ck_hs_t *, unsigned long, unsigned long); unsigned long ck_hs_count(ck_hs_t *); bool ck_hs_reset(ck_hs_t *); bool ck_hs_reset_size(ck_hs_t *, unsigned long); void ck_hs_stat(ck_hs_t *, struct ck_hs_stat *); #endif /* CK_HS_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_ht.h ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_HT_H #define CK_HT_H #include #define CK_F_HT #if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_STORE_64) #define CK_HT_TYPE uint64_t #define CK_HT_TYPE_LOAD ck_pr_load_64 #define CK_HT_TYPE_STORE ck_pr_store_64 #define CK_HT_TYPE_MAX UINT64_MAX #else #define CK_HT_TYPE uint32_t #define CK_HT_TYPE_LOAD ck_pr_load_32 #define CK_HT_TYPE_STORE ck_pr_store_32 #define CK_HT_TYPE_MAX UINT32_MAX #endif #include #include #include #include #include #include struct ck_ht_hash { uint64_t value; }; typedef struct ck_ht_hash ck_ht_hash_t; #define CK_HT_MODE_DIRECT 1U #define CK_HT_MODE_BYTESTRING 2U #define CK_HT_WORKLOAD_DELETE 4U #if defined(CK_MD_POINTER_PACK_ENABLE) && defined(CK_MD_VMA_BITS) #define CK_HT_PP #define CK_HT_KEY_LENGTH ((sizeof(void *) * 8) - CK_MD_VMA_BITS) #define CK_HT_KEY_MASK ((1U << CK_HT_KEY_LENGTH) - 1) #else #define CK_HT_KEY_LENGTH 65535U #endif struct ck_ht_entry { #ifdef CK_HT_PP uintptr_t key; uintptr_t value CK_CC_PACKED; } CK_CC_ALIGN(16); #else uintptr_t key; uintptr_t value; CK_HT_TYPE key_length; CK_HT_TYPE hash; } CK_CC_ALIGN(32); #endif typedef struct ck_ht_entry ck_ht_entry_t; /* * The user is free to define their own stub values. */ #ifndef CK_HT_KEY_EMPTY #define CK_HT_KEY_EMPTY ((uintptr_t)0) #endif #ifndef CK_HT_KEY_TOMBSTONE #define CK_HT_KEY_TOMBSTONE (~CK_HT_KEY_EMPTY) #endif /* * Hash callback function. First argument is updated to contain a hash value, * second argument is the key, third argument is key length and final argument * is the hash table seed value. */ typedef void ck_ht_hash_cb_t(ck_ht_hash_t *, const void *, size_t, uint64_t); struct ck_ht_map; struct ck_ht { struct ck_malloc *m; struct ck_ht_map *map; unsigned int mode; uint64_t seed; ck_ht_hash_cb_t *h; }; typedef struct ck_ht ck_ht_t; struct ck_ht_stat { uint64_t probe_maximum; uint64_t n_entries; }; struct ck_ht_iterator { struct ck_ht_entry *current; uint64_t offset; }; typedef struct ck_ht_iterator ck_ht_iterator_t; #define CK_HT_ITERATOR_INITIALIZER { NULL, 0 } CK_CC_INLINE static void ck_ht_iterator_init(struct ck_ht_iterator *iterator) { iterator->current = NULL; iterator->offset = 0; return; } CK_CC_INLINE static bool ck_ht_entry_empty(ck_ht_entry_t *entry) { return entry->key == CK_HT_KEY_EMPTY; } CK_CC_INLINE static void ck_ht_entry_key_set_direct(ck_ht_entry_t *entry, uintptr_t key) { entry->key = key; return; } CK_CC_INLINE static void ck_ht_entry_key_set(ck_ht_entry_t *entry, const void *key, uint16_t key_length) { #ifdef CK_HT_PP entry->key = (uintptr_t)key | ((uintptr_t)key_length << CK_MD_VMA_BITS); #else entry->key = (uintptr_t)key; entry->key_length = key_length; #endif return; } CK_CC_INLINE static void * ck_ht_entry_key(ck_ht_entry_t *entry) { #ifdef CK_HT_PP return (void *)(entry->key & (((uintptr_t)1 << CK_MD_VMA_BITS) - 1)); #else return (void *)entry->key; #endif } CK_CC_INLINE static uint16_t ck_ht_entry_key_length(ck_ht_entry_t *entry) { #ifdef CK_HT_PP return entry->key >> CK_MD_VMA_BITS; #else return entry->key_length; #endif } CK_CC_INLINE static void * ck_ht_entry_value(ck_ht_entry_t *entry) { #ifdef CK_HT_PP return (void *)(entry->value & (((uintptr_t)1 << CK_MD_VMA_BITS) - 1)); #else return (void *)entry->value; #endif } CK_CC_INLINE static void ck_ht_entry_set(struct ck_ht_entry *entry, ck_ht_hash_t h, const void *key, uint16_t key_length, const void *value) { #ifdef CK_HT_PP entry->key = (uintptr_t)key | ((uintptr_t)key_length << CK_MD_VMA_BITS); entry->value = (uintptr_t)value | ((uintptr_t)(h.value >> 32) << CK_MD_VMA_BITS); #else entry->key = (uintptr_t)key; entry->value = (uintptr_t)value; entry->key_length = key_length; entry->hash = h.value; #endif return; } CK_CC_INLINE static void ck_ht_entry_set_direct(struct ck_ht_entry *entry, ck_ht_hash_t h, uintptr_t key, uintptr_t value) { entry->key = key; entry->value = value; #ifndef CK_HT_PP entry->hash = h.value; #else (void)h; #endif return; } CK_CC_INLINE static uintptr_t ck_ht_entry_key_direct(ck_ht_entry_t *entry) { return entry->key; } CK_CC_INLINE static uintptr_t ck_ht_entry_value_direct(ck_ht_entry_t *entry) { return entry->value; } /* * Iteration must occur without any concurrent mutations on * the hash table. */ bool ck_ht_next(ck_ht_t *, ck_ht_iterator_t *, ck_ht_entry_t **entry); void ck_ht_stat(ck_ht_t *, struct ck_ht_stat *); void ck_ht_hash(ck_ht_hash_t *, ck_ht_t *, const void *, uint16_t); void ck_ht_hash_direct(ck_ht_hash_t *, ck_ht_t *, uintptr_t); bool ck_ht_init(ck_ht_t *, unsigned int, ck_ht_hash_cb_t *, struct ck_malloc *, CK_HT_TYPE, uint64_t); void ck_ht_destroy(ck_ht_t *); bool ck_ht_set_spmc(ck_ht_t *, ck_ht_hash_t, ck_ht_entry_t *); bool ck_ht_put_spmc(ck_ht_t *, ck_ht_hash_t, ck_ht_entry_t *); bool ck_ht_get_spmc(ck_ht_t *, ck_ht_hash_t, ck_ht_entry_t *); bool ck_ht_gc(struct ck_ht *, unsigned long, unsigned long); bool ck_ht_grow_spmc(ck_ht_t *, CK_HT_TYPE); bool ck_ht_remove_spmc(ck_ht_t *, ck_ht_hash_t, ck_ht_entry_t *); bool ck_ht_reset_spmc(ck_ht_t *); bool ck_ht_reset_size_spmc(ck_ht_t *, CK_HT_TYPE); CK_HT_TYPE ck_ht_count(ck_ht_t *); #endif /* CK_HT_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_limits.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(__linux__) && defined(__KERNEL__) #include #ifndef UINT8_MAX #define UINT8_MAX ((u8)(~0U)) #endif #ifndef UINT16_MAX #define UINT16_MAX USHRT_MAX #endif #ifndef UINT32_MAX #define UINT32_MAX UINT_MAX #endif #ifndef UINT64_MAX #define UINT64_MAX ULLONG_MAX #endif #elif defined(__FreeBSD__) && defined(_KERNEL) #include #include #else #include #endif /* __linux__ && __KERNEL__ */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_malloc.h ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_MALLOC_H #define CK_MALLOC_H #include #include struct ck_malloc { void *(*malloc)(size_t); void *(*realloc)(void *, size_t, size_t, bool); void (*free)(void *, size_t, bool); }; #endif /* CK_MALLOC_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_md.h.in ================================================ /* * Copyright 2011-2012 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_MD_H #define CK_MD_H #ifndef CK_MD_CACHELINE #define CK_MD_CACHELINE (64) #endif #ifndef CK_MD_PAGESIZE #define CK_MD_PAGESIZE (4096) #endif #ifndef @RTM_ENABLE@ #define @RTM_ENABLE@ #endif /* @RTM_ENABLE@ */ #ifndef @LSE_ENABLE@ #define @LSE_ENABLE@ #endif /* @LSE_ENABLE@ */ #ifndef @POINTER_PACK_ENABLE@ #define @POINTER_PACK_ENABLE@ #endif /* @POINTER_PACK_ENABLE@ */ #ifndef @VMA_BITS@ #define @VMA_BITS@ @VMA_BITS_VALUE@ #endif /* @VMA_BITS@ */ #ifndef @MM@ #define @MM@ #endif /* @MM@ */ #ifndef @DISABLE_DOUBLE@ #define @DISABLE_DOUBLE@ #endif /* @DISABLE_DOUBLE@ */ #define CK_VERSION "@VERSION@" #define CK_GIT_SHA "@GIT_SHA@" #endif /* CK_MD_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_pflock.h ================================================ /* * Copyright 2013 John Wittrock. * Copyright 2013-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PFLOCK_H #define CK_PFLOCK_H /* * This is an implementation of phase-fair locks derived from the work * described in: * Brandenburg, B. and Anderson, J. 2010. Spin-Based * Reader-Writer Synchronization for Multiprocessor Real-Time Systems */ #include #include struct ck_pflock { uint32_t rin; uint32_t rout; uint32_t win; uint32_t wout; }; typedef struct ck_pflock ck_pflock_t; #define CK_PFLOCK_LSB 0xFFFFFFF0 #define CK_PFLOCK_RINC 0x100 /* Reader increment value. */ #define CK_PFLOCK_WBITS 0x3 /* Writer bits in reader. */ #define CK_PFLOCK_PRES 0x2 /* Writer present bit. */ #define CK_PFLOCK_PHID 0x1 /* Phase ID bit. */ #define CK_PFLOCK_INITIALIZER {0, 0, 0, 0} CK_CC_INLINE static void ck_pflock_init(struct ck_pflock *pf) { pf->rin = 0; pf->rout = 0; pf->win = 0; pf->wout = 0; ck_pr_barrier(); return; } CK_CC_INLINE static void ck_pflock_write_unlock(ck_pflock_t *pf) { ck_pr_fence_unlock(); /* Migrate from write phase to read phase. */ ck_pr_and_32(&pf->rin, CK_PFLOCK_LSB); /* Allow other writers to continue. */ ck_pr_faa_32(&pf->wout, 1); return; } CK_CC_INLINE static void ck_pflock_write_lock(ck_pflock_t *pf) { uint32_t ticket; /* Acquire ownership of write-phase. */ ticket = ck_pr_faa_32(&pf->win, 1); while (ck_pr_load_32(&pf->wout) != ticket) ck_pr_stall(); /* * Acquire ticket on read-side in order to allow them * to flush. Indicates to any incoming reader that a * write-phase is pending. */ ticket = ck_pr_faa_32(&pf->rin, (ticket & CK_PFLOCK_PHID) | CK_PFLOCK_PRES); /* Wait for any pending readers to flush. */ while (ck_pr_load_32(&pf->rout) != ticket) ck_pr_stall(); ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_pflock_read_unlock(ck_pflock_t *pf) { ck_pr_fence_unlock(); ck_pr_faa_32(&pf->rout, CK_PFLOCK_RINC); return; } CK_CC_INLINE static void ck_pflock_read_lock(ck_pflock_t *pf) { uint32_t w; /* * If no writer is present, then the operation has completed * successfully. */ w = ck_pr_faa_32(&pf->rin, CK_PFLOCK_RINC) & CK_PFLOCK_WBITS; if (w == 0) goto leave; /* Wait for current write phase to complete. */ while ((ck_pr_load_32(&pf->rin) & CK_PFLOCK_WBITS) == w) ck_pr_stall(); leave: /* Acquire semantics with respect to readers. */ ck_pr_fence_lock(); return; } #endif /* CK_PFLOCK_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_pr.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_H #define CK_PR_H #include #include #include #include #include #ifndef CK_USE_CC_BUILTINS #if defined(__x86_64__) #include "gcc/x86_64/ck_pr.h" #elif defined(__x86__) #include "gcc/x86/ck_pr.h" #elif defined(__sparcv9__) #include "gcc/sparcv9/ck_pr.h" #elif defined(__ppc64__) #include "gcc/ppc64/ck_pr.h" #elif defined(__s390x__) #include "gcc/s390x/ck_pr.h" #elif defined(__ppc__) #include "gcc/ppc/ck_pr.h" #elif defined(__arm__) #include "gcc/arm/ck_pr.h" #elif defined(__aarch64__) #include "gcc/aarch64/ck_pr.h" #elif !defined(__GNUC__) #error Your platform is unsupported #endif #endif /* !CK_USE_CC_BUILTINS */ #if defined(__GNUC__) #include "gcc/ck_pr.h" #endif #define CK_PR_FENCE_EMIT(T) \ CK_CC_INLINE static void \ ck_pr_fence_##T(void) \ { \ ck_pr_fence_strict_##T(); \ return; \ } #define CK_PR_FENCE_NOOP(T) \ CK_CC_INLINE static void \ ck_pr_fence_##T(void) \ { \ ck_pr_barrier(); \ return; \ } /* * None of the currently supported platforms allow for data-dependent * load ordering. */ CK_PR_FENCE_NOOP(load_depends) #define ck_pr_fence_strict_load_depends ck_pr_fence_load_depends /* * In memory models where atomic operations do not have serializing * effects, atomic read-modify-write operations are modeled as stores. */ #if defined(CK_MD_RMO) /* * Only stores to the same location have a global * ordering. */ CK_PR_FENCE_EMIT(atomic) CK_PR_FENCE_EMIT(atomic_load) CK_PR_FENCE_EMIT(atomic_store) CK_PR_FENCE_EMIT(store_atomic) CK_PR_FENCE_EMIT(load_atomic) CK_PR_FENCE_EMIT(load_store) CK_PR_FENCE_EMIT(store_load) CK_PR_FENCE_EMIT(load) CK_PR_FENCE_EMIT(store) CK_PR_FENCE_EMIT(memory) CK_PR_FENCE_EMIT(acquire) CK_PR_FENCE_EMIT(release) CK_PR_FENCE_EMIT(acqrel) CK_PR_FENCE_EMIT(lock) CK_PR_FENCE_EMIT(unlock) #elif defined(CK_MD_PSO) /* * Anything can be re-ordered with respect to stores. * Otherwise, loads are executed in-order. */ CK_PR_FENCE_EMIT(atomic) CK_PR_FENCE_NOOP(atomic_load) CK_PR_FENCE_EMIT(atomic_store) CK_PR_FENCE_EMIT(store_atomic) CK_PR_FENCE_NOOP(load_atomic) CK_PR_FENCE_EMIT(load_store) CK_PR_FENCE_EMIT(store_load) CK_PR_FENCE_NOOP(load) CK_PR_FENCE_EMIT(store) CK_PR_FENCE_EMIT(memory) CK_PR_FENCE_EMIT(acquire) CK_PR_FENCE_EMIT(release) CK_PR_FENCE_EMIT(acqrel) CK_PR_FENCE_EMIT(lock) CK_PR_FENCE_EMIT(unlock) #elif defined(CK_MD_TSO) /* * Only loads are re-ordered and only with respect to * prior stores. Atomic operations are serializing. */ CK_PR_FENCE_NOOP(atomic) CK_PR_FENCE_NOOP(atomic_load) CK_PR_FENCE_NOOP(atomic_store) CK_PR_FENCE_NOOP(store_atomic) CK_PR_FENCE_NOOP(load_atomic) CK_PR_FENCE_NOOP(load_store) CK_PR_FENCE_EMIT(store_load) CK_PR_FENCE_NOOP(load) CK_PR_FENCE_NOOP(store) CK_PR_FENCE_EMIT(memory) CK_PR_FENCE_NOOP(acquire) CK_PR_FENCE_NOOP(release) CK_PR_FENCE_NOOP(acqrel) CK_PR_FENCE_NOOP(lock) CK_PR_FENCE_NOOP(unlock) #else #error "No memory model has been defined." #endif /* CK_MD_TSO */ #undef CK_PR_FENCE_EMIT #undef CK_PR_FENCE_NOOP #ifndef CK_F_PR_RFO #define CK_F_PR_RFO CK_CC_INLINE static void ck_pr_rfo(const void *m) { (void)m; return; } #endif /* CK_F_PR_RFO */ #define CK_PR_STORE_SAFE(DST, VAL, TYPE) \ ck_pr_md_store_##TYPE( \ ((void)sizeof(*(DST) = (VAL)), (DST)), \ (VAL)) #define ck_pr_store_ptr(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), ptr) #define ck_pr_store_char(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), char) #ifndef CK_PR_DISABLE_DOUBLE #define ck_pr_store_double(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), double) #endif #define ck_pr_store_uint(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), uint) #define ck_pr_store_int(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), int) #define ck_pr_store_32(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), 32) #define ck_pr_store_16(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), 16) #define ck_pr_store_8(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), 8) #define ck_pr_store_ptr_unsafe(DST, VAL) ck_pr_md_store_ptr((DST), (VAL)) #ifdef CK_F_PR_LOAD_64 #define ck_pr_store_64(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), 64) #endif /* CK_F_PR_LOAD_64 */ #define CK_PR_LOAD_PTR_SAFE(SRC) (CK_CC_TYPEOF(*(SRC), (void *)))ck_pr_md_load_ptr((SRC)) #define ck_pr_load_ptr(SRC) CK_PR_LOAD_PTR_SAFE((SRC)) #define CK_PR_LOAD_SAFE(SRC, TYPE) ck_pr_md_load_##TYPE((SRC)) #define ck_pr_load_char(SRC) CK_PR_LOAD_SAFE((SRC), char) #ifndef CK_PR_DISABLE_DOUBLE #define ck_pr_load_double(SRC) CK_PR_LOAD_SAFE((SRC), double) #endif #define ck_pr_load_uint(SRC) CK_PR_LOAD_SAFE((SRC), uint) #define ck_pr_load_int(SRC) CK_PR_LOAD_SAFE((SRC), int) #define ck_pr_load_32(SRC) CK_PR_LOAD_SAFE((SRC), 32) #define ck_pr_load_16(SRC) CK_PR_LOAD_SAFE((SRC), 16) #define ck_pr_load_8(SRC) CK_PR_LOAD_SAFE((SRC), 8) #ifdef CK_F_PR_LOAD_64 #define ck_pr_load_64(SRC) CK_PR_LOAD_SAFE((SRC), 64) #endif /* CK_F_PR_LOAD_64 */ #define CK_PR_BIN(K, S, M, T, P, C) \ CK_CC_INLINE static void \ ck_pr_##K##_##S(M *target, T value) \ { \ T previous; \ C punt; \ punt = ck_pr_md_load_##S(target); \ previous = (T)punt; \ while (ck_pr_cas_##S##_value(target, \ (C)previous, \ (C)(previous P value), \ &previous) == false) \ ck_pr_stall(); \ \ return; \ } #define CK_PR_BIN_S(K, S, T, P) CK_PR_BIN(K, S, T, T, P, T) #if defined(CK_F_PR_LOAD_CHAR) && defined(CK_F_PR_CAS_CHAR_VALUE) #ifndef CK_F_PR_ADD_CHAR #define CK_F_PR_ADD_CHAR CK_PR_BIN_S(add, char, char, +) #endif /* CK_F_PR_ADD_CHAR */ #ifndef CK_F_PR_SUB_CHAR #define CK_F_PR_SUB_CHAR CK_PR_BIN_S(sub, char, char, -) #endif /* CK_F_PR_SUB_CHAR */ #ifndef CK_F_PR_AND_CHAR #define CK_F_PR_AND_CHAR CK_PR_BIN_S(and, char, char, &) #endif /* CK_F_PR_AND_CHAR */ #ifndef CK_F_PR_XOR_CHAR #define CK_F_PR_XOR_CHAR CK_PR_BIN_S(xor, char, char, ^) #endif /* CK_F_PR_XOR_CHAR */ #ifndef CK_F_PR_OR_CHAR #define CK_F_PR_OR_CHAR CK_PR_BIN_S(or, char, char, |) #endif /* CK_F_PR_OR_CHAR */ #endif /* CK_F_PR_LOAD_CHAR && CK_F_PR_CAS_CHAR_VALUE */ #if defined(CK_F_PR_LOAD_INT) && defined(CK_F_PR_CAS_INT_VALUE) #ifndef CK_F_PR_ADD_INT #define CK_F_PR_ADD_INT CK_PR_BIN_S(add, int, int, +) #endif /* CK_F_PR_ADD_INT */ #ifndef CK_F_PR_SUB_INT #define CK_F_PR_SUB_INT CK_PR_BIN_S(sub, int, int, -) #endif /* CK_F_PR_SUB_INT */ #ifndef CK_F_PR_AND_INT #define CK_F_PR_AND_INT CK_PR_BIN_S(and, int, int, &) #endif /* CK_F_PR_AND_INT */ #ifndef CK_F_PR_XOR_INT #define CK_F_PR_XOR_INT CK_PR_BIN_S(xor, int, int, ^) #endif /* CK_F_PR_XOR_INT */ #ifndef CK_F_PR_OR_INT #define CK_F_PR_OR_INT CK_PR_BIN_S(or, int, int, |) #endif /* CK_F_PR_OR_INT */ #endif /* CK_F_PR_LOAD_INT && CK_F_PR_CAS_INT_VALUE */ #if defined(CK_F_PR_LOAD_DOUBLE) && defined(CK_F_PR_CAS_DOUBLE_VALUE) && \ !defined(CK_PR_DISABLE_DOUBLE) #ifndef CK_F_PR_ADD_DOUBLE #define CK_F_PR_ADD_DOUBLE CK_PR_BIN_S(add, double, double, +) #endif /* CK_F_PR_ADD_DOUBLE */ #ifndef CK_F_PR_SUB_DOUBLE #define CK_F_PR_SUB_DOUBLE CK_PR_BIN_S(sub, double, double, -) #endif /* CK_F_PR_SUB_DOUBLE */ #endif /* CK_F_PR_LOAD_DOUBLE && CK_F_PR_CAS_DOUBLE_VALUE && !CK_PR_DISABLE_DOUBLE */ #if defined(CK_F_PR_LOAD_UINT) && defined(CK_F_PR_CAS_UINT_VALUE) #ifndef CK_F_PR_ADD_UINT #define CK_F_PR_ADD_UINT CK_PR_BIN_S(add, uint, unsigned int, +) #endif /* CK_F_PR_ADD_UINT */ #ifndef CK_F_PR_SUB_UINT #define CK_F_PR_SUB_UINT CK_PR_BIN_S(sub, uint, unsigned int, -) #endif /* CK_F_PR_SUB_UINT */ #ifndef CK_F_PR_AND_UINT #define CK_F_PR_AND_UINT CK_PR_BIN_S(and, uint, unsigned int, &) #endif /* CK_F_PR_AND_UINT */ #ifndef CK_F_PR_XOR_UINT #define CK_F_PR_XOR_UINT CK_PR_BIN_S(xor, uint, unsigned int, ^) #endif /* CK_F_PR_XOR_UINT */ #ifndef CK_F_PR_OR_UINT #define CK_F_PR_OR_UINT CK_PR_BIN_S(or, uint, unsigned int, |) #endif /* CK_F_PR_OR_UINT */ #endif /* CK_F_PR_LOAD_UINT && CK_F_PR_CAS_UINT_VALUE */ #if defined(CK_F_PR_LOAD_PTR) && defined(CK_F_PR_CAS_PTR_VALUE) #ifndef CK_F_PR_ADD_PTR #define CK_F_PR_ADD_PTR CK_PR_BIN(add, ptr, void, uintptr_t, +, void *) #endif /* CK_F_PR_ADD_PTR */ #ifndef CK_F_PR_SUB_PTR #define CK_F_PR_SUB_PTR CK_PR_BIN(sub, ptr, void, uintptr_t, -, void *) #endif /* CK_F_PR_SUB_PTR */ #ifndef CK_F_PR_AND_PTR #define CK_F_PR_AND_PTR CK_PR_BIN(and, ptr, void, uintptr_t, &, void *) #endif /* CK_F_PR_AND_PTR */ #ifndef CK_F_PR_XOR_PTR #define CK_F_PR_XOR_PTR CK_PR_BIN(xor, ptr, void, uintptr_t, ^, void *) #endif /* CK_F_PR_XOR_PTR */ #ifndef CK_F_PR_OR_PTR #define CK_F_PR_OR_PTR CK_PR_BIN(or, ptr, void, uintptr_t, |, void *) #endif /* CK_F_PR_OR_PTR */ #endif /* CK_F_PR_LOAD_PTR && CK_F_PR_CAS_PTR_VALUE */ #if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_CAS_64_VALUE) #ifndef CK_F_PR_ADD_64 #define CK_F_PR_ADD_64 CK_PR_BIN_S(add, 64, uint64_t, +) #endif /* CK_F_PR_ADD_64 */ #ifndef CK_F_PR_SUB_64 #define CK_F_PR_SUB_64 CK_PR_BIN_S(sub, 64, uint64_t, -) #endif /* CK_F_PR_SUB_64 */ #ifndef CK_F_PR_AND_64 #define CK_F_PR_AND_64 CK_PR_BIN_S(and, 64, uint64_t, &) #endif /* CK_F_PR_AND_64 */ #ifndef CK_F_PR_XOR_64 #define CK_F_PR_XOR_64 CK_PR_BIN_S(xor, 64, uint64_t, ^) #endif /* CK_F_PR_XOR_64 */ #ifndef CK_F_PR_OR_64 #define CK_F_PR_OR_64 CK_PR_BIN_S(or, 64, uint64_t, |) #endif /* CK_F_PR_OR_64 */ #endif /* CK_F_PR_LOAD_64 && CK_F_PR_CAS_64_VALUE */ #if defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_CAS_32_VALUE) #ifndef CK_F_PR_ADD_32 #define CK_F_PR_ADD_32 CK_PR_BIN_S(add, 32, uint32_t, +) #endif /* CK_F_PR_ADD_32 */ #ifndef CK_F_PR_SUB_32 #define CK_F_PR_SUB_32 CK_PR_BIN_S(sub, 32, uint32_t, -) #endif /* CK_F_PR_SUB_32 */ #ifndef CK_F_PR_AND_32 #define CK_F_PR_AND_32 CK_PR_BIN_S(and, 32, uint32_t, &) #endif /* CK_F_PR_AND_32 */ #ifndef CK_F_PR_XOR_32 #define CK_F_PR_XOR_32 CK_PR_BIN_S(xor, 32, uint32_t, ^) #endif /* CK_F_PR_XOR_32 */ #ifndef CK_F_PR_OR_32 #define CK_F_PR_OR_32 CK_PR_BIN_S(or, 32, uint32_t, |) #endif /* CK_F_PR_OR_32 */ #endif /* CK_F_PR_LOAD_32 && CK_F_PR_CAS_32_VALUE */ #if defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_CAS_16_VALUE) #ifndef CK_F_PR_ADD_16 #define CK_F_PR_ADD_16 CK_PR_BIN_S(add, 16, uint16_t, +) #endif /* CK_F_PR_ADD_16 */ #ifndef CK_F_PR_SUB_16 #define CK_F_PR_SUB_16 CK_PR_BIN_S(sub, 16, uint16_t, -) #endif /* CK_F_PR_SUB_16 */ #ifndef CK_F_PR_AND_16 #define CK_F_PR_AND_16 CK_PR_BIN_S(and, 16, uint16_t, &) #endif /* CK_F_PR_AND_16 */ #ifndef CK_F_PR_XOR_16 #define CK_F_PR_XOR_16 CK_PR_BIN_S(xor, 16, uint16_t, ^) #endif /* CK_F_PR_XOR_16 */ #ifndef CK_F_PR_OR_16 #define CK_F_PR_OR_16 CK_PR_BIN_S(or, 16, uint16_t, |) #endif /* CK_F_PR_OR_16 */ #endif /* CK_F_PR_LOAD_16 && CK_F_PR_CAS_16_VALUE */ #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_CAS_8_VALUE) #ifndef CK_F_PR_ADD_8 #define CK_F_PR_ADD_8 CK_PR_BIN_S(add, 8, uint8_t, +) #endif /* CK_F_PR_ADD_8 */ #ifndef CK_F_PR_SUB_8 #define CK_F_PR_SUB_8 CK_PR_BIN_S(sub, 8, uint8_t, -) #endif /* CK_F_PR_SUB_8 */ #ifndef CK_F_PR_AND_8 #define CK_F_PR_AND_8 CK_PR_BIN_S(and, 8, uint8_t, &) #endif /* CK_F_PR_AND_8 */ #ifndef CK_F_PR_XOR_8 #define CK_F_PR_XOR_8 CK_PR_BIN_S(xor, 8, uint8_t, ^) #endif /* CK_F_PR_XOR_8 */ #ifndef CK_F_PR_OR_8 #define CK_F_PR_OR_8 CK_PR_BIN_S(or, 8, uint8_t, |) #endif /* CK_F_PR_OR_8 */ #endif /* CK_F_PR_LOAD_8 && CK_F_PR_CAS_8_VALUE */ #undef CK_PR_BIN_S #undef CK_PR_BIN #define CK_PR_BTX(K, S, M, T, P, C, R) \ CK_CC_INLINE static bool \ ck_pr_##K##_##S(M *target, unsigned int offset) \ { \ T previous; \ C punt; \ punt = ck_pr_md_load_##S(target); \ previous = (T)punt; \ while (ck_pr_cas_##S##_value(target, (C)previous, \ (C)(previous P (R ((T)1 << offset))), &previous) == false) \ ck_pr_stall(); \ return ((previous >> offset) & 1); \ } #define CK_PR_BTX_S(K, S, T, P, R) CK_PR_BTX(K, S, T, T, P, T, R) #if defined(CK_F_PR_LOAD_INT) && defined(CK_F_PR_CAS_INT_VALUE) #ifndef CK_F_PR_BTC_INT #define CK_F_PR_BTC_INT CK_PR_BTX_S(btc, int, int, ^,) #endif /* CK_F_PR_BTC_INT */ #ifndef CK_F_PR_BTR_INT #define CK_F_PR_BTR_INT CK_PR_BTX_S(btr, int, int, &, ~) #endif /* CK_F_PR_BTR_INT */ #ifndef CK_F_PR_BTS_INT #define CK_F_PR_BTS_INT CK_PR_BTX_S(bts, int, int, |,) #endif /* CK_F_PR_BTS_INT */ #endif /* CK_F_PR_LOAD_INT && CK_F_PR_CAS_INT_VALUE */ #if defined(CK_F_PR_LOAD_UINT) && defined(CK_F_PR_CAS_UINT_VALUE) #ifndef CK_F_PR_BTC_UINT #define CK_F_PR_BTC_UINT CK_PR_BTX_S(btc, uint, unsigned int, ^,) #endif /* CK_F_PR_BTC_UINT */ #ifndef CK_F_PR_BTR_UINT #define CK_F_PR_BTR_UINT CK_PR_BTX_S(btr, uint, unsigned int, &, ~) #endif /* CK_F_PR_BTR_UINT */ #ifndef CK_F_PR_BTS_UINT #define CK_F_PR_BTS_UINT CK_PR_BTX_S(bts, uint, unsigned int, |,) #endif /* CK_F_PR_BTS_UINT */ #endif /* CK_F_PR_LOAD_UINT && CK_F_PR_CAS_UINT_VALUE */ #if defined(CK_F_PR_LOAD_PTR) && defined(CK_F_PR_CAS_PTR_VALUE) #ifndef CK_F_PR_BTC_PTR #define CK_F_PR_BTC_PTR CK_PR_BTX(btc, ptr, void, uintptr_t, ^, void *,) #endif /* CK_F_PR_BTC_PTR */ #ifndef CK_F_PR_BTR_PTR #define CK_F_PR_BTR_PTR CK_PR_BTX(btr, ptr, void, uintptr_t, &, void *, ~) #endif /* CK_F_PR_BTR_PTR */ #ifndef CK_F_PR_BTS_PTR #define CK_F_PR_BTS_PTR CK_PR_BTX(bts, ptr, void, uintptr_t, |, void *,) #endif /* CK_F_PR_BTS_PTR */ #endif /* CK_F_PR_LOAD_PTR && CK_F_PR_CAS_PTR_VALUE */ #if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_CAS_64_VALUE) #ifndef CK_F_PR_BTC_64 #define CK_F_PR_BTC_64 CK_PR_BTX_S(btc, 64, uint64_t, ^,) #endif /* CK_F_PR_BTC_64 */ #ifndef CK_F_PR_BTR_64 #define CK_F_PR_BTR_64 CK_PR_BTX_S(btr, 64, uint64_t, &, ~) #endif /* CK_F_PR_BTR_64 */ #ifndef CK_F_PR_BTS_64 #define CK_F_PR_BTS_64 CK_PR_BTX_S(bts, 64, uint64_t, |,) #endif /* CK_F_PR_BTS_64 */ #endif /* CK_F_PR_LOAD_64 && CK_F_PR_CAS_64_VALUE */ #if defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_CAS_32_VALUE) #ifndef CK_F_PR_BTC_32 #define CK_F_PR_BTC_32 CK_PR_BTX_S(btc, 32, uint32_t, ^,) #endif /* CK_F_PR_BTC_32 */ #ifndef CK_F_PR_BTR_32 #define CK_F_PR_BTR_32 CK_PR_BTX_S(btr, 32, uint32_t, &, ~) #endif /* CK_F_PR_BTR_32 */ #ifndef CK_F_PR_BTS_32 #define CK_F_PR_BTS_32 CK_PR_BTX_S(bts, 32, uint32_t, |,) #endif /* CK_F_PR_BTS_32 */ #endif /* CK_F_PR_LOAD_32 && CK_F_PR_CAS_32_VALUE */ #if defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_CAS_16_VALUE) #ifndef CK_F_PR_BTC_16 #define CK_F_PR_BTC_16 CK_PR_BTX_S(btc, 16, uint16_t, ^,) #endif /* CK_F_PR_BTC_16 */ #ifndef CK_F_PR_BTR_16 #define CK_F_PR_BTR_16 CK_PR_BTX_S(btr, 16, uint16_t, &, ~) #endif /* CK_F_PR_BTR_16 */ #ifndef CK_F_PR_BTS_16 #define CK_F_PR_BTS_16 CK_PR_BTX_S(bts, 16, uint16_t, |,) #endif /* CK_F_PR_BTS_16 */ #endif /* CK_F_PR_LOAD_16 && CK_F_PR_CAS_16_VALUE */ #undef CK_PR_BTX_S #undef CK_PR_BTX #define CK_PR_UNARY(K, X, S, M, T) \ CK_CC_INLINE static void \ ck_pr_##K##_##S(M *target) \ { \ ck_pr_##X##_##S(target, (T)1); \ return; \ } #define CK_PR_UNARY_Z(K, S, M, T, P, C, Z) \ CK_CC_INLINE static void \ ck_pr_##K##_##S##_zero(M *target, bool *zero) \ { \ T previous; \ C punt; \ punt = (C)ck_pr_md_load_##S(target); \ previous = (T)punt; \ while (ck_pr_cas_##S##_value(target, \ (C)previous, \ (C)(previous P 1), \ &previous) == false) \ ck_pr_stall(); \ *zero = previous == (T)Z; \ return; \ } #define CK_PR_UNARY_S(K, X, S, M) CK_PR_UNARY(K, X, S, M, M) #define CK_PR_UNARY_Z_S(K, S, M, P, Z) CK_PR_UNARY_Z(K, S, M, M, P, M, Z) #if defined(CK_F_PR_LOAD_CHAR) && defined(CK_F_PR_CAS_CHAR_VALUE) #ifndef CK_F_PR_INC_CHAR #define CK_F_PR_INC_CHAR CK_PR_UNARY_S(inc, add, char, char) #endif /* CK_F_PR_INC_CHAR */ #ifndef CK_F_PR_INC_CHAR_ZERO #define CK_F_PR_INC_CHAR_ZERO CK_PR_UNARY_Z_S(inc, char, char, +, -1) #endif /* CK_F_PR_INC_CHAR_ZERO */ #ifndef CK_F_PR_DEC_CHAR #define CK_F_PR_DEC_CHAR CK_PR_UNARY_S(dec, sub, char, char) #endif /* CK_F_PR_DEC_CHAR */ #ifndef CK_F_PR_DEC_CHAR_ZERO #define CK_F_PR_DEC_CHAR_ZERO CK_PR_UNARY_Z_S(dec, char, char, -, 1) #endif /* CK_F_PR_DEC_CHAR_ZERO */ #endif /* CK_F_PR_LOAD_CHAR && CK_F_PR_CAS_CHAR_VALUE */ #if defined(CK_F_PR_LOAD_INT) && defined(CK_F_PR_CAS_INT_VALUE) #ifndef CK_F_PR_INC_INT #define CK_F_PR_INC_INT CK_PR_UNARY_S(inc, add, int, int) #endif /* CK_F_PR_INC_INT */ #ifndef CK_F_PR_INC_INT_ZERO #define CK_F_PR_INC_INT_ZERO CK_PR_UNARY_Z_S(inc, int, int, +, -1) #endif /* CK_F_PR_INC_INT_ZERO */ #ifndef CK_F_PR_DEC_INT #define CK_F_PR_DEC_INT CK_PR_UNARY_S(dec, sub, int, int) #endif /* CK_F_PR_DEC_INT */ #ifndef CK_F_PR_DEC_INT_ZERO #define CK_F_PR_DEC_INT_ZERO CK_PR_UNARY_Z_S(dec, int, int, -, 1) #endif /* CK_F_PR_DEC_INT_ZERO */ #endif /* CK_F_PR_LOAD_INT && CK_F_PR_CAS_INT_VALUE */ #if defined(CK_F_PR_LOAD_DOUBLE) && defined(CK_F_PR_CAS_DOUBLE_VALUE) && \ !defined(CK_PR_DISABLE_DOUBLE) #ifndef CK_F_PR_INC_DOUBLE #define CK_F_PR_INC_DOUBLE CK_PR_UNARY_S(inc, add, double, double) #endif /* CK_F_PR_INC_DOUBLE */ #ifndef CK_F_PR_DEC_DOUBLE #define CK_F_PR_DEC_DOUBLE CK_PR_UNARY_S(dec, sub, double, double) #endif /* CK_F_PR_DEC_DOUBLE */ #endif /* CK_F_PR_LOAD_DOUBLE && CK_F_PR_CAS_DOUBLE_VALUE && !CK_PR_DISABLE_DOUBLE */ #if defined(CK_F_PR_LOAD_UINT) && defined(CK_F_PR_CAS_UINT_VALUE) #ifndef CK_F_PR_INC_UINT #define CK_F_PR_INC_UINT CK_PR_UNARY_S(inc, add, uint, unsigned int) #endif /* CK_F_PR_INC_UINT */ #ifndef CK_F_PR_INC_UINT_ZERO #define CK_F_PR_INC_UINT_ZERO CK_PR_UNARY_Z_S(inc, uint, unsigned int, +, UINT_MAX) #endif /* CK_F_PR_INC_UINT_ZERO */ #ifndef CK_F_PR_DEC_UINT #define CK_F_PR_DEC_UINT CK_PR_UNARY_S(dec, sub, uint, unsigned int) #endif /* CK_F_PR_DEC_UINT */ #ifndef CK_F_PR_DEC_UINT_ZERO #define CK_F_PR_DEC_UINT_ZERO CK_PR_UNARY_Z_S(dec, uint, unsigned int, -, 1) #endif /* CK_F_PR_DEC_UINT_ZERO */ #endif /* CK_F_PR_LOAD_UINT && CK_F_PR_CAS_UINT_VALUE */ #if defined(CK_F_PR_LOAD_PTR) && defined(CK_F_PR_CAS_PTR_VALUE) #ifndef CK_F_PR_INC_PTR #define CK_F_PR_INC_PTR CK_PR_UNARY(inc, add, ptr, void, uintptr_t) #endif /* CK_F_PR_INC_PTR */ #ifndef CK_F_PR_INC_PTR_ZERO #define CK_F_PR_INC_PTR_ZERO CK_PR_UNARY_Z(inc, ptr, void, uintptr_t, +, void *, UINT_MAX) #endif /* CK_F_PR_INC_PTR_ZERO */ #ifndef CK_F_PR_DEC_PTR #define CK_F_PR_DEC_PTR CK_PR_UNARY(dec, sub, ptr, void, uintptr_t) #endif /* CK_F_PR_DEC_PTR */ #ifndef CK_F_PR_DEC_PTR_ZERO #define CK_F_PR_DEC_PTR_ZERO CK_PR_UNARY_Z(dec, ptr, void, uintptr_t, -, void *, 1) #endif /* CK_F_PR_DEC_PTR_ZERO */ #endif /* CK_F_PR_LOAD_PTR && CK_F_PR_CAS_PTR_VALUE */ #if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_CAS_64_VALUE) #ifndef CK_F_PR_INC_64 #define CK_F_PR_INC_64 CK_PR_UNARY_S(inc, add, 64, uint64_t) #endif /* CK_F_PR_INC_64 */ #ifndef CK_F_PR_INC_64_ZERO #define CK_F_PR_INC_64_ZERO CK_PR_UNARY_Z_S(inc, 64, uint64_t, +, UINT64_MAX) #endif /* CK_F_PR_INC_64_ZERO */ #ifndef CK_F_PR_DEC_64 #define CK_F_PR_DEC_64 CK_PR_UNARY_S(dec, sub, 64, uint64_t) #endif /* CK_F_PR_DEC_64 */ #ifndef CK_F_PR_DEC_64_ZERO #define CK_F_PR_DEC_64_ZERO CK_PR_UNARY_Z_S(dec, 64, uint64_t, -, 1) #endif /* CK_F_PR_DEC_64_ZERO */ #endif /* CK_F_PR_LOAD_64 && CK_F_PR_CAS_64_VALUE */ #if defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_CAS_32_VALUE) #ifndef CK_F_PR_INC_32 #define CK_F_PR_INC_32 CK_PR_UNARY_S(inc, add, 32, uint32_t) #endif /* CK_F_PR_INC_32 */ #ifndef CK_F_PR_INC_32_ZERO #define CK_F_PR_INC_32_ZERO CK_PR_UNARY_Z_S(inc, 32, uint32_t, +, UINT32_MAX) #endif /* CK_F_PR_INC_32_ZERO */ #ifndef CK_F_PR_DEC_32 #define CK_F_PR_DEC_32 CK_PR_UNARY_S(dec, sub, 32, uint32_t) #endif /* CK_F_PR_DEC_32 */ #ifndef CK_F_PR_DEC_32_ZERO #define CK_F_PR_DEC_32_ZERO CK_PR_UNARY_Z_S(dec, 32, uint32_t, -, 1) #endif /* CK_F_PR_DEC_32_ZERO */ #endif /* CK_F_PR_LOAD_32 && CK_F_PR_CAS_32_VALUE */ #if defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_CAS_16_VALUE) #ifndef CK_F_PR_INC_16 #define CK_F_PR_INC_16 CK_PR_UNARY_S(inc, add, 16, uint16_t) #endif /* CK_F_PR_INC_16 */ #ifndef CK_F_PR_INC_16_ZERO #define CK_F_PR_INC_16_ZERO CK_PR_UNARY_Z_S(inc, 16, uint16_t, +, UINT16_MAX) #endif /* CK_F_PR_INC_16_ZERO */ #ifndef CK_F_PR_DEC_16 #define CK_F_PR_DEC_16 CK_PR_UNARY_S(dec, sub, 16, uint16_t) #endif /* CK_F_PR_DEC_16 */ #ifndef CK_F_PR_DEC_16_ZERO #define CK_F_PR_DEC_16_ZERO CK_PR_UNARY_Z_S(dec, 16, uint16_t, -, 1) #endif /* CK_F_PR_DEC_16_ZERO */ #endif /* CK_F_PR_LOAD_16 && CK_F_PR_CAS_16_VALUE */ #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_CAS_8_VALUE) #ifndef CK_F_PR_INC_8 #define CK_F_PR_INC_8 CK_PR_UNARY_S(inc, add, 8, uint8_t) #endif /* CK_F_PR_INC_8 */ #ifndef CK_F_PR_INC_8_ZERO #define CK_F_PR_INC_8_ZERO CK_PR_UNARY_Z_S(inc, 8, uint8_t, +, UINT8_MAX) #endif /* CK_F_PR_INC_8_ZERO */ #ifndef CK_F_PR_DEC_8 #define CK_F_PR_DEC_8 CK_PR_UNARY_S(dec, sub, 8, uint8_t) #endif /* CK_F_PR_DEC_8 */ #ifndef CK_F_PR_DEC_8_ZERO #define CK_F_PR_DEC_8_ZERO CK_PR_UNARY_Z_S(dec, 8, uint8_t, -, 1) #endif /* CK_F_PR_DEC_8_ZERO */ #endif /* CK_F_PR_LOAD_8 && CK_F_PR_CAS_8_VALUE */ #undef CK_PR_UNARY_Z_S #undef CK_PR_UNARY_S #undef CK_PR_UNARY_Z #undef CK_PR_UNARY #define CK_PR_N(K, S, M, T, P, C) \ CK_CC_INLINE static void \ ck_pr_##K##_##S(M *target) \ { \ T previous; \ C punt; \ punt = (C)ck_pr_md_load_##S(target); \ previous = (T)punt; \ while (ck_pr_cas_##S##_value(target, \ (C)previous, \ (C)(P previous), \ &previous) == false) \ ck_pr_stall(); \ \ return; \ } #define CK_PR_N_Z(S, M, T, C) \ CK_CC_INLINE static void \ ck_pr_neg_##S##_zero(M *target, bool *zero) \ { \ T previous; \ C punt; \ punt = (C)ck_pr_md_load_##S(target); \ previous = (T)punt; \ while (ck_pr_cas_##S##_value(target, \ (C)previous, \ (C)(-previous), \ &previous) == false) \ ck_pr_stall(); \ \ *zero = previous == 0; \ return; \ } #define CK_PR_N_S(K, S, M, P) CK_PR_N(K, S, M, M, P, M) #define CK_PR_N_Z_S(S, M) CK_PR_N_Z(S, M, M, M) #if defined(CK_F_PR_LOAD_CHAR) && defined(CK_F_PR_CAS_CHAR_VALUE) #ifndef CK_F_PR_NOT_CHAR #define CK_F_PR_NOT_CHAR CK_PR_N_S(not, char, char, ~) #endif /* CK_F_PR_NOT_CHAR */ #ifndef CK_F_PR_NEG_CHAR #define CK_F_PR_NEG_CHAR CK_PR_N_S(neg, char, char, -) #endif /* CK_F_PR_NEG_CHAR */ #ifndef CK_F_PR_NEG_CHAR_ZERO #define CK_F_PR_NEG_CHAR_ZERO CK_PR_N_Z_S(char, char) #endif /* CK_F_PR_NEG_CHAR_ZERO */ #endif /* CK_F_PR_LOAD_CHAR && CK_F_PR_CAS_CHAR_VALUE */ #if defined(CK_F_PR_LOAD_INT) && defined(CK_F_PR_CAS_INT_VALUE) #ifndef CK_F_PR_NOT_INT #define CK_F_PR_NOT_INT CK_PR_N_S(not, int, int, ~) #endif /* CK_F_PR_NOT_INT */ #ifndef CK_F_PR_NEG_INT #define CK_F_PR_NEG_INT CK_PR_N_S(neg, int, int, -) #endif /* CK_F_PR_NEG_INT */ #ifndef CK_F_PR_NEG_INT_ZERO #define CK_F_PR_NEG_INT_ZERO CK_PR_N_Z_S(int, int) #endif /* CK_F_PR_NEG_INT_ZERO */ #endif /* CK_F_PR_LOAD_INT && CK_F_PR_CAS_INT_VALUE */ #if defined(CK_F_PR_LOAD_DOUBLE) && defined(CK_F_PR_CAS_DOUBLE_VALUE) && \ !defined(CK_PR_DISABLE_DOUBLE) #ifndef CK_F_PR_NEG_DOUBLE #define CK_F_PR_NEG_DOUBLE CK_PR_N_S(neg, double, double, -) #endif /* CK_F_PR_NEG_DOUBLE */ #endif /* CK_F_PR_LOAD_DOUBLE && CK_F_PR_CAS_DOUBLE_VALUE && !CK_PR_DISABLE_DOUBLE */ #if defined(CK_F_PR_LOAD_UINT) && defined(CK_F_PR_CAS_UINT_VALUE) #ifndef CK_F_PR_NOT_UINT #define CK_F_PR_NOT_UINT CK_PR_N_S(not, uint, unsigned int, ~) #endif /* CK_F_PR_NOT_UINT */ #ifndef CK_F_PR_NEG_UINT #define CK_F_PR_NEG_UINT CK_PR_N_S(neg, uint, unsigned int, -) #endif /* CK_F_PR_NEG_UINT */ #ifndef CK_F_PR_NEG_UINT_ZERO #define CK_F_PR_NEG_UINT_ZERO CK_PR_N_Z_S(uint, unsigned int) #endif /* CK_F_PR_NEG_UINT_ZERO */ #endif /* CK_F_PR_LOAD_UINT && CK_F_PR_CAS_UINT_VALUE */ #if defined(CK_F_PR_LOAD_PTR) && defined(CK_F_PR_CAS_PTR_VALUE) #ifndef CK_F_PR_NOT_PTR #define CK_F_PR_NOT_PTR CK_PR_N(not, ptr, void, uintptr_t, ~, void *) #endif /* CK_F_PR_NOT_PTR */ #ifndef CK_F_PR_NEG_PTR #define CK_F_PR_NEG_PTR CK_PR_N(neg, ptr, void, uintptr_t, -, void *) #endif /* CK_F_PR_NEG_PTR */ #ifndef CK_F_PR_NEG_PTR_ZERO #define CK_F_PR_NEG_PTR_ZERO CK_PR_N_Z(ptr, void, uintptr_t, void *) #endif /* CK_F_PR_NEG_PTR_ZERO */ #endif /* CK_F_PR_LOAD_PTR && CK_F_PR_CAS_PTR_VALUE */ #if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_CAS_64_VALUE) #ifndef CK_F_PR_NOT_64 #define CK_F_PR_NOT_64 CK_PR_N_S(not, 64, uint64_t, ~) #endif /* CK_F_PR_NOT_64 */ #ifndef CK_F_PR_NEG_64 #define CK_F_PR_NEG_64 CK_PR_N_S(neg, 64, uint64_t, -) #endif /* CK_F_PR_NEG_64 */ #ifndef CK_F_PR_NEG_64_ZERO #define CK_F_PR_NEG_64_ZERO CK_PR_N_Z_S(64, uint64_t) #endif /* CK_F_PR_NEG_64_ZERO */ #endif /* CK_F_PR_LOAD_64 && CK_F_PR_CAS_64_VALUE */ #if defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_CAS_32_VALUE) #ifndef CK_F_PR_NOT_32 #define CK_F_PR_NOT_32 CK_PR_N_S(not, 32, uint32_t, ~) #endif /* CK_F_PR_NOT_32 */ #ifndef CK_F_PR_NEG_32 #define CK_F_PR_NEG_32 CK_PR_N_S(neg, 32, uint32_t, -) #endif /* CK_F_PR_NEG_32 */ #ifndef CK_F_PR_NEG_32_ZERO #define CK_F_PR_NEG_32_ZERO CK_PR_N_Z_S(32, uint32_t) #endif /* CK_F_PR_NEG_32_ZERO */ #endif /* CK_F_PR_LOAD_32 && CK_F_PR_CAS_32_VALUE */ #if defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_CAS_16_VALUE) #ifndef CK_F_PR_NOT_16 #define CK_F_PR_NOT_16 CK_PR_N_S(not, 16, uint16_t, ~) #endif /* CK_F_PR_NOT_16 */ #ifndef CK_F_PR_NEG_16 #define CK_F_PR_NEG_16 CK_PR_N_S(neg, 16, uint16_t, -) #endif /* CK_F_PR_NEG_16 */ #ifndef CK_F_PR_NEG_16_ZERO #define CK_F_PR_NEG_16_ZERO CK_PR_N_Z_S(16, uint16_t) #endif /* CK_F_PR_NEG_16_ZERO */ #endif /* CK_F_PR_LOAD_16 && CK_F_PR_CAS_16_VALUE */ #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_CAS_8_VALUE) #ifndef CK_F_PR_NOT_8 #define CK_F_PR_NOT_8 CK_PR_N_S(not, 8, uint8_t, ~) #endif /* CK_F_PR_NOT_8 */ #ifndef CK_F_PR_NEG_8 #define CK_F_PR_NEG_8 CK_PR_N_S(neg, 8, uint8_t, -) #endif /* CK_F_PR_NEG_8 */ #ifndef CK_F_PR_NEG_8_ZERO #define CK_F_PR_NEG_8_ZERO CK_PR_N_Z_S(8, uint8_t) #endif /* CK_F_PR_NEG_8_ZERO */ #endif /* CK_F_PR_LOAD_8 && CK_F_PR_CAS_8_VALUE */ #undef CK_PR_N_Z_S #undef CK_PR_N_S #undef CK_PR_N_Z #undef CK_PR_N #define CK_PR_FAA(S, M, T, C) \ CK_CC_INLINE static C \ ck_pr_faa_##S(M *target, T delta) \ { \ T previous; \ C punt; \ punt = (C)ck_pr_md_load_##S(target); \ previous = (T)punt; \ while (ck_pr_cas_##S##_value(target, \ (C)previous, \ (C)(previous + delta), \ &previous) == false) \ ck_pr_stall(); \ \ return ((C)previous); \ } #define CK_PR_FAS(S, M, C) \ CK_CC_INLINE static C \ ck_pr_fas_##S(M *target, C update) \ { \ C previous; \ previous = ck_pr_md_load_##S(target); \ while (ck_pr_cas_##S##_value(target, \ previous, \ update, \ &previous) == false) \ ck_pr_stall(); \ \ return (previous); \ } #define CK_PR_FAA_S(S, M) CK_PR_FAA(S, M, M, M) #define CK_PR_FAS_S(S, M) CK_PR_FAS(S, M, M) #if defined(CK_F_PR_LOAD_CHAR) && defined(CK_F_PR_CAS_CHAR_VALUE) #ifndef CK_F_PR_FAA_CHAR #define CK_F_PR_FAA_CHAR CK_PR_FAA_S(char, char) #endif /* CK_F_PR_FAA_CHAR */ #ifndef CK_F_PR_FAS_CHAR #define CK_F_PR_FAS_CHAR CK_PR_FAS_S(char, char) #endif /* CK_F_PR_FAS_CHAR */ #endif /* CK_F_PR_LOAD_CHAR && CK_F_PR_CAS_CHAR_VALUE */ #if defined(CK_F_PR_LOAD_INT) && defined(CK_F_PR_CAS_INT_VALUE) #ifndef CK_F_PR_FAA_INT #define CK_F_PR_FAA_INT CK_PR_FAA_S(int, int) #endif /* CK_F_PR_FAA_INT */ #ifndef CK_F_PR_FAS_INT #define CK_F_PR_FAS_INT CK_PR_FAS_S(int, int) #endif /* CK_F_PR_FAS_INT */ #endif /* CK_F_PR_LOAD_INT && CK_F_PR_CAS_INT_VALUE */ #if defined(CK_F_PR_LOAD_DOUBLE) && defined(CK_F_PR_CAS_DOUBLE_VALUE) && \ !defined(CK_PR_DISABLE_DOUBLE) #ifndef CK_F_PR_FAA_DOUBLE #define CK_F_PR_FAA_DOUBLE CK_PR_FAA_S(double, double) #endif /* CK_F_PR_FAA_DOUBLE */ #ifndef CK_F_PR_FAS_DOUBLE #define CK_F_PR_FAS_DOUBLE CK_PR_FAS_S(double, double) #endif /* CK_F_PR_FAS_DOUBLE */ #endif /* CK_F_PR_LOAD_DOUBLE && CK_F_PR_CAS_DOUBLE_VALUE && !CK_PR_DISABLE_DOUBLE */ #if defined(CK_F_PR_LOAD_UINT) && defined(CK_F_PR_CAS_UINT_VALUE) #ifndef CK_F_PR_FAA_UINT #define CK_F_PR_FAA_UINT CK_PR_FAA_S(uint, unsigned int) #endif /* CK_F_PR_FAA_UINT */ #ifndef CK_F_PR_FAS_UINT #define CK_F_PR_FAS_UINT CK_PR_FAS_S(uint, unsigned int) #endif /* CK_F_PR_FAS_UINT */ #endif /* CK_F_PR_LOAD_UINT && CK_F_PR_CAS_UINT_VALUE */ #if defined(CK_F_PR_LOAD_PTR) && defined(CK_F_PR_CAS_PTR_VALUE) #ifndef CK_F_PR_FAA_PTR #define CK_F_PR_FAA_PTR CK_PR_FAA(ptr, void, uintptr_t, void *) #endif /* CK_F_PR_FAA_PTR */ #ifndef CK_F_PR_FAS_PTR #define CK_F_PR_FAS_PTR CK_PR_FAS(ptr, void, void *) #endif /* CK_F_PR_FAS_PTR */ #endif /* CK_F_PR_LOAD_PTR && CK_F_PR_CAS_PTR_VALUE */ #if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_CAS_64_VALUE) #ifndef CK_F_PR_FAA_64 #define CK_F_PR_FAA_64 CK_PR_FAA_S(64, uint64_t) #endif /* CK_F_PR_FAA_64 */ #ifndef CK_F_PR_FAS_64 #define CK_F_PR_FAS_64 CK_PR_FAS_S(64, uint64_t) #endif /* CK_F_PR_FAS_64 */ #endif /* CK_F_PR_LOAD_64 && CK_F_PR_CAS_64_VALUE */ #if defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_CAS_32_VALUE) #ifndef CK_F_PR_FAA_32 #define CK_F_PR_FAA_32 CK_PR_FAA_S(32, uint32_t) #endif /* CK_F_PR_FAA_32 */ #ifndef CK_F_PR_FAS_32 #define CK_F_PR_FAS_32 CK_PR_FAS_S(32, uint32_t) #endif /* CK_F_PR_FAS_32 */ #endif /* CK_F_PR_LOAD_32 && CK_F_PR_CAS_32_VALUE */ #if defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_CAS_16_VALUE) #ifndef CK_F_PR_FAA_16 #define CK_F_PR_FAA_16 CK_PR_FAA_S(16, uint16_t) #endif /* CK_F_PR_FAA_16 */ #ifndef CK_F_PR_FAS_16 #define CK_F_PR_FAS_16 CK_PR_FAS_S(16, uint16_t) #endif /* CK_F_PR_FAS_16 */ #endif /* CK_F_PR_LOAD_16 && CK_F_PR_CAS_16_VALUE */ #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_CAS_8_VALUE) #ifndef CK_F_PR_FAA_8 #define CK_F_PR_FAA_8 CK_PR_FAA_S(8, uint8_t) #endif /* CK_F_PR_FAA_8 */ #ifndef CK_F_PR_FAS_8 #define CK_F_PR_FAS_8 CK_PR_FAS_S(8, uint8_t) #endif /* CK_F_PR_FAS_8 */ #endif /* CK_F_PR_LOAD_8 && CK_F_PR_CAS_8_VALUE */ #undef CK_PR_FAA_S #undef CK_PR_FAS_S #undef CK_PR_FAA #undef CK_PR_FAS #endif /* CK_PR_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_queue.h ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 * $FreeBSD: release/9.0.0/sys/sys/queue.h 221843 2011-05-13 15:49:23Z mdf $ */ #ifndef CK_QUEUE_H #define CK_QUEUE_H #include /* * This file defines three types of data structures: singly-linked lists, * singly-linked tail queues and lists. * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at * the expense of O(n) removal for arbitrary elements. New elements can be * added to the list after an existing element or at the head of the list. * Elements being removed from the head of the list should use the explicit * macro for this purpose for optimum efficiency. A singly-linked list may * only be traversed in the forward direction. Singly-linked lists are ideal * for applications with large datasets and few or no removals or for * implementing a LIFO queue. * * A singly-linked tail queue is headed by a pair of pointers, one to the * head of the list and the other to the tail of the list. The elements are * singly linked for minimum space and pointer manipulation overhead at the * expense of O(n) removal for arbitrary elements. New elements can be added * to the list after an existing element, at the head of the list, or at the * end of the list. Elements being removed from the head of the tail queue * should use the explicit macro for this purpose for optimum efficiency. * A singly-linked tail queue may only be traversed in the forward direction. * Singly-linked tail queues are ideal for applications with large datasets * and few or no removals or for implementing a FIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * It is safe to use _FOREACH/_FOREACH_SAFE in the presence of concurrent * modifications to the list. Writers to these lists must, on the other hand, * implement writer-side synchronization. The _SWAP operations are not atomic. * This facility is currently unsupported on architectures such as the Alpha * which require load-depend memory fences. * * CK_SLIST CK_LIST CK_STAILQ * _HEAD + + + * _HEAD_INITIALIZER + + + * _ENTRY + + + * _INIT + + + * _EMPTY + + + * _FIRST + + + * _NEXT + + + * _FOREACH + + + * _FOREACH_SAFE + + + * _INSERT_HEAD + + + * _INSERT_BEFORE - + - * _INSERT_AFTER + + + * _INSERT_TAIL - - + * _REMOVE_AFTER + - + * _REMOVE_HEAD + - + * _REMOVE + + + * _SWAP + + + * _MOVE + + + */ /* * Singly-linked List declarations. */ #define CK_SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define CK_SLIST_HEAD_INITIALIZER(head) \ { NULL } #define CK_SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List functions. */ #define CK_SLIST_EMPTY(head) \ (ck_pr_load_ptr(&(head)->slh_first) == NULL) #define CK_SLIST_FIRST(head) \ (ck_pr_load_ptr(&(head)->slh_first)) #define CK_SLIST_NEXT(elm, field) \ ck_pr_load_ptr(&((elm)->field.sle_next)) #define CK_SLIST_FOREACH(var, head, field) \ for ((var) = CK_SLIST_FIRST((head)); \ (var) && (ck_pr_fence_load(), 1); \ (var) = CK_SLIST_NEXT((var), field)) #define CK_SLIST_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = CK_SLIST_FIRST(head); \ (var) && (ck_pr_fence_load(), (tvar) = CK_SLIST_NEXT(var, field), 1);\ (var) = (tvar)) #define CK_SLIST_FOREACH_PREVPTR(var, varp, head, field) \ for ((varp) = &(head)->slh_first; \ ((var) = ck_pr_load_ptr(varp)) != NULL && (ck_pr_fence_load(), 1); \ (varp) = &(var)->field.sle_next) #define CK_SLIST_INIT(head) do { \ ck_pr_store_ptr(&(head)->slh_first, NULL); \ ck_pr_fence_store(); \ } while (0) #define CK_SLIST_INSERT_AFTER(a, b, field) do { \ (b)->field.sle_next = (a)->field.sle_next; \ ck_pr_fence_store(); \ ck_pr_store_ptr(&(a)->field.sle_next, b); \ } while (0) #define CK_SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ ck_pr_fence_store(); \ ck_pr_store_ptr(&(head)->slh_first, elm); \ } while (0) #define CK_SLIST_REMOVE_AFTER(elm, field) do { \ ck_pr_store_ptr(&(elm)->field.sle_next, \ (elm)->field.sle_next->field.sle_next); \ } while (0) #define CK_SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ CK_SLIST_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->slh_first; \ while (curelm->field.sle_next != (elm)) \ curelm = curelm->field.sle_next; \ CK_SLIST_REMOVE_AFTER(curelm, field); \ } \ } while (0) #define CK_SLIST_REMOVE_HEAD(head, field) do { \ ck_pr_store_ptr(&(head)->slh_first, \ (head)->slh_first->field.sle_next); \ } while (0) #define CK_SLIST_MOVE(head1, head2, field) do { \ ck_pr_store_ptr(&(head1)->slh_first, (head2)->slh_first); \ } while (0) /* * This operation is not applied atomically. */ #define CK_SLIST_SWAP(a, b, type) do { \ struct type *swap_first = (a)->slh_first; \ (a)->slh_first = (b)->slh_first; \ (b)->slh_first = swap_first; \ } while (0) /* * Singly-linked Tail queue declarations. */ #define CK_STAILQ_HEAD(name, type) \ struct name { \ struct type *stqh_first;/* first element */ \ struct type **stqh_last;/* addr of last next element */ \ } #define CK_STAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).stqh_first } #define CK_STAILQ_ENTRY(type) \ struct { \ struct type *stqe_next; /* next element */ \ } /* * Singly-linked Tail queue functions. */ #define CK_STAILQ_CONCAT(head1, head2) do { \ if ((head2)->stqh_first != NULL) { \ ck_pr_store_ptr((head1)->stqh_last, (head2)->stqh_first); \ ck_pr_fence_store(); \ (head1)->stqh_last = (head2)->stqh_last; \ CK_STAILQ_INIT((head2)); \ } \ } while (0) #define CK_STAILQ_EMPTY(head) (ck_pr_load_ptr(&(head)->stqh_first) == NULL) #define CK_STAILQ_FIRST(head) (ck_pr_load_ptr(&(head)->stqh_first)) #define CK_STAILQ_FOREACH(var, head, field) \ for((var) = CK_STAILQ_FIRST((head)); \ (var) && (ck_pr_fence_load(), 1); \ (var) = CK_STAILQ_NEXT((var), field)) #define CK_STAILQ_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = CK_STAILQ_FIRST((head)); \ (var) && (ck_pr_fence_load(), (tvar) = \ CK_STAILQ_NEXT((var), field), 1); \ (var) = (tvar)) #define CK_STAILQ_INIT(head) do { \ ck_pr_store_ptr(&(head)->stqh_first, NULL); \ ck_pr_fence_store(); \ (head)->stqh_last = &(head)->stqh_first; \ } while (0) #define CK_STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ (elm)->field.stqe_next = (tqelm)->field.stqe_next; \ ck_pr_fence_store(); \ ck_pr_store_ptr(&(tqelm)->field.stqe_next, elm); \ if ((elm)->field.stqe_next == NULL) \ (head)->stqh_last = &(elm)->field.stqe_next; \ } while (0) #define CK_STAILQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.stqe_next = (head)->stqh_first; \ ck_pr_fence_store(); \ ck_pr_store_ptr(&(head)->stqh_first, elm); \ if ((elm)->field.stqe_next == NULL) \ (head)->stqh_last = &(elm)->field.stqe_next; \ } while (0) #define CK_STAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.stqe_next = NULL; \ ck_pr_fence_store(); \ ck_pr_store_ptr((head)->stqh_last, (elm)); \ (head)->stqh_last = &(elm)->field.stqe_next; \ } while (0) #define CK_STAILQ_NEXT(elm, field) \ (ck_pr_load_ptr(&(elm)->field.stqe_next)) #define CK_STAILQ_REMOVE(head, elm, type, field) do { \ if ((head)->stqh_first == (elm)) { \ CK_STAILQ_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->stqh_first; \ while (curelm->field.stqe_next != (elm)) \ curelm = curelm->field.stqe_next; \ CK_STAILQ_REMOVE_AFTER(head, curelm, field); \ } \ } while (0) #define CK_STAILQ_REMOVE_AFTER(head, elm, field) do { \ ck_pr_store_ptr(&(elm)->field.stqe_next, \ (elm)->field.stqe_next->field.stqe_next); \ if ((elm)->field.stqe_next == NULL) \ (head)->stqh_last = &(elm)->field.stqe_next; \ } while (0) #define CK_STAILQ_REMOVE_HEAD(head, field) do { \ ck_pr_store_ptr(&(head)->stqh_first, \ (head)->stqh_first->field.stqe_next); \ if ((head)->stqh_first == NULL) \ (head)->stqh_last = &(head)->stqh_first; \ } while (0) #define CK_STAILQ_MOVE(head1, head2, field) do { \ ck_pr_store_ptr(&(head1)->stqh_first, (head2)->stqh_first); \ (head1)->stqh_last = (head2)->stqh_last; \ if ((head2)->stqh_last == &(head2)->stqh_first) \ (head1)->stqh_last = &(head1)->stqh_first; \ } while (0) /* * This operation is not applied atomically. */ #define CK_STAILQ_SWAP(head1, head2, type) do { \ struct type *swap_first = CK_STAILQ_FIRST(head1); \ struct type **swap_last = (head1)->stqh_last; \ CK_STAILQ_FIRST(head1) = CK_STAILQ_FIRST(head2); \ (head1)->stqh_last = (head2)->stqh_last; \ CK_STAILQ_FIRST(head2) = swap_first; \ (head2)->stqh_last = swap_last; \ if (CK_STAILQ_EMPTY(head1)) \ (head1)->stqh_last = &(head1)->stqh_first; \ if (CK_STAILQ_EMPTY(head2)) \ (head2)->stqh_last = &(head2)->stqh_first; \ } while (0) /* * List declarations. */ #define CK_LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define CK_LIST_HEAD_INITIALIZER(head) \ { NULL } #define CK_LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } #define CK_LIST_FIRST(head) ck_pr_load_ptr(&(head)->lh_first) #define CK_LIST_EMPTY(head) (CK_LIST_FIRST(head) == NULL) #define CK_LIST_NEXT(elm, field) ck_pr_load_ptr(&(elm)->field.le_next) #define CK_LIST_FOREACH(var, head, field) \ for ((var) = CK_LIST_FIRST((head)); \ (var) && (ck_pr_fence_load(), 1); \ (var) = CK_LIST_NEXT((var), field)) #define CK_LIST_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = CK_LIST_FIRST((head)); \ (var) && (ck_pr_fence_load(), (tvar) = CK_LIST_NEXT((var), field), 1);\ (var) = (tvar)) #define CK_LIST_INIT(head) do { \ ck_pr_store_ptr(&(head)->lh_first, NULL); \ ck_pr_fence_store(); \ } while (0) #define CK_LIST_INSERT_AFTER(listelm, elm, field) do { \ (elm)->field.le_next = (listelm)->field.le_next; \ (elm)->field.le_prev = &(listelm)->field.le_next; \ ck_pr_fence_store(); \ if ((listelm)->field.le_next != NULL) \ (listelm)->field.le_next->field.le_prev = &(elm)->field.le_next;\ ck_pr_store_ptr(&(listelm)->field.le_next, elm); \ } while (0) #define CK_LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ ck_pr_fence_store(); \ ck_pr_store_ptr((listelm)->field.le_prev, (elm)); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (0) #define CK_LIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.le_next = (head)->lh_first; \ ck_pr_fence_store(); \ if ((elm)->field.le_next != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next; \ ck_pr_store_ptr(&(head)->lh_first, elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (0) #define CK_LIST_REMOVE(elm, field) do { \ ck_pr_store_ptr((elm)->field.le_prev, (elm)->field.le_next); \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = (elm)->field.le_prev; \ } while (0) #define CK_LIST_MOVE(head1, head2, field) do { \ ck_pr_store_ptr(&(head1)->lh_first, (head2)->lh_first); \ if ((head1)->lh_first != NULL) \ (head1)->lh_first->field.le_prev = &(head1)->lh_first; \ } while (0) /* * This operation is not applied atomically. */ #define CK_LIST_SWAP(head1, head2, type, field) do { \ struct type *swap_tmp = (head1)->lh_first; \ (head1)->lh_first = (head2)->lh_first; \ (head2)->lh_first = swap_tmp; \ if ((swap_tmp = (head1)->lh_first) != NULL) \ swap_tmp->field.le_prev = &(head1)->lh_first; \ if ((swap_tmp = (head2)->lh_first) != NULL) \ swap_tmp->field.le_prev = &(head2)->lh_first; \ } while (0) #endif /* CK_QUEUE_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_rhs.h ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_RHS_H #define CK_RHS_H #include #include #include #include #include #include #include /* * Indicates a single-writer many-reader workload. Mutually * exclusive with CK_RHS_MODE_MPMC */ #define CK_RHS_MODE_SPMC 1 /* * Indicates that values to be stored are not pointers but * values. Allows for full precision. Mutually exclusive * with CK_RHS_MODE_OBJECT. */ #define CK_RHS_MODE_DIRECT 2 /* * Indicates that the values to be stored are pointers. * Allows for space optimizations in the presence of pointer * packing. Mutually exclusive with CK_RHS_MODE_DIRECT. */ #define CK_RHS_MODE_OBJECT 8 /* * Indicated that the load is read-mostly, so get should be optimized * over put and delete */ #define CK_RHS_MODE_READ_MOSTLY 16 /* Currently unsupported. */ #define CK_RHS_MODE_MPMC (void) /* * Hash callback function. */ typedef unsigned long ck_rhs_hash_cb_t(const void *, unsigned long); /* * Returns pointer to object if objects are equivalent. */ typedef bool ck_rhs_compare_cb_t(const void *, const void *); #if defined(CK_MD_POINTER_PACK_ENABLE) && defined(CK_MD_VMA_BITS) #define CK_RHS_PP #define CK_RHS_KEY_MASK ((1U << ((sizeof(void *) * 8) - CK_MD_VMA_BITS)) - 1) #endif struct ck_rhs_map; struct ck_rhs { struct ck_malloc *m; struct ck_rhs_map *map; unsigned int mode; unsigned int load_factor; unsigned long seed; ck_rhs_hash_cb_t *hf; ck_rhs_compare_cb_t *compare; }; typedef struct ck_rhs ck_rhs_t; struct ck_rhs_stat { unsigned long n_entries; unsigned int probe_maximum; }; struct ck_rhs_iterator { void **cursor; unsigned long offset; }; typedef struct ck_rhs_iterator ck_rhs_iterator_t; #define CK_RHS_ITERATOR_INITIALIZER { NULL, 0 } /* Convenience wrapper to table hash function. */ #define CK_RHS_HASH(T, F, K) F((K), (T)->seed) typedef void *ck_rhs_apply_fn_t(void *, void *); bool ck_rhs_apply(ck_rhs_t *, unsigned long, const void *, ck_rhs_apply_fn_t *, void *); void ck_rhs_iterator_init(ck_rhs_iterator_t *); bool ck_rhs_next(ck_rhs_t *, ck_rhs_iterator_t *, void **); bool ck_rhs_move(ck_rhs_t *, ck_rhs_t *, ck_rhs_hash_cb_t *, ck_rhs_compare_cb_t *, struct ck_malloc *); bool ck_rhs_init(ck_rhs_t *, unsigned int, ck_rhs_hash_cb_t *, ck_rhs_compare_cb_t *, struct ck_malloc *, unsigned long, unsigned long); void ck_rhs_destroy(ck_rhs_t *); void *ck_rhs_get(ck_rhs_t *, unsigned long, const void *); bool ck_rhs_put(ck_rhs_t *, unsigned long, const void *); bool ck_rhs_put_unique(ck_rhs_t *, unsigned long, const void *); bool ck_rhs_set(ck_rhs_t *, unsigned long, const void *, void **); bool ck_rhs_fas(ck_rhs_t *, unsigned long, const void *, void **); void *ck_rhs_remove(ck_rhs_t *, unsigned long, const void *); bool ck_rhs_grow(ck_rhs_t *, unsigned long); bool ck_rhs_rebuild(ck_rhs_t *); bool ck_rhs_gc(ck_rhs_t *); unsigned long ck_rhs_count(ck_rhs_t *); bool ck_rhs_reset(ck_rhs_t *); bool ck_rhs_reset_size(ck_rhs_t *, unsigned long); void ck_rhs_stat(ck_rhs_t *, struct ck_rhs_stat *); bool ck_rhs_set_load_factor(ck_rhs_t *, unsigned int); #endif /* CK_RHS_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_ring.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_RING_H #define CK_RING_H #include #include #include #include #include /* * Concurrent ring buffer. */ struct ck_ring { unsigned int c_head; char pad[CK_MD_CACHELINE - sizeof(unsigned int)]; unsigned int p_tail; unsigned int p_head; char _pad[CK_MD_CACHELINE - sizeof(unsigned int) * 2]; unsigned int size; unsigned int mask; }; typedef struct ck_ring ck_ring_t; struct ck_ring_buffer { void *value; }; typedef struct ck_ring_buffer ck_ring_buffer_t; CK_CC_INLINE static unsigned int ck_ring_size(const struct ck_ring *ring) { unsigned int c, p; c = ck_pr_load_uint(&ring->c_head); p = ck_pr_load_uint(&ring->p_tail); return (p - c) & ring->mask; } CK_CC_INLINE static unsigned int ck_ring_capacity(const struct ck_ring *ring) { return ring->size; } CK_CC_INLINE static void ck_ring_init(struct ck_ring *ring, unsigned int size) { ring->size = size; ring->mask = size - 1; ring->p_tail = 0; ring->p_head = 0; ring->c_head = 0; return; } /* * The _ck_ring_* namespace is internal only and must not used externally. */ CK_CC_FORCE_INLINE static bool _ck_ring_enqueue_sp(struct ck_ring *ring, void *CK_CC_RESTRICT buffer, const void *CK_CC_RESTRICT entry, unsigned int ts, unsigned int *size) { const unsigned int mask = ring->mask; unsigned int consumer, producer, delta; consumer = ck_pr_load_uint(&ring->c_head); producer = ring->p_tail; delta = producer + 1; if (size != NULL) *size = (producer - consumer) & mask; if (CK_CC_UNLIKELY((delta & mask) == (consumer & mask))) return false; buffer = (char *)buffer + ts * (producer & mask); memcpy(buffer, entry, ts); /* * Make sure to update slot value before indicating * that the slot is available for consumption. */ ck_pr_fence_store(); ck_pr_store_uint(&ring->p_tail, delta); return true; } CK_CC_FORCE_INLINE static bool _ck_ring_enqueue_sp_size(struct ck_ring *ring, void *CK_CC_RESTRICT buffer, const void *CK_CC_RESTRICT entry, unsigned int ts, unsigned int *size) { unsigned int sz; bool r; r = _ck_ring_enqueue_sp(ring, buffer, entry, ts, &sz); *size = sz; return r; } CK_CC_FORCE_INLINE static bool _ck_ring_dequeue_sc(struct ck_ring *ring, const void *CK_CC_RESTRICT buffer, void *CK_CC_RESTRICT target, unsigned int size) { const unsigned int mask = ring->mask; unsigned int consumer, producer; consumer = ring->c_head; producer = ck_pr_load_uint(&ring->p_tail); if (CK_CC_UNLIKELY(consumer == producer)) return false; /* * Make sure to serialize with respect to our snapshot * of the producer counter. */ ck_pr_fence_load(); buffer = (const char *)buffer + size * (consumer & mask); memcpy(target, buffer, size); /* * Make sure copy is completed with respect to consumer * update. */ ck_pr_fence_store(); ck_pr_store_uint(&ring->c_head, consumer + 1); return true; } CK_CC_FORCE_INLINE static bool _ck_ring_enqueue_mp(struct ck_ring *ring, void *buffer, const void *entry, unsigned int ts, unsigned int *size) { const unsigned int mask = ring->mask; unsigned int producer, consumer, delta; bool r = true; producer = ck_pr_load_uint(&ring->p_head); for (;;) { /* * The snapshot of producer must be up to date with respect to * consumer. */ ck_pr_fence_load(); consumer = ck_pr_load_uint(&ring->c_head); delta = producer + 1; /* * Only try to CAS if the producer is not clearly stale (not * less than consumer) and the buffer is definitely not full. */ if (CK_CC_LIKELY((producer - consumer) < mask)) { if (ck_pr_cas_uint_value(&ring->p_head, producer, delta, &producer) == true) { break; } } else { unsigned int new_producer; /* * Slow path. Either the buffer is full or we have a * stale snapshot of p_head. Execute a second read of * p_read that must be ordered wrt the snapshot of * c_head. */ ck_pr_fence_load(); new_producer = ck_pr_load_uint(&ring->p_head); /* * Only fail if we haven't made forward progress in * production: the buffer must have been full when we * read new_producer (or we wrapped around UINT_MAX * during this iteration). */ if (producer == new_producer) { r = false; goto leave; } /* * p_head advanced during this iteration. Try again. */ producer = new_producer; } } buffer = (char *)buffer + ts * (producer & mask); memcpy(buffer, entry, ts); /* * Wait until all concurrent producers have completed writing * their data into the ring buffer. */ while (ck_pr_load_uint(&ring->p_tail) != producer) ck_pr_stall(); /* * Ensure that copy is completed before updating shared producer * counter. */ ck_pr_fence_store(); ck_pr_store_uint(&ring->p_tail, delta); leave: if (size != NULL) *size = (producer - consumer) & mask; return r; } CK_CC_FORCE_INLINE static bool _ck_ring_enqueue_mp_size(struct ck_ring *ring, void *buffer, const void *entry, unsigned int ts, unsigned int *size) { unsigned int sz; bool r; r = _ck_ring_enqueue_mp(ring, buffer, entry, ts, &sz); *size = sz; return r; } CK_CC_FORCE_INLINE static bool _ck_ring_trydequeue_mc(struct ck_ring *ring, const void *buffer, void *data, unsigned int size) { const unsigned int mask = ring->mask; unsigned int consumer, producer; consumer = ck_pr_load_uint(&ring->c_head); ck_pr_fence_load(); producer = ck_pr_load_uint(&ring->p_tail); if (CK_CC_UNLIKELY(consumer == producer)) return false; ck_pr_fence_load(); buffer = (const char *)buffer + size * (consumer & mask); memcpy(data, buffer, size); ck_pr_fence_store_atomic(); return ck_pr_cas_uint(&ring->c_head, consumer, consumer + 1); } CK_CC_FORCE_INLINE static bool _ck_ring_dequeue_mc(struct ck_ring *ring, const void *buffer, void *data, unsigned int ts) { const unsigned int mask = ring->mask; unsigned int consumer, producer; consumer = ck_pr_load_uint(&ring->c_head); do { const char *target; /* * Producer counter must represent state relative to * our latest consumer snapshot. */ ck_pr_fence_load(); producer = ck_pr_load_uint(&ring->p_tail); if (CK_CC_UNLIKELY(consumer == producer)) return false; ck_pr_fence_load(); target = (const char *)buffer + ts * (consumer & mask); memcpy(data, target, ts); /* Serialize load with respect to head update. */ ck_pr_fence_store_atomic(); } while (ck_pr_cas_uint_value(&ring->c_head, consumer, consumer + 1, &consumer) == false); return true; } /* * The ck_ring_*_spsc namespace is the public interface for interacting with a * ring buffer containing pointers. Correctness is only provided if there is up * to one concurrent consumer and up to one concurrent producer. */ CK_CC_INLINE static bool ck_ring_enqueue_spsc_size(struct ck_ring *ring, struct ck_ring_buffer *buffer, const void *entry, unsigned int *size) { return _ck_ring_enqueue_sp_size(ring, buffer, &entry, sizeof(entry), size); } CK_CC_INLINE static bool ck_ring_enqueue_spsc(struct ck_ring *ring, struct ck_ring_buffer *buffer, const void *entry) { return _ck_ring_enqueue_sp(ring, buffer, &entry, sizeof(entry), NULL); } CK_CC_INLINE static bool ck_ring_dequeue_spsc(struct ck_ring *ring, const struct ck_ring_buffer *buffer, void *data) { return _ck_ring_dequeue_sc(ring, buffer, (void **)data, sizeof(void *)); } /* * The ck_ring_*_mpmc namespace is the public interface for interacting with a * ring buffer containing pointers. Correctness is provided for any number of * producers and consumers. */ CK_CC_INLINE static bool ck_ring_enqueue_mpmc(struct ck_ring *ring, struct ck_ring_buffer *buffer, const void *entry) { return _ck_ring_enqueue_mp(ring, buffer, &entry, sizeof(entry), NULL); } CK_CC_INLINE static bool ck_ring_enqueue_mpmc_size(struct ck_ring *ring, struct ck_ring_buffer *buffer, const void *entry, unsigned int *size) { return _ck_ring_enqueue_mp_size(ring, buffer, &entry, sizeof(entry), size); } CK_CC_INLINE static bool ck_ring_trydequeue_mpmc(struct ck_ring *ring, const struct ck_ring_buffer *buffer, void *data) { return _ck_ring_trydequeue_mc(ring, buffer, (void **)data, sizeof(void *)); } CK_CC_INLINE static bool ck_ring_dequeue_mpmc(struct ck_ring *ring, const struct ck_ring_buffer *buffer, void *data) { return _ck_ring_dequeue_mc(ring, buffer, (void **)data, sizeof(void *)); } /* * The ck_ring_*_spmc namespace is the public interface for interacting with a * ring buffer containing pointers. Correctness is provided for any number of * consumers with up to one concurrent producer. */ CK_CC_INLINE static bool ck_ring_enqueue_spmc_size(struct ck_ring *ring, struct ck_ring_buffer *buffer, const void *entry, unsigned int *size) { return _ck_ring_enqueue_sp_size(ring, buffer, &entry, sizeof(entry), size); } CK_CC_INLINE static bool ck_ring_enqueue_spmc(struct ck_ring *ring, struct ck_ring_buffer *buffer, const void *entry) { return _ck_ring_enqueue_sp(ring, buffer, &entry, sizeof(entry), NULL); } CK_CC_INLINE static bool ck_ring_trydequeue_spmc(struct ck_ring *ring, const struct ck_ring_buffer *buffer, void *data) { return _ck_ring_trydequeue_mc(ring, buffer, (void **)data, sizeof(void *)); } CK_CC_INLINE static bool ck_ring_dequeue_spmc(struct ck_ring *ring, const struct ck_ring_buffer *buffer, void *data) { return _ck_ring_dequeue_mc(ring, buffer, (void **)data, sizeof(void *)); } /* * The ck_ring_*_mpsc namespace is the public interface for interacting with a * ring buffer containing pointers. Correctness is provided for any number of * producers with up to one concurrent consumers. */ CK_CC_INLINE static bool ck_ring_enqueue_mpsc(struct ck_ring *ring, struct ck_ring_buffer *buffer, const void *entry) { return _ck_ring_enqueue_mp(ring, buffer, &entry, sizeof(entry), NULL); } CK_CC_INLINE static bool ck_ring_enqueue_mpsc_size(struct ck_ring *ring, struct ck_ring_buffer *buffer, const void *entry, unsigned int *size) { return _ck_ring_enqueue_mp_size(ring, buffer, &entry, sizeof(entry), size); } CK_CC_INLINE static bool ck_ring_dequeue_mpsc(struct ck_ring *ring, const struct ck_ring_buffer *buffer, void *data) { return _ck_ring_dequeue_sc(ring, buffer, (void **)data, sizeof(void *)); } /* * CK_RING_PROTOTYPE is used to define a type-safe interface for inlining * values of a particular type in the ring the buffer. */ #define CK_RING_PROTOTYPE(name, type) \ CK_CC_INLINE static bool \ ck_ring_enqueue_spsc_size_##name(struct ck_ring *a, \ struct type *b, \ struct type *c, \ unsigned int *d) \ { \ \ return _ck_ring_enqueue_sp_size(a, b, c, \ sizeof(struct type), d); \ } \ \ CK_CC_INLINE static bool \ ck_ring_enqueue_spsc_##name(struct ck_ring *a, \ struct type *b, \ struct type *c) \ { \ \ return _ck_ring_enqueue_sp(a, b, c, \ sizeof(struct type), NULL); \ } \ \ CK_CC_INLINE static bool \ ck_ring_dequeue_spsc_##name(struct ck_ring *a, \ struct type *b, \ struct type *c) \ { \ \ return _ck_ring_dequeue_sc(a, b, c, \ sizeof(struct type)); \ } \ \ CK_CC_INLINE static bool \ ck_ring_enqueue_spmc_size_##name(struct ck_ring *a, \ struct type *b, \ struct type *c, \ unsigned int *d) \ { \ \ return _ck_ring_enqueue_sp_size(a, b, c, \ sizeof(struct type), d); \ } \ \ CK_CC_INLINE static bool \ ck_ring_enqueue_spmc_##name(struct ck_ring *a, \ struct type *b, \ struct type *c) \ { \ \ return _ck_ring_enqueue_sp(a, b, c, \ sizeof(struct type), NULL); \ } \ \ CK_CC_INLINE static bool \ ck_ring_trydequeue_spmc_##name(struct ck_ring *a, \ struct type *b, \ struct type *c) \ { \ \ return _ck_ring_trydequeue_mc(a, \ b, c, sizeof(struct type)); \ } \ \ CK_CC_INLINE static bool \ ck_ring_dequeue_spmc_##name(struct ck_ring *a, \ struct type *b, \ struct type *c) \ { \ \ return _ck_ring_dequeue_mc(a, b, c, \ sizeof(struct type)); \ } \ \ CK_CC_INLINE static bool \ ck_ring_enqueue_mpsc_##name(struct ck_ring *a, \ struct type *b, \ struct type *c) \ { \ \ return _ck_ring_enqueue_mp(a, b, c, \ sizeof(struct type), NULL); \ } \ \ CK_CC_INLINE static bool \ ck_ring_enqueue_mpsc_size_##name(struct ck_ring *a, \ struct type *b, \ struct type *c, \ unsigned int *d) \ { \ \ return _ck_ring_enqueue_mp_size(a, b, c, \ sizeof(struct type), d); \ } \ \ CK_CC_INLINE static bool \ ck_ring_dequeue_mpsc_##name(struct ck_ring *a, \ struct type *b, \ struct type *c) \ { \ \ return _ck_ring_dequeue_sc(a, b, c, \ sizeof(struct type)); \ } \ \ CK_CC_INLINE static bool \ ck_ring_enqueue_mpmc_size_##name(struct ck_ring *a, \ struct type *b, \ struct type *c, \ unsigned int *d) \ { \ \ return _ck_ring_enqueue_mp_size(a, b, c, \ sizeof(struct type), d); \ } \ \ CK_CC_INLINE static bool \ ck_ring_enqueue_mpmc_##name(struct ck_ring *a, \ struct type *b, \ struct type *c) \ { \ \ return _ck_ring_enqueue_mp(a, b, c, \ sizeof(struct type), NULL); \ } \ \ CK_CC_INLINE static bool \ ck_ring_trydequeue_mpmc_##name(struct ck_ring *a, \ struct type *b, \ struct type *c) \ { \ \ return _ck_ring_trydequeue_mc(a, \ b, c, sizeof(struct type)); \ } \ \ CK_CC_INLINE static bool \ ck_ring_dequeue_mpmc_##name(struct ck_ring *a, \ struct type *b, \ struct type *c) \ { \ \ return _ck_ring_dequeue_mc(a, b, c, \ sizeof(struct type)); \ } /* * A single producer with one concurrent consumer. */ #define CK_RING_ENQUEUE_SPSC(name, a, b, c) \ ck_ring_enqueue_spsc_##name(a, b, c) #define CK_RING_ENQUEUE_SPSC_SIZE(name, a, b, c, d) \ ck_ring_enqueue_spsc_size_##name(a, b, c, d) #define CK_RING_DEQUEUE_SPSC(name, a, b, c) \ ck_ring_dequeue_spsc_##name(a, b, c) /* * A single producer with any number of concurrent consumers. */ #define CK_RING_ENQUEUE_SPMC(name, a, b, c) \ ck_ring_enqueue_spmc_##name(a, b, c) #define CK_RING_ENQUEUE_SPMC_SIZE(name, a, b, c, d) \ ck_ring_enqueue_spmc_size_##name(a, b, c, d) #define CK_RING_TRYDEQUEUE_SPMC(name, a, b, c) \ ck_ring_trydequeue_spmc_##name(a, b, c) #define CK_RING_DEQUEUE_SPMC(name, a, b, c) \ ck_ring_dequeue_spmc_##name(a, b, c) /* * Any number of concurrent producers with up to one * concurrent consumer. */ #define CK_RING_ENQUEUE_MPSC(name, a, b, c) \ ck_ring_enqueue_mpsc_##name(a, b, c) #define CK_RING_ENQUEUE_MPSC_SIZE(name, a, b, c, d) \ ck_ring_enqueue_mpsc_size_##name(a, b, c, d) #define CK_RING_DEQUEUE_MPSC(name, a, b, c) \ ck_ring_dequeue_mpsc_##name(a, b, c) /* * Any number of concurrent producers and consumers. */ #define CK_RING_ENQUEUE_MPMC(name, a, b, c) \ ck_ring_enqueue_mpmc_##name(a, b, c) #define CK_RING_ENQUEUE_MPMC_SIZE(name, a, b, c, d) \ ck_ring_enqueue_mpmc_size_##name(a, b, c, d) #define CK_RING_TRYDEQUEUE_MPMC(name, a, b, c) \ ck_ring_trydequeue_mpmc_##name(a, b, c) #define CK_RING_DEQUEUE_MPMC(name, a, b, c) \ ck_ring_dequeue_mpmc_##name(a, b, c) #endif /* CK_RING_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_rwcohort.h ================================================ /* * Copyright 2013-2015 Samy Al Bahra. * Copyright 2013 Brendon Scheinman. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_RWCOHORT_H #define CK_RWCOHORT_H /* * This is an implementation of NUMA-aware reader-writer locks as described in: * Calciu, I.; Dice, D.; Lev, Y.; Luchangco, V.; Marathe, V.; and Shavit, N. 2014. * NUMA-Aware Reader-Writer Locks */ #include #include #include #include #define CK_RWCOHORT_WP_NAME(N) ck_rwcohort_wp_##N #define CK_RWCOHORT_WP_INSTANCE(N) struct CK_RWCOHORT_WP_NAME(N) #define CK_RWCOHORT_WP_INIT(N, RW, WL) ck_rwcohort_wp_##N##_init(RW, WL) #define CK_RWCOHORT_WP_READ_LOCK(N, RW, C, GC, LC) \ ck_rwcohort_wp_##N##_read_lock(RW, C, GC, LC) #define CK_RWCOHORT_WP_READ_UNLOCK(N, RW, C, GC, LC) \ ck_rwcohort_wp_##N##_read_unlock(RW) #define CK_RWCOHORT_WP_WRITE_LOCK(N, RW, C, GC, LC) \ ck_rwcohort_wp_##N##_write_lock(RW, C, GC, LC) #define CK_RWCOHORT_WP_WRITE_UNLOCK(N, RW, C, GC, LC) \ ck_rwcohort_wp_##N##_write_unlock(RW, C, GC, LC) #define CK_RWCOHORT_WP_DEFAULT_WAIT_LIMIT 1000 #define CK_RWCOHORT_WP_PROTOTYPE(N) \ CK_RWCOHORT_WP_INSTANCE(N) { \ unsigned int read_counter; \ unsigned int write_barrier; \ unsigned int wait_limit; \ }; \ CK_CC_INLINE static void \ ck_rwcohort_wp_##N##_init(CK_RWCOHORT_WP_INSTANCE(N) *rw_cohort, \ unsigned int wait_limit) \ { \ \ rw_cohort->read_counter = 0; \ rw_cohort->write_barrier = 0; \ rw_cohort->wait_limit = wait_limit; \ ck_pr_barrier(); \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_wp_##N##_write_lock(CK_RWCOHORT_WP_INSTANCE(N) *rw_cohort, \ CK_COHORT_INSTANCE(N) *cohort, void *global_context, \ void *local_context) \ { \ \ while (ck_pr_load_uint(&rw_cohort->write_barrier) > 0) \ ck_pr_stall(); \ \ CK_COHORT_LOCK(N, cohort, global_context, local_context); \ \ while (ck_pr_load_uint(&rw_cohort->read_counter) > 0) \ ck_pr_stall(); \ \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_wp_##N##_write_unlock(CK_RWCOHORT_WP_INSTANCE(N) *rw_cohort, \ CK_COHORT_INSTANCE(N) *cohort, void *global_context, \ void *local_context) \ { \ \ (void)rw_cohort; \ CK_COHORT_UNLOCK(N, cohort, global_context, local_context); \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_wp_##N##_read_lock(CK_RWCOHORT_WP_INSTANCE(N) *rw_cohort, \ CK_COHORT_INSTANCE(N) *cohort, void *global_context, \ void *local_context) \ { \ unsigned int wait_count = 0; \ bool raised = false; \ \ for (;;) { \ ck_pr_inc_uint(&rw_cohort->read_counter); \ ck_pr_fence_atomic_load(); \ if (CK_COHORT_LOCKED(N, cohort, global_context, \ local_context) == false) \ break; \ \ ck_pr_dec_uint(&rw_cohort->read_counter); \ while (CK_COHORT_LOCKED(N, cohort, global_context, \ local_context) == true) { \ ck_pr_stall(); \ if (++wait_count > rw_cohort->wait_limit && \ raised == false) { \ ck_pr_inc_uint(&rw_cohort->write_barrier); \ raised = true; \ } \ } \ } \ \ if (raised == true) \ ck_pr_dec_uint(&rw_cohort->write_barrier); \ \ ck_pr_fence_load(); \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_wp_##N##_read_unlock(CK_RWCOHORT_WP_INSTANCE(N) *cohort) \ { \ \ ck_pr_fence_load_atomic(); \ ck_pr_dec_uint(&cohort->read_counter); \ return; \ } #define CK_RWCOHORT_WP_INITIALIZER { \ .read_counter = 0, \ .write_barrier = 0, \ .wait_limit = 0 \ } #define CK_RWCOHORT_RP_NAME(N) ck_rwcohort_rp_##N #define CK_RWCOHORT_RP_INSTANCE(N) struct CK_RWCOHORT_RP_NAME(N) #define CK_RWCOHORT_RP_INIT(N, RW, WL) ck_rwcohort_rp_##N##_init(RW, WL) #define CK_RWCOHORT_RP_READ_LOCK(N, RW, C, GC, LC) \ ck_rwcohort_rp_##N##_read_lock(RW, C, GC, LC) #define CK_RWCOHORT_RP_READ_UNLOCK(N, RW, C, GC, LC) \ ck_rwcohort_rp_##N##_read_unlock(RW) #define CK_RWCOHORT_RP_WRITE_LOCK(N, RW, C, GC, LC) \ ck_rwcohort_rp_##N##_write_lock(RW, C, GC, LC) #define CK_RWCOHORT_RP_WRITE_UNLOCK(N, RW, C, GC, LC) \ ck_rwcohort_rp_##N##_write_unlock(RW, C, GC, LC) #define CK_RWCOHORT_RP_DEFAULT_WAIT_LIMIT 1000 #define CK_RWCOHORT_RP_PROTOTYPE(N) \ CK_RWCOHORT_RP_INSTANCE(N) { \ unsigned int read_counter; \ unsigned int read_barrier; \ unsigned int wait_limit; \ }; \ CK_CC_INLINE static void \ ck_rwcohort_rp_##N##_init(CK_RWCOHORT_RP_INSTANCE(N) *rw_cohort, \ unsigned int wait_limit) \ { \ \ rw_cohort->read_counter = 0; \ rw_cohort->read_barrier = 0; \ rw_cohort->wait_limit = wait_limit; \ ck_pr_barrier(); \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_rp_##N##_write_lock(CK_RWCOHORT_RP_INSTANCE(N) *rw_cohort, \ CK_COHORT_INSTANCE(N) *cohort, void *global_context, \ void *local_context) \ { \ unsigned int wait_count = 0; \ bool raised = false; \ \ for (;;) { \ CK_COHORT_LOCK(N, cohort, global_context, local_context); \ if (ck_pr_load_uint(&rw_cohort->read_counter) == 0) \ break; \ \ CK_COHORT_UNLOCK(N, cohort, global_context, local_context); \ while (ck_pr_load_uint(&rw_cohort->read_counter) > 0) { \ ck_pr_stall(); \ if (++wait_count > rw_cohort->wait_limit && \ raised == false) { \ ck_pr_inc_uint(&rw_cohort->read_barrier); \ raised = true; \ } \ } \ } \ \ if (raised == true) \ ck_pr_dec_uint(&rw_cohort->read_barrier); \ \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_rp_##N##_write_unlock(CK_RWCOHORT_RP_INSTANCE(N) *rw_cohort, \ CK_COHORT_INSTANCE(N) *cohort, void *global_context, void *local_context) \ { \ \ (void)rw_cohort; \ CK_COHORT_UNLOCK(N, cohort, global_context, local_context); \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_rp_##N##_read_lock(CK_RWCOHORT_RP_INSTANCE(N) *rw_cohort, \ CK_COHORT_INSTANCE(N) *cohort, void *global_context, \ void *local_context) \ { \ \ while (ck_pr_load_uint(&rw_cohort->read_barrier) > 0) \ ck_pr_stall(); \ \ ck_pr_inc_uint(&rw_cohort->read_counter); \ ck_pr_fence_atomic_load(); \ \ while (CK_COHORT_LOCKED(N, cohort, global_context, \ local_context) == true) \ ck_pr_stall(); \ \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_rp_##N##_read_unlock(CK_RWCOHORT_RP_INSTANCE(N) *cohort) \ { \ \ ck_pr_fence_load_atomic(); \ ck_pr_dec_uint(&cohort->read_counter); \ return; \ } #define CK_RWCOHORT_RP_INITIALIZER { \ .read_counter = 0, \ .read_barrier = 0, \ .wait_limit = 0 \ } #define CK_RWCOHORT_NEUTRAL_NAME(N) ck_rwcohort_neutral_##N #define CK_RWCOHORT_NEUTRAL_INSTANCE(N) struct CK_RWCOHORT_NEUTRAL_NAME(N) #define CK_RWCOHORT_NEUTRAL_INIT(N, RW) ck_rwcohort_neutral_##N##_init(RW) #define CK_RWCOHORT_NEUTRAL_READ_LOCK(N, RW, C, GC, LC) \ ck_rwcohort_neutral_##N##_read_lock(RW, C, GC, LC) #define CK_RWCOHORT_NEUTRAL_READ_UNLOCK(N, RW, C, GC, LC) \ ck_rwcohort_neutral_##N##_read_unlock(RW) #define CK_RWCOHORT_NEUTRAL_WRITE_LOCK(N, RW, C, GC, LC) \ ck_rwcohort_neutral_##N##_write_lock(RW, C, GC, LC) #define CK_RWCOHORT_NEUTRAL_WRITE_UNLOCK(N, RW, C, GC, LC) \ ck_rwcohort_neutral_##N##_write_unlock(RW, C, GC, LC) #define CK_RWCOHORT_NEUTRAL_DEFAULT_WAIT_LIMIT 1000 #define CK_RWCOHORT_NEUTRAL_PROTOTYPE(N) \ CK_RWCOHORT_NEUTRAL_INSTANCE(N) { \ unsigned int read_counter; \ }; \ CK_CC_INLINE static void \ ck_rwcohort_neutral_##N##_init(CK_RWCOHORT_NEUTRAL_INSTANCE(N) *rw_cohort) \ { \ \ rw_cohort->read_counter = 0; \ ck_pr_barrier(); \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_neutral_##N##_write_lock(CK_RWCOHORT_NEUTRAL_INSTANCE(N) *rw_cohort,\ CK_COHORT_INSTANCE(N) *cohort, void *global_context, \ void *local_context) \ { \ \ CK_COHORT_LOCK(N, cohort, global_context, local_context); \ while (ck_pr_load_uint(&rw_cohort->read_counter) > 0) { \ ck_pr_stall(); \ } \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_neutral_##N##_write_unlock(CK_RWCOHORT_NEUTRAL_INSTANCE(N) *rw_cohort,\ CK_COHORT_INSTANCE(N) *cohort, void *global_context, void *local_context) \ { \ \ (void)rw_cohort; \ CK_COHORT_UNLOCK(N, cohort, global_context, local_context); \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_neutral_##N##_read_lock(CK_RWCOHORT_NEUTRAL_INSTANCE(N) *rw_cohort, \ CK_COHORT_INSTANCE(N) *cohort, void *global_context, \ void *local_context) \ { \ \ CK_COHORT_LOCK(N, cohort, global_context, local_context); \ ck_pr_inc_uint(&rw_cohort->read_counter); \ CK_COHORT_UNLOCK(N, cohort, global_context, local_context); \ return; \ } \ CK_CC_INLINE static void \ ck_rwcohort_neutral_##N##_read_unlock(CK_RWCOHORT_NEUTRAL_INSTANCE(N) *cohort) \ { \ \ ck_pr_fence_load_atomic(); \ ck_pr_dec_uint(&cohort->read_counter); \ return; \ } #define CK_RWCOHORT_NEUTRAL_INITIALIZER { \ .read_counter = 0, \ } #endif /* CK_RWCOHORT_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_rwlock.h ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_RWLOCK_H #define CK_RWLOCK_H #include #include #include #include struct ck_rwlock { unsigned int writer; unsigned int n_readers; }; typedef struct ck_rwlock ck_rwlock_t; #define CK_RWLOCK_INITIALIZER {0, 0} CK_CC_INLINE static void ck_rwlock_init(struct ck_rwlock *rw) { rw->writer = 0; rw->n_readers = 0; ck_pr_barrier(); return; } CK_CC_INLINE static void ck_rwlock_write_unlock(ck_rwlock_t *rw) { ck_pr_fence_unlock(); ck_pr_store_uint(&rw->writer, 0); return; } CK_CC_INLINE static bool ck_rwlock_locked_writer(ck_rwlock_t *rw) { bool r; r = ck_pr_load_uint(&rw->writer); ck_pr_fence_acquire(); return r; } CK_CC_INLINE static void ck_rwlock_write_downgrade(ck_rwlock_t *rw) { ck_pr_inc_uint(&rw->n_readers); ck_rwlock_write_unlock(rw); return; } CK_CC_INLINE static bool ck_rwlock_locked(ck_rwlock_t *rw) { bool l; l = ck_pr_load_uint(&rw->n_readers) | ck_pr_load_uint(&rw->writer); ck_pr_fence_acquire(); return l; } CK_CC_INLINE static bool ck_rwlock_write_trylock(ck_rwlock_t *rw) { if (ck_pr_fas_uint(&rw->writer, 1) != 0) return false; ck_pr_fence_atomic_load(); if (ck_pr_load_uint(&rw->n_readers) != 0) { ck_rwlock_write_unlock(rw); return false; } ck_pr_fence_lock(); return true; } CK_ELIDE_TRYLOCK_PROTOTYPE(ck_rwlock_write, ck_rwlock_t, ck_rwlock_locked, ck_rwlock_write_trylock) CK_CC_INLINE static void ck_rwlock_write_lock(ck_rwlock_t *rw) { while (ck_pr_fas_uint(&rw->writer, 1) != 0) ck_pr_stall(); ck_pr_fence_atomic_load(); while (ck_pr_load_uint(&rw->n_readers) != 0) ck_pr_stall(); ck_pr_fence_lock(); return; } CK_ELIDE_PROTOTYPE(ck_rwlock_write, ck_rwlock_t, ck_rwlock_locked, ck_rwlock_write_lock, ck_rwlock_locked_writer, ck_rwlock_write_unlock) CK_CC_INLINE static bool ck_rwlock_read_trylock(ck_rwlock_t *rw) { if (ck_pr_load_uint(&rw->writer) != 0) return false; ck_pr_inc_uint(&rw->n_readers); /* * Serialize with respect to concurrent write * lock operation. */ ck_pr_fence_atomic_load(); if (ck_pr_load_uint(&rw->writer) == 0) { ck_pr_fence_lock(); return true; } ck_pr_dec_uint(&rw->n_readers); return false; } CK_ELIDE_TRYLOCK_PROTOTYPE(ck_rwlock_read, ck_rwlock_t, ck_rwlock_locked_writer, ck_rwlock_read_trylock) CK_CC_INLINE static void ck_rwlock_read_lock(ck_rwlock_t *rw) { for (;;) { while (ck_pr_load_uint(&rw->writer) != 0) ck_pr_stall(); ck_pr_inc_uint(&rw->n_readers); /* * Serialize with respect to concurrent write * lock operation. */ ck_pr_fence_atomic_load(); if (ck_pr_load_uint(&rw->writer) == 0) break; ck_pr_dec_uint(&rw->n_readers); } /* Acquire semantics are necessary. */ ck_pr_fence_load(); return; } CK_CC_INLINE static bool ck_rwlock_locked_reader(ck_rwlock_t *rw) { ck_pr_fence_load(); return ck_pr_load_uint(&rw->n_readers); } CK_CC_INLINE static void ck_rwlock_read_unlock(ck_rwlock_t *rw) { ck_pr_fence_load_atomic(); ck_pr_dec_uint(&rw->n_readers); return; } CK_ELIDE_PROTOTYPE(ck_rwlock_read, ck_rwlock_t, ck_rwlock_locked_writer, ck_rwlock_read_lock, ck_rwlock_locked_reader, ck_rwlock_read_unlock) /* * Recursive writer reader-writer lock implementation. */ struct ck_rwlock_recursive { struct ck_rwlock rw; unsigned int wc; }; typedef struct ck_rwlock_recursive ck_rwlock_recursive_t; #define CK_RWLOCK_RECURSIVE_INITIALIZER {CK_RWLOCK_INITIALIZER, 0} CK_CC_INLINE static void ck_rwlock_recursive_write_lock(ck_rwlock_recursive_t *rw, unsigned int tid) { unsigned int o; o = ck_pr_load_uint(&rw->rw.writer); if (o == tid) goto leave; while (ck_pr_cas_uint(&rw->rw.writer, 0, tid) == false) ck_pr_stall(); ck_pr_fence_atomic_load(); while (ck_pr_load_uint(&rw->rw.n_readers) != 0) ck_pr_stall(); ck_pr_fence_lock(); leave: rw->wc++; return; } CK_CC_INLINE static bool ck_rwlock_recursive_write_trylock(ck_rwlock_recursive_t *rw, unsigned int tid) { unsigned int o; o = ck_pr_load_uint(&rw->rw.writer); if (o == tid) goto leave; if (ck_pr_cas_uint(&rw->rw.writer, 0, tid) == false) return false; ck_pr_fence_atomic_load(); if (ck_pr_load_uint(&rw->rw.n_readers) != 0) { ck_pr_store_uint(&rw->rw.writer, 0); return false; } ck_pr_fence_lock(); leave: rw->wc++; return true; } CK_CC_INLINE static void ck_rwlock_recursive_write_unlock(ck_rwlock_recursive_t *rw) { if (--rw->wc == 0) { ck_pr_fence_unlock(); ck_pr_store_uint(&rw->rw.writer, 0); } return; } CK_CC_INLINE static void ck_rwlock_recursive_read_lock(ck_rwlock_recursive_t *rw) { ck_rwlock_read_lock(&rw->rw); return; } CK_CC_INLINE static bool ck_rwlock_recursive_read_trylock(ck_rwlock_recursive_t *rw) { return ck_rwlock_read_trylock(&rw->rw); } CK_CC_INLINE static void ck_rwlock_recursive_read_unlock(ck_rwlock_recursive_t *rw) { ck_rwlock_read_unlock(&rw->rw); return; } #endif /* CK_RWLOCK_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_sequence.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_SEQUENCE_H #define CK_SEQUENCE_H #include #include #include struct ck_sequence { unsigned int sequence; }; typedef struct ck_sequence ck_sequence_t; #define CK_SEQUENCE_INITIALIZER { .sequence = 0 } CK_CC_INLINE static void ck_sequence_init(struct ck_sequence *sq) { ck_pr_store_uint(&sq->sequence, 0); return; } CK_CC_INLINE static unsigned int ck_sequence_read_begin(const struct ck_sequence *sq) { unsigned int version; for (;;) { version = ck_pr_load_uint(&sq->sequence); /* * If a sequence is even then associated data may be in a * consistent state. */ if (CK_CC_LIKELY((version & 1) == 0)) break; /* * If a sequence is odd then a thread is in the middle of an * update. Retry the read to avoid operating on inconsistent * data. */ ck_pr_stall(); } ck_pr_fence_load(); return version; } CK_CC_INLINE static bool ck_sequence_read_retry(const struct ck_sequence *sq, unsigned int version) { /* * If the sequence number was updated then a read should be * re-attempted. */ ck_pr_fence_load(); return ck_pr_load_uint(&sq->sequence) != version; } #define CK_SEQUENCE_READ(seqlock, version) \ for (*(version) = 1; \ (*(version) != 0) && (*(version) = ck_sequence_read_begin(seqlock), 1); \ *(version) = ck_sequence_read_retry(seqlock, *(version))) /* * This must be called after a successful mutex acquisition. */ CK_CC_INLINE static void ck_sequence_write_begin(struct ck_sequence *sq) { /* * Increment the sequence to an odd number to indicate * the beginning of a write update. */ ck_pr_store_uint(&sq->sequence, sq->sequence + 1); ck_pr_fence_store(); return; } /* * This must be called before mutex ownership is relinquished. */ CK_CC_INLINE static void ck_sequence_write_end(struct ck_sequence *sq) { /* * Increment the sequence to an even number to indicate * completion of a write update. */ ck_pr_fence_store(); ck_pr_store_uint(&sq->sequence, sq->sequence + 1); return; } #endif /* CK_SEQUENCE_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_spinlock.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_SPINLOCK_H #define CK_SPINLOCK_H #include "spinlock/anderson.h" #include "spinlock/cas.h" #include "spinlock/clh.h" #include "spinlock/dec.h" #include "spinlock/fas.h" #include "spinlock/hclh.h" #include "spinlock/mcs.h" #include "spinlock/ticket.h" /* * On tested x86, x86_64, PPC64 and SPARC64 targets, * ck_spinlock_fas proved to have lowest latency * in fast path testing or negligible degradation * from faster but less robust implementations. */ #define CK_SPINLOCK_INITIALIZER CK_SPINLOCK_FAS_INITIALIZER #define ck_spinlock_t ck_spinlock_fas_t #define ck_spinlock_init(x) ck_spinlock_fas_init(x) #define ck_spinlock_lock(x) ck_spinlock_fas_lock(x) #define ck_spinlock_lock_eb(x) ck_spinlock_fas_lock_eb(x) #define ck_spinlock_unlock(x) ck_spinlock_fas_unlock(x) #define ck_spinlock_locked(x) ck_spinlock_fas_locked(x) #define ck_spinlock_trylock(x) ck_spinlock_fas_trylock(x) CK_ELIDE_PROTOTYPE(ck_spinlock, ck_spinlock_t, ck_spinlock_locked, ck_spinlock_lock, ck_spinlock_locked, ck_spinlock_unlock) CK_ELIDE_TRYLOCK_PROTOTYPE(ck_spinlock, ck_spinlock_t, ck_spinlock_locked, ck_spinlock_trylock) #endif /* CK_SPINLOCK_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_stack.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_STACK_H #define CK_STACK_H #include #include #include #include struct ck_stack_entry { struct ck_stack_entry *next; }; typedef struct ck_stack_entry ck_stack_entry_t; struct ck_stack { struct ck_stack_entry *head; char *generation CK_CC_PACKED; } CK_CC_ALIASED; typedef struct ck_stack ck_stack_t; #define CK_STACK_INITIALIZER { NULL, NULL } #ifndef CK_F_STACK_PUSH_UPMC #define CK_F_STACK_PUSH_UPMC /* * Stack producer operation safe for multiple unique producers and multiple consumers. */ CK_CC_INLINE static void ck_stack_push_upmc(struct ck_stack *target, struct ck_stack_entry *entry) { struct ck_stack_entry *stack; stack = ck_pr_load_ptr(&target->head); entry->next = stack; ck_pr_fence_store(); while (ck_pr_cas_ptr_value(&target->head, stack, entry, &stack) == false) { entry->next = stack; ck_pr_fence_store(); } return; } #endif /* CK_F_STACK_PUSH_UPMC */ #ifndef CK_F_STACK_TRYPUSH_UPMC #define CK_F_STACK_TRYPUSH_UPMC /* * Stack producer operation for multiple unique producers and multiple consumers. * Returns true on success and false on failure. */ CK_CC_INLINE static bool ck_stack_trypush_upmc(struct ck_stack *target, struct ck_stack_entry *entry) { struct ck_stack_entry *stack; stack = ck_pr_load_ptr(&target->head); entry->next = stack; ck_pr_fence_store(); return ck_pr_cas_ptr(&target->head, stack, entry); } #endif /* CK_F_STACK_TRYPUSH_UPMC */ #ifndef CK_F_STACK_POP_UPMC #define CK_F_STACK_POP_UPMC /* * Stack consumer operation safe for multiple unique producers and multiple consumers. */ CK_CC_INLINE static struct ck_stack_entry * ck_stack_pop_upmc(struct ck_stack *target) { struct ck_stack_entry *entry, *next; entry = ck_pr_load_ptr(&target->head); if (entry == NULL) return NULL; ck_pr_fence_load(); next = entry->next; while (ck_pr_cas_ptr_value(&target->head, entry, next, &entry) == false) { if (entry == NULL) break; ck_pr_fence_load(); next = entry->next; } return entry; } #endif #ifndef CK_F_STACK_TRYPOP_UPMC #define CK_F_STACK_TRYPOP_UPMC /* * Stack production operation for multiple unique producers and multiple consumers. * Returns true on success and false on failure. The value pointed to by the second * argument is set to a valid ck_stack_entry_t reference if true is returned. If * false is returned, then the value pointed to by the second argument is undefined. */ CK_CC_INLINE static bool ck_stack_trypop_upmc(struct ck_stack *target, struct ck_stack_entry **r) { struct ck_stack_entry *entry; entry = ck_pr_load_ptr(&target->head); if (entry == NULL) return false; ck_pr_fence_load(); if (ck_pr_cas_ptr(&target->head, entry, entry->next) == true) { *r = entry; return true; } return false; } #endif /* CK_F_STACK_TRYPOP_UPMC */ #ifndef CK_F_STACK_BATCH_POP_UPMC #define CK_F_STACK_BATCH_POP_UPMC /* * Pop all items off the stack. */ CK_CC_INLINE static struct ck_stack_entry * ck_stack_batch_pop_upmc(struct ck_stack *target) { struct ck_stack_entry *entry; entry = ck_pr_fas_ptr(&target->head, NULL); ck_pr_fence_load(); return entry; } #endif /* CK_F_STACK_BATCH_POP_UPMC */ #ifndef CK_F_STACK_PUSH_MPMC #define CK_F_STACK_PUSH_MPMC /* * Stack producer operation safe for multiple producers and multiple consumers. */ CK_CC_INLINE static void ck_stack_push_mpmc(struct ck_stack *target, struct ck_stack_entry *entry) { ck_stack_push_upmc(target, entry); return; } #endif /* CK_F_STACK_PUSH_MPMC */ #ifndef CK_F_STACK_TRYPUSH_MPMC #define CK_F_STACK_TRYPUSH_MPMC /* * Stack producer operation safe for multiple producers and multiple consumers. */ CK_CC_INLINE static bool ck_stack_trypush_mpmc(struct ck_stack *target, struct ck_stack_entry *entry) { return ck_stack_trypush_upmc(target, entry); } #endif /* CK_F_STACK_TRYPUSH_MPMC */ #ifdef CK_F_PR_CAS_PTR_2_VALUE #ifndef CK_F_STACK_POP_MPMC #define CK_F_STACK_POP_MPMC /* * Stack consumer operation safe for multiple producers and multiple consumers. */ CK_CC_INLINE static struct ck_stack_entry * ck_stack_pop_mpmc(struct ck_stack *target) { struct ck_stack original, update; original.generation = ck_pr_load_ptr(&target->generation); ck_pr_fence_load(); original.head = ck_pr_load_ptr(&target->head); if (original.head == NULL) return NULL; /* Order with respect to next pointer. */ ck_pr_fence_load(); update.generation = original.generation + 1; update.head = original.head->next; while (ck_pr_cas_ptr_2_value(target, &original, &update, &original) == false) { if (original.head == NULL) return NULL; update.generation = original.generation + 1; /* Order with respect to next pointer. */ ck_pr_fence_load(); update.head = original.head->next; } return original.head; } #endif /* CK_F_STACK_POP_MPMC */ #ifndef CK_F_STACK_TRYPOP_MPMC #define CK_F_STACK_TRYPOP_MPMC CK_CC_INLINE static bool ck_stack_trypop_mpmc(struct ck_stack *target, struct ck_stack_entry **r) { struct ck_stack original, update; original.generation = ck_pr_load_ptr(&target->generation); ck_pr_fence_load(); original.head = ck_pr_load_ptr(&target->head); if (original.head == NULL) return false; update.generation = original.generation + 1; ck_pr_fence_load(); update.head = original.head->next; if (ck_pr_cas_ptr_2_value(target, &original, &update, &original) == true) { *r = original.head; return true; } return false; } #endif /* CK_F_STACK_TRYPOP_MPMC */ #endif /* CK_F_PR_CAS_PTR_2_VALUE */ #ifndef CK_F_STACK_BATCH_POP_MPMC #define CK_F_STACK_BATCH_POP_MPMC /* * This is equivalent to the UP/MC version as NULL does not need a * a generation count. */ CK_CC_INLINE static struct ck_stack_entry * ck_stack_batch_pop_mpmc(struct ck_stack *target) { return ck_stack_batch_pop_upmc(target); } #endif /* CK_F_STACK_BATCH_POP_MPMC */ #ifndef CK_F_STACK_PUSH_MPNC #define CK_F_STACK_PUSH_MPNC /* * Stack producer operation safe with no concurrent consumers. */ CK_CC_INLINE static void ck_stack_push_mpnc(struct ck_stack *target, struct ck_stack_entry *entry) { struct ck_stack_entry *stack; entry->next = NULL; ck_pr_fence_store_atomic(); stack = ck_pr_fas_ptr(&target->head, entry); ck_pr_store_ptr(&entry->next, stack); ck_pr_fence_store(); return; } #endif /* CK_F_STACK_PUSH_MPNC */ /* * Stack producer operation for single producer and no concurrent consumers. */ CK_CC_INLINE static void ck_stack_push_spnc(struct ck_stack *target, struct ck_stack_entry *entry) { entry->next = target->head; target->head = entry; return; } /* * Stack consumer operation for no concurrent producers and single consumer. */ CK_CC_INLINE static struct ck_stack_entry * ck_stack_pop_npsc(struct ck_stack *target) { struct ck_stack_entry *n; if (target->head == NULL) return NULL; n = target->head; target->head = n->next; return n; } /* * Pop all items off a stack. */ CK_CC_INLINE static struct ck_stack_entry * ck_stack_batch_pop_npsc(struct ck_stack *target) { struct ck_stack_entry *n; n = target->head; target->head = NULL; return n; } /* * Stack initialization function. Guarantees initialization across processors. */ CK_CC_INLINE static void ck_stack_init(struct ck_stack *stack) { stack->head = NULL; stack->generation = NULL; return; } /* Defines a container_of functions for */ #define CK_STACK_CONTAINER(T, M, N) CK_CC_CONTAINER(ck_stack_entry_t, T, M, N) #define CK_STACK_ISEMPTY(m) ((m)->head == NULL) #define CK_STACK_FIRST(s) ((s)->head) #define CK_STACK_NEXT(m) ((m)->next) #define CK_STACK_FOREACH(stack, entry) \ for ((entry) = CK_STACK_FIRST(stack); \ (entry) != NULL; \ (entry) = CK_STACK_NEXT(entry)) #define CK_STACK_FOREACH_SAFE(stack, entry, T) \ for ((entry) = CK_STACK_FIRST(stack); \ (entry) != NULL && ((T) = (entry)->next, 1); \ (entry) = (T)) #endif /* CK_STACK_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_stdbool.h ================================================ /* * Copyright 2015 Olivier Houchard. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(__FreeBSD__) && defined(_KERNEL) #include #else #include #endif ================================================ FILE: third_party/concurrency_kit/ck/include/ck_stddef.h ================================================ /* * Copyright 2015 Olivier Houchard. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(__FreeBSD__) && defined(_KERNEL) #include #else #include #endif ================================================ FILE: third_party/concurrency_kit/ck/include/ck_stdint.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(__linux__) && defined(__KERNEL__) #include #include #elif defined(__FreeBSD__) && defined(_KERNEL) #include #else #include #endif /* __linux__ && __KERNEL__ */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_stdlib.h ================================================ /* * Copyright 2015 Olivier Houchard. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(__FreeBSD__) && defined(_KERNEL) #include #else #include #endif ================================================ FILE: third_party/concurrency_kit/ck/include/ck_string.h ================================================ /* * Copyright 2015 Olivier Houchard. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(__FreeBSD__) && defined(_KERNEL) #include #else #include #endif ================================================ FILE: third_party/concurrency_kit/ck/include/ck_swlock.h ================================================ /* * Copyright 2014 Jaidev Sridhar. * Copyright 2014 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_SWLOCK_H #define CK_SWLOCK_H #include #include #include #include #include struct ck_swlock { uint32_t value; }; typedef struct ck_swlock ck_swlock_t; #define CK_SWLOCK_INITIALIZER {0} #define CK_SWLOCK_WRITER_BIT (1UL << 31) #define CK_SWLOCK_LATCH_BIT (1UL << 30) #define CK_SWLOCK_WRITER_MASK (CK_SWLOCK_LATCH_BIT | CK_SWLOCK_WRITER_BIT) #define CK_SWLOCK_READER_MASK (UINT32_MAX ^ CK_SWLOCK_WRITER_MASK) CK_CC_INLINE static void ck_swlock_init(struct ck_swlock *rw) { rw->value = 0; ck_pr_barrier(); return; } CK_CC_INLINE static void ck_swlock_write_unlock(ck_swlock_t *rw) { ck_pr_fence_unlock(); ck_pr_and_32(&rw->value, CK_SWLOCK_READER_MASK); return; } CK_CC_INLINE static bool ck_swlock_locked_writer(ck_swlock_t *rw) { bool r; r = ck_pr_load_32(&rw->value) & CK_SWLOCK_WRITER_BIT; ck_pr_fence_acquire(); return r; } CK_CC_INLINE static void ck_swlock_write_downgrade(ck_swlock_t *rw) { ck_pr_inc_32(&rw->value); ck_swlock_write_unlock(rw); return; } CK_CC_INLINE static bool ck_swlock_locked(ck_swlock_t *rw) { bool r; r = ck_pr_load_32(&rw->value); ck_pr_fence_acquire(); return r; } CK_CC_INLINE static bool ck_swlock_write_trylock(ck_swlock_t *rw) { bool r; r = ck_pr_cas_32(&rw->value, 0, CK_SWLOCK_WRITER_BIT); ck_pr_fence_lock(); return r; } CK_ELIDE_TRYLOCK_PROTOTYPE(ck_swlock_write, ck_swlock_t, ck_swlock_locked, ck_swlock_write_trylock) CK_CC_INLINE static void ck_swlock_write_lock(ck_swlock_t *rw) { ck_pr_or_32(&rw->value, CK_SWLOCK_WRITER_BIT); while (ck_pr_load_32(&rw->value) & CK_SWLOCK_READER_MASK) ck_pr_stall(); ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_swlock_write_latch(ck_swlock_t *rw) { /* Publish intent to acquire lock. */ ck_pr_or_32(&rw->value, CK_SWLOCK_WRITER_BIT); /* Stall until readers have seen the writer and cleared. */ while (ck_pr_cas_32(&rw->value, CK_SWLOCK_WRITER_BIT, CK_SWLOCK_WRITER_MASK) == false) { do { ck_pr_stall(); } while (ck_pr_load_32(&rw->value) != CK_SWLOCK_WRITER_BIT); } ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_swlock_write_unlatch(ck_swlock_t *rw) { ck_pr_fence_unlock(); ck_pr_store_32(&rw->value, 0); return; } CK_ELIDE_PROTOTYPE(ck_swlock_write, ck_swlock_t, ck_swlock_locked, ck_swlock_write_lock, ck_swlock_locked_writer, ck_swlock_write_unlock) CK_ELIDE_TRYLOCK_PROTOTYPE(ck_swlock_read, ck_swlock_t, ck_swlock_locked_writer, ck_swlock_read_trylock) CK_CC_INLINE static bool ck_swlock_read_trylock(ck_swlock_t *rw) { uint32_t l = ck_pr_load_32(&rw->value); if (l & CK_SWLOCK_WRITER_BIT) return false; l = ck_pr_faa_32(&rw->value, 1) & CK_SWLOCK_WRITER_MASK; if (l == CK_SWLOCK_WRITER_BIT) ck_pr_dec_32(&rw->value); ck_pr_fence_lock(); return l == 0; } CK_CC_INLINE static void ck_swlock_read_lock(ck_swlock_t *rw) { uint32_t l; for (;;) { while (ck_pr_load_32(&rw->value) & CK_SWLOCK_WRITER_BIT) ck_pr_stall(); l = ck_pr_faa_32(&rw->value, 1) & CK_SWLOCK_WRITER_MASK; if (l == 0) break; /* * If the latch bit has not been set, then the writer would * have observed the reader and will wait to completion of * read-side critical section. */ if (l == CK_SWLOCK_WRITER_BIT) ck_pr_dec_32(&rw->value); } ck_pr_fence_lock(); return; } CK_CC_INLINE static bool ck_swlock_locked_reader(ck_swlock_t *rw) { ck_pr_fence_load(); return ck_pr_load_32(&rw->value) & CK_SWLOCK_READER_MASK; } CK_CC_INLINE static void ck_swlock_read_unlock(ck_swlock_t *rw) { ck_pr_fence_unlock(); ck_pr_dec_32(&rw->value); return; } CK_ELIDE_PROTOTYPE(ck_swlock_read, ck_swlock_t, ck_swlock_locked_writer, ck_swlock_read_lock, ck_swlock_locked_reader, ck_swlock_read_unlock) #endif /* CK_SWLOCK_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/ck_tflock.h ================================================ /* * Copyright 2014 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_TFLOCK_TICKET_H #define CK_TFLOCK_TICKET_H /* * This is an implementation of task-fair locks derived from the work * described in: * John M. Mellor-Crummey and Michael L. Scott. 1991. * Scalable reader-writer synchronization for shared-memory * multiprocessors. SIGPLAN Not. 26, 7 (April 1991), 106-113. */ #include #include struct ck_tflock_ticket { uint32_t request; uint32_t completion; }; typedef struct ck_tflock_ticket ck_tflock_ticket_t; #define CK_TFLOCK_TICKET_INITIALIZER { 0, 0 } #define CK_TFLOCK_TICKET_RC_INCR 0x10000U /* Read-side increment. */ #define CK_TFLOCK_TICKET_WC_INCR 0x1U /* Write-side increment. */ #define CK_TFLOCK_TICKET_W_MASK 0xffffU /* Write-side mask. */ #define CK_TFLOCK_TICKET_WC_TOPMSK 0x8000U /* Write clear mask for overflow. */ #define CK_TFLOCK_TICKET_RC_TOPMSK 0x80000000U /* Read clear mask for overflow. */ CK_CC_INLINE static uint32_t ck_tflock_ticket_fca_32(uint32_t *target, uint32_t mask, uint32_t delta) { uint32_t snapshot = ck_pr_load_32(target); uint32_t goal; for (;;) { goal = (snapshot & ~mask) + delta; if (ck_pr_cas_32_value(target, snapshot, goal, &snapshot) == true) break; ck_pr_stall(); } return snapshot; } CK_CC_INLINE static void ck_tflock_ticket_init(struct ck_tflock_ticket *pf) { pf->request = pf->completion = 0; ck_pr_barrier(); return; } CK_CC_INLINE static void ck_tflock_ticket_write_lock(struct ck_tflock_ticket *lock) { uint32_t previous; previous = ck_tflock_ticket_fca_32(&lock->request, CK_TFLOCK_TICKET_WC_TOPMSK, CK_TFLOCK_TICKET_WC_INCR); ck_pr_fence_atomic_load(); while (ck_pr_load_32(&lock->completion) != previous) ck_pr_stall(); ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_tflock_ticket_write_unlock(struct ck_tflock_ticket *lock) { ck_pr_fence_unlock(); ck_tflock_ticket_fca_32(&lock->completion, CK_TFLOCK_TICKET_WC_TOPMSK, CK_TFLOCK_TICKET_WC_INCR); return; } CK_CC_INLINE static void ck_tflock_ticket_read_lock(struct ck_tflock_ticket *lock) { uint32_t previous; previous = ck_tflock_ticket_fca_32(&lock->request, CK_TFLOCK_TICKET_RC_TOPMSK, CK_TFLOCK_TICKET_RC_INCR) & CK_TFLOCK_TICKET_W_MASK; ck_pr_fence_atomic_load(); while ((ck_pr_load_32(&lock->completion) & CK_TFLOCK_TICKET_W_MASK) != previous) { ck_pr_stall(); } ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_tflock_ticket_read_unlock(struct ck_tflock_ticket *lock) { ck_pr_fence_unlock(); ck_tflock_ticket_fca_32(&lock->completion, CK_TFLOCK_TICKET_RC_TOPMSK, CK_TFLOCK_TICKET_RC_INCR); return; } #endif /* CK_TFLOCK_TICKET_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/aarch64/ck_f_pr.h ================================================ /* DO NOT EDIT. This is auto-generated from feature.sh */ #define CK_F_PR_ADD_16 #define CK_F_PR_ADD_32 #define CK_F_PR_ADD_64 #define CK_F_PR_ADD_8 #define CK_F_PR_ADD_CHAR #define CK_F_PR_ADD_INT #define CK_F_PR_ADD_PTR #define CK_F_PR_ADD_SHORT #define CK_F_PR_ADD_UINT #define CK_F_PR_AND_16 #define CK_F_PR_AND_32 #define CK_F_PR_AND_64 #define CK_F_PR_AND_8 #define CK_F_PR_AND_CHAR #define CK_F_PR_AND_INT #define CK_F_PR_AND_PTR #define CK_F_PR_AND_SHORT #define CK_F_PR_AND_UINT #define CK_F_PR_BARRIER #define CK_F_PR_CAS_16 #define CK_F_PR_CAS_16_VALUE #define CK_F_PR_CAS_32 #define CK_F_PR_CAS_32_VALUE #define CK_F_PR_CAS_64 #define CK_F_PR_CAS_64_VALUE #define CK_F_PR_CAS_64_2 #define CK_F_PR_CAS_64_2_VALUE #define CK_F_PR_CAS_DOUBLE #define CK_F_PR_CAS_DOUBLE_VALUE #define CK_F_PR_CAS_8 #define CK_F_PR_CAS_8_VALUE #define CK_F_PR_CAS_CHAR #define CK_F_PR_CAS_CHAR_VALUE #define CK_F_PR_CAS_INT #define CK_F_PR_CAS_INT_VALUE #define CK_F_PR_CAS_PTR #define CK_F_PR_CAS_PTR_2 #define CK_F_PR_CAS_PTR_2_VALUE #define CK_F_PR_CAS_PTR_VALUE #define CK_F_PR_CAS_SHORT #define CK_F_PR_CAS_SHORT_VALUE #define CK_F_PR_CAS_UINT #define CK_F_PR_CAS_UINT_VALUE #define CK_F_PR_DEC_16 #define CK_F_PR_DEC_32 #define CK_F_PR_DEC_64 #define CK_F_PR_DEC_8 #define CK_F_PR_DEC_CHAR #define CK_F_PR_DEC_INT #define CK_F_PR_DEC_PTR #define CK_F_PR_DEC_SHORT #define CK_F_PR_DEC_UINT #define CK_F_PR_FAA_16 #define CK_F_PR_FAA_32 #define CK_F_PR_FAA_64 #define CK_F_PR_FAA_8 #define CK_F_PR_FAA_CHAR #define CK_F_PR_FAA_INT #define CK_F_PR_FAA_PTR #define CK_F_PR_FAA_SHORT #define CK_F_PR_FAA_UINT #define CK_F_PR_FAS_16 #define CK_F_PR_FAS_32 #define CK_F_PR_FAS_64 #define CK_F_PR_FAS_8 #define CK_F_PR_FAS_CHAR #define CK_F_PR_FAS_INT #define CK_F_PR_FAS_PTR #define CK_F_PR_FAS_SHORT #define CK_F_PR_FAS_UINT #define CK_F_PR_FENCE_ATOMIC #define CK_F_PR_FENCE_ATOMIC_LOAD #define CK_F_PR_FENCE_ATOMIC_STORE #define CK_F_PR_FENCE_LOAD #define CK_F_PR_FENCE_LOAD_ATOMIC #define CK_F_PR_FENCE_LOAD_DEPENDS #define CK_F_PR_FENCE_LOAD_STORE #define CK_F_PR_FENCE_MEMORY #define CK_F_PR_FENCE_STORE #define CK_F_PR_FENCE_STORE_ATOMIC #define CK_F_PR_FENCE_STORE_LOAD #define CK_F_PR_FENCE_STRICT_ATOMIC #define CK_F_PR_FENCE_STRICT_ATOMIC_LOAD #define CK_F_PR_FENCE_STRICT_ATOMIC_STORE #define CK_F_PR_FENCE_STRICT_LOAD #define CK_F_PR_FENCE_STRICT_LOAD_ATOMIC #define CK_F_PR_FENCE_STRICT_LOAD_STORE #define CK_F_PR_FENCE_STRICT_MEMORY #define CK_F_PR_FENCE_STRICT_STORE #define CK_F_PR_FENCE_STRICT_STORE_ATOMIC #define CK_F_PR_FENCE_STRICT_STORE_LOAD #define CK_F_PR_INC_16 #define CK_F_PR_INC_32 #define CK_F_PR_INC_64 #define CK_F_PR_INC_8 #define CK_F_PR_INC_CHAR #define CK_F_PR_INC_INT #define CK_F_PR_INC_PTR #define CK_F_PR_INC_SHORT #define CK_F_PR_INC_UINT #define CK_F_PR_LOAD_16 #define CK_F_PR_LOAD_32 #define CK_F_PR_LOAD_64 #define CK_F_PR_LOAD_DOUBLE #define CK_F_PR_LOAD_8 #define CK_F_PR_LOAD_CHAR #define CK_F_PR_LOAD_INT #define CK_F_PR_LOAD_PTR #define CK_F_PR_LOAD_SHORT #define CK_F_PR_LOAD_UINT #define CK_F_PR_NEG_16 #define CK_F_PR_NEG_32 #define CK_F_PR_NEG_64 #define CK_F_PR_NEG_8 #define CK_F_PR_NEG_CHAR #define CK_F_PR_NEG_INT #define CK_F_PR_NEG_PTR #define CK_F_PR_NEG_SHORT #define CK_F_PR_NEG_UINT #define CK_F_PR_NOT_16 #define CK_F_PR_NOT_32 #define CK_F_PR_NOT_64 #define CK_F_PR_NOT_8 #define CK_F_PR_NOT_CHAR #define CK_F_PR_NOT_INT #define CK_F_PR_NOT_PTR #define CK_F_PR_NOT_SHORT #define CK_F_PR_NOT_UINT #define CK_F_PR_OR_16 #define CK_F_PR_OR_32 #define CK_F_PR_OR_64 #define CK_F_PR_OR_8 #define CK_F_PR_OR_CHAR #define CK_F_PR_OR_INT #define CK_F_PR_OR_PTR #define CK_F_PR_OR_SHORT #define CK_F_PR_OR_UINT #define CK_F_PR_STALL #define CK_F_PR_STORE_16 #define CK_F_PR_STORE_32 #define CK_F_PR_STORE_64 #define CK_F_PR_STORE_DOUBLE #define CK_F_PR_STORE_8 #define CK_F_PR_STORE_CHAR #define CK_F_PR_STORE_INT #define CK_F_PR_STORE_PTR #define CK_F_PR_STORE_SHORT #define CK_F_PR_STORE_UINT #define CK_F_PR_SUB_16 #define CK_F_PR_SUB_32 #define CK_F_PR_SUB_64 #define CK_F_PR_SUB_8 #define CK_F_PR_SUB_CHAR #define CK_F_PR_SUB_INT #define CK_F_PR_SUB_PTR #define CK_F_PR_SUB_SHORT #define CK_F_PR_SUB_UINT #define CK_F_PR_XOR_16 #define CK_F_PR_XOR_32 #define CK_F_PR_XOR_64 #define CK_F_PR_XOR_8 #define CK_F_PR_XOR_CHAR #define CK_F_PR_XOR_INT #define CK_F_PR_XOR_PTR #define CK_F_PR_XOR_SHORT #define CK_F_PR_XOR_UINT ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/aarch64/ck_pr.h ================================================ /* * Copyright 2009-2016 Samy Al Bahra. * Copyright 2013-2016 Olivier Houchard. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_AARCH64_H #define CK_PR_AARCH64_H #ifndef CK_PR_H #error Do not include this file directly, use ck_pr.h #endif #include #include /* * The following represent supported atomic operations. * These operations may be emulated. */ #include "ck_f_pr.h" /* * Minimum interface requirement met. */ #define CK_F_PR CK_CC_INLINE static void ck_pr_stall(void) { __asm__ __volatile__("" ::: "memory"); return; } #define CK_DMB_SY __asm __volatile("dmb ish" : : "r" (0) : "memory") #define CK_DMB_LD __asm __volatile("dmb ishld" : : "r" (0) : "memory") #define CK_DMB_ST __asm __volatile("dmb ishst" : : "r" (0) : "memory") #define CK_PR_FENCE(T, I) \ CK_CC_INLINE static void \ ck_pr_fence_strict_##T(void) \ { \ I; \ } CK_PR_FENCE(atomic, CK_DMB_ST) CK_PR_FENCE(atomic_store, CK_DMB_ST) CK_PR_FENCE(atomic_load, CK_DMB_SY) CK_PR_FENCE(store_atomic, CK_DMB_ST) CK_PR_FENCE(load_atomic, CK_DMB_SY) CK_PR_FENCE(store, CK_DMB_ST) CK_PR_FENCE(store_load, CK_DMB_SY) CK_PR_FENCE(load, CK_DMB_LD) CK_PR_FENCE(load_store, CK_DMB_SY) CK_PR_FENCE(memory, CK_DMB_SY) CK_PR_FENCE(acquire, CK_DMB_SY) CK_PR_FENCE(release, CK_DMB_SY) CK_PR_FENCE(acqrel, CK_DMB_SY) CK_PR_FENCE(lock, CK_DMB_SY) CK_PR_FENCE(unlock, CK_DMB_SY) #undef CK_PR_FENCE #undef CK_DMB_SI #undef CK_DMB_LD #undef CK_DMB_ST #define CK_PR_LOAD(S, M, T, I) \ CK_CC_INLINE static T \ ck_pr_md_load_##S(const M *target) \ { \ long r = 0; \ __asm__ __volatile__(I " %w0, [%1];" \ : "=r" (r) \ : "r" (target) \ : "memory"); \ return ((T)r); \ } #define CK_PR_LOAD_64(S, M, T, I) \ CK_CC_INLINE static T \ ck_pr_md_load_##S(const M *target) \ { \ long r = 0; \ __asm__ __volatile__(I " %0, [%1];" \ : "=r" (r) \ : "r" (target) \ : "memory"); \ return ((T)r); \ } CK_PR_LOAD_64(ptr, void, void *, "ldr") #define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, I) #define CK_PR_LOAD_S_64(S, T, I) CK_PR_LOAD_64(S, T, T, I) CK_PR_LOAD_S_64(64, uint64_t, "ldr") CK_PR_LOAD_S(32, uint32_t, "ldr") CK_PR_LOAD_S(16, uint16_t, "ldrh") CK_PR_LOAD_S(8, uint8_t, "ldrb") CK_PR_LOAD_S(uint, unsigned int, "ldr") CK_PR_LOAD_S(int, int, "ldr") CK_PR_LOAD_S(short, short, "ldrh") CK_PR_LOAD_S(char, char, "ldrb") #ifndef CK_PR_DISABLE_DOUBLE CK_PR_LOAD_S_64(double, double, "ldr") #endif #undef CK_PR_LOAD_S #undef CK_PR_LOAD_S_64 #undef CK_PR_LOAD #undef CK_PR_LAOD_64 #define CK_PR_STORE(S, M, T, I) \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ __asm__ __volatile__(I " %w1, [%0]" \ : \ : "r" (target), \ "r" (v) \ : "memory"); \ return; \ } #define CK_PR_STORE_64(S, M, T, I) \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ __asm__ __volatile__(I " %1, [%0]" \ : \ : "r" (target), \ "r" (v) \ : "memory"); \ return; \ } CK_PR_STORE_64(ptr, void, const void *, "str") #define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, I) #define CK_PR_STORE_S_64(S, T, I) CK_PR_STORE_64(S, T, T, I) CK_PR_STORE_S_64(64, uint64_t, "str") CK_PR_STORE_S(32, uint32_t, "str") CK_PR_STORE_S(16, uint16_t, "strh") CK_PR_STORE_S(8, uint8_t, "strb") CK_PR_STORE_S(uint, unsigned int, "str") CK_PR_STORE_S(int, int, "str") CK_PR_STORE_S(short, short, "strh") CK_PR_STORE_S(char, char, "strb") #ifndef CK_PR_DISABLE_DOUBLE CK_PR_STORE_S_64(double, double, "str") #endif #undef CK_PR_STORE_S #undef CK_PR_STORE_S_64 #undef CK_PR_STORE #undef CK_PR_STORE_64 #ifdef CK_MD_LSE_ENABLE #include "ck_pr_lse.h" #else #include "ck_pr_llsc.h" #endif /* * ck_pr_neg_*() functions can only be implemented via LL/SC, as there are no * LSE alternatives. */ #define CK_PR_NEG(N, M, T, W, R) \ CK_CC_INLINE static void \ ck_pr_neg_##N(M *target) \ { \ T previous = 0; \ T tmp = 0; \ __asm__ __volatile__("1:" \ "ldxr" W " %" R "0, [%2];" \ "neg %" R "0, %" R "0;" \ "stxr" W " %w1, %" R "0, [%2];" \ "cbnz %w1, 1b;" \ : "=&r" (previous), \ "=&r" (tmp) \ : "r" (target) \ : "memory", "cc"); \ return; \ } CK_PR_NEG(ptr, void, void *, "", "") CK_PR_NEG(64, uint64_t, uint64_t, "", "") #define CK_PR_NEG_S(S, T, W) \ CK_PR_NEG(S, T, T, W, "w") \ CK_PR_NEG_S(32, uint32_t, "") CK_PR_NEG_S(uint, unsigned int, "") CK_PR_NEG_S(int, int, "") CK_PR_NEG_S(16, uint16_t, "h") CK_PR_NEG_S(8, uint8_t, "b") CK_PR_NEG_S(short, short, "h") CK_PR_NEG_S(char, char, "b") #undef CK_PR_NEG_S #undef CK_PR_NEG #endif /* CK_PR_AARCH64_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/aarch64/ck_pr_llsc.h ================================================ /* * Copyright 2009-2016 Samy Al Bahra. * Copyright 2013-2016 Olivier Houchard. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_AARCH64_LLSC_H #define CK_PR_AARCH64_LLSC_H #ifndef CK_PR_H #error Do not include this file directly, use ck_pr.h #endif CK_CC_INLINE static bool ck_pr_cas_64_2_value(uint64_t target[2], uint64_t compare[2], uint64_t set[2], uint64_t value[2]) { uint64_t tmp1, tmp2; __asm__ __volatile__("1:" "ldxp %0, %1, [%4];" "mov %2, %0;" "mov %3, %1;" "eor %0, %0, %5;" "eor %1, %1, %6;" "orr %1, %0, %1;" "mov %w0, #0;" "cbnz %1, 2f;" "stxp %w0, %7, %8, [%4];" "cbnz %w0, 1b;" "mov %w0, #1;" "2:" : "=&r" (tmp1), "=&r" (tmp2), "=&r" (value[0]), "=&r" (value[1]) : "r" (target), "r" (compare[0]), "r" (compare[1]), "r" (set[0]), "r" (set[1]) : "cc", "memory"); return (tmp1); } CK_CC_INLINE static bool ck_pr_cas_ptr_2_value(void *target, void *compare, void *set, void *value) { return (ck_pr_cas_64_2_value(CK_CPP_CAST(uint64_t *, target), CK_CPP_CAST(uint64_t *, compare), CK_CPP_CAST(uint64_t *, set), CK_CPP_CAST(uint64_t *, value))); } CK_CC_INLINE static bool ck_pr_cas_64_2(uint64_t target[2], uint64_t compare[2], uint64_t set[2]) { uint64_t tmp1, tmp2; __asm__ __volatile__("1:" "ldxp %0, %1, [%2];" "eor %0, %0, %3;" "eor %1, %1, %4;" "orr %1, %0, %1;" "mov %w0, #0;" "cbnz %1, 2f;" "stxp %w0, %5, %6, [%2];" "cbnz %w0, 1b;" "mov %w0, #1;" "2:" : "=&r" (tmp1), "=&r" (tmp2) : "r" (target), "r" (compare[0]), "r" (compare[1]), "r" (set[0]), "r" (set[1]) : "cc", "memory"); return (tmp1); } CK_CC_INLINE static bool ck_pr_cas_ptr_2(void *target, void *compare, void *set) { return (ck_pr_cas_64_2(CK_CPP_CAST(uint64_t *, target), CK_CPP_CAST(uint64_t *, compare), CK_CPP_CAST(uint64_t *, set))); } #define CK_PR_CAS(N, M, T, W, R) \ CK_CC_INLINE static bool \ ck_pr_cas_##N##_value(M *target, T compare, T set, M *value) \ { \ T previous; \ T tmp; \ __asm__ __volatile__("1:" \ "ldxr" W " %" R "0, [%2];" \ "cmp %" R "0, %" R "4;" \ "b.ne 2f;" \ "stxr" W " %w1, %" R "3, [%2];" \ "cbnz %w1, 1b;" \ "2:" \ : "=&r" (previous), \ "=&r" (tmp) \ : "r" (target), \ "r" (set), \ "r" (compare) \ : "memory", "cc"); \ *(T *)value = previous; \ return (previous == compare); \ } \ CK_CC_INLINE static bool \ ck_pr_cas_##N(M *target, T compare, T set) \ { \ T previous; \ T tmp; \ __asm__ __volatile__( \ "1:" \ "ldxr" W " %" R "0, [%2];" \ "cmp %" R "0, %" R "4;" \ "b.ne 2f;" \ "stxr" W " %w1, %" R "3, [%2];" \ "cbnz %w1, 1b;" \ "2:" \ : "=&r" (previous), \ "=&r" (tmp) \ : "r" (target), \ "r" (set), \ "r" (compare) \ : "memory", "cc"); \ return (previous == compare); \ } CK_PR_CAS(ptr, void, void *, "", "") #define CK_PR_CAS_S(N, M, W, R) CK_PR_CAS(N, M, M, W, R) CK_PR_CAS_S(64, uint64_t, "", "") #ifndef CK_PR_DISABLE_DOUBLE CK_PR_CAS_S(double, double, "", "") #endif CK_PR_CAS_S(32, uint32_t, "", "w") CK_PR_CAS_S(uint, unsigned int, "", "w") CK_PR_CAS_S(int, int, "", "w") CK_PR_CAS_S(16, uint16_t, "h", "w") CK_PR_CAS_S(8, uint8_t, "b", "w") CK_PR_CAS_S(short, short, "h", "w") CK_PR_CAS_S(char, char, "b", "w") #undef CK_PR_CAS_S #undef CK_PR_CAS #define CK_PR_FAS(N, M, T, W, R) \ CK_CC_INLINE static T \ ck_pr_fas_##N(M *target, T v) \ { \ T previous; \ T tmp; \ __asm__ __volatile__("1:" \ "ldxr" W " %" R "0, [%2];" \ "stxr" W " %w1, %" R "3, [%2];"\ "cbnz %w1, 1b;" \ : "=&r" (previous), \ "=&r" (tmp) \ : "r" (target), \ "r" (v) \ : "memory", "cc"); \ return (previous); \ } CK_PR_FAS(64, uint64_t, uint64_t, "", "") CK_PR_FAS(32, uint32_t, uint32_t, "", "w") CK_PR_FAS(ptr, void, void *, "", "") CK_PR_FAS(int, int, int, "", "w") CK_PR_FAS(uint, unsigned int, unsigned int, "", "w") CK_PR_FAS(16, uint16_t, uint16_t, "h", "w") CK_PR_FAS(8, uint8_t, uint8_t, "b", "w") CK_PR_FAS(short, short, short, "h", "w") CK_PR_FAS(char, char, char, "b", "w") #undef CK_PR_FAS #define CK_PR_UNARY(O, N, M, T, I, W, R) \ CK_CC_INLINE static void \ ck_pr_##O##_##N(M *target) \ { \ T previous = 0; \ T tmp = 0; \ __asm__ __volatile__("1:" \ "ldxr" W " %" R "0, [%2];" \ I ";" \ "stxr" W " %w1, %" R "0, [%2];" \ "cbnz %w1, 1b;" \ : "=&r" (previous), \ "=&r" (tmp) \ : "r" (target) \ : "memory", "cc"); \ return; \ } CK_PR_UNARY(inc, ptr, void, void *, "add %0, %0, #1", "", "") CK_PR_UNARY(dec, ptr, void, void *, "sub %0, %0, #1", "", "") CK_PR_UNARY(not, ptr, void, void *, "mvn %0, %0", "", "") CK_PR_UNARY(inc, 64, uint64_t, uint64_t, "add %0, %0, #1", "", "") CK_PR_UNARY(dec, 64, uint64_t, uint64_t, "sub %0, %0, #1", "", "") CK_PR_UNARY(not, 64, uint64_t, uint64_t, "mvn %0, %0", "", "") #define CK_PR_UNARY_S(S, T, W) \ CK_PR_UNARY(inc, S, T, T, "add %w0, %w0, #1", W, "w") \ CK_PR_UNARY(dec, S, T, T, "sub %w0, %w0, #1", W, "w") \ CK_PR_UNARY(not, S, T, T, "mvn %w0, %w0", W, "w") \ CK_PR_UNARY_S(32, uint32_t, "") CK_PR_UNARY_S(uint, unsigned int, "") CK_PR_UNARY_S(int, int, "") CK_PR_UNARY_S(16, uint16_t, "h") CK_PR_UNARY_S(8, uint8_t, "b") CK_PR_UNARY_S(short, short, "h") CK_PR_UNARY_S(char, char, "b") #undef CK_PR_UNARY_S #undef CK_PR_UNARY #define CK_PR_BINARY(O, N, M, T, I, W, R) \ CK_CC_INLINE static void \ ck_pr_##O##_##N(M *target, T delta) \ { \ T previous; \ T tmp; \ __asm__ __volatile__("1:" \ "ldxr" W " %" R "0, [%2];"\ I " %" R "0, %" R "0, %" R "3;" \ "stxr" W " %w1, %" R "0, [%2];" \ "cbnz %w1, 1b;" \ : "=&r" (previous), \ "=&r" (tmp) \ : "r" (target), \ "r" (delta) \ : "memory", "cc"); \ return; \ } CK_PR_BINARY(and, ptr, void, uintptr_t, "and", "", "") CK_PR_BINARY(add, ptr, void, uintptr_t, "add", "", "") CK_PR_BINARY(or, ptr, void, uintptr_t, "orr", "", "") CK_PR_BINARY(sub, ptr, void, uintptr_t, "sub", "", "") CK_PR_BINARY(xor, ptr, void, uintptr_t, "eor", "", "") CK_PR_BINARY(and, 64, uint64_t, uint64_t, "and", "", "") CK_PR_BINARY(add, 64, uint64_t, uint64_t, "add", "", "") CK_PR_BINARY(or, 64, uint64_t, uint64_t, "orr", "", "") CK_PR_BINARY(sub, 64, uint64_t, uint64_t, "sub", "", "") CK_PR_BINARY(xor, 64, uint64_t, uint64_t, "eor", "", "") #define CK_PR_BINARY_S(S, T, W) \ CK_PR_BINARY(and, S, T, T, "and", W, "w") \ CK_PR_BINARY(add, S, T, T, "add", W, "w") \ CK_PR_BINARY(or, S, T, T, "orr", W, "w") \ CK_PR_BINARY(sub, S, T, T, "sub", W, "w") \ CK_PR_BINARY(xor, S, T, T, "eor", W, "w") CK_PR_BINARY_S(32, uint32_t, "") CK_PR_BINARY_S(uint, unsigned int, "") CK_PR_BINARY_S(int, int, "") CK_PR_BINARY_S(16, uint16_t, "h") CK_PR_BINARY_S(8, uint8_t, "b") CK_PR_BINARY_S(short, short, "h") CK_PR_BINARY_S(char, char, "b") #undef CK_PR_BINARY_S #undef CK_PR_BINARY CK_CC_INLINE static void * ck_pr_faa_ptr(void *target, uintptr_t delta) { uintptr_t previous, r, tmp; __asm__ __volatile__("1:" "ldxr %0, [%3];" "add %1, %4, %0;" "stxr %w2, %1, [%3];" "cbnz %w2, 1b;" : "=&r" (previous), "=&r" (r), "=&r" (tmp) : "r" (target), "r" (delta) : "memory", "cc"); return (void *)(previous); } CK_CC_INLINE static uint64_t ck_pr_faa_64(uint64_t *target, uint64_t delta) { uint64_t previous, r, tmp; __asm__ __volatile__("1:" "ldxr %0, [%3];" "add %1, %4, %0;" "stxr %w2, %1, [%3];" "cbnz %w2, 1b;" : "=&r" (previous), "=&r" (r), "=&r" (tmp) : "r" (target), "r" (delta) : "memory", "cc"); return (previous); } #define CK_PR_FAA(S, T, W) \ CK_CC_INLINE static T \ ck_pr_faa_##S(T *target, T delta) \ { \ T previous, r, tmp; \ __asm__ __volatile__("1:" \ "ldxr" W " %w0, [%3];" \ "add %w1, %w4, %w0;" \ "stxr" W " %w2, %w1, [%3];" \ "cbnz %w2, 1b;" \ : "=&r" (previous), \ "=&r" (r), \ "=&r" (tmp) \ : "r" (target), \ "r" (delta) \ : "memory", "cc"); \ return (previous); \ } CK_PR_FAA(32, uint32_t, "") CK_PR_FAA(uint, unsigned int, "") CK_PR_FAA(int, int, "") CK_PR_FAA(16, uint16_t, "h") CK_PR_FAA(8, uint8_t, "b") CK_PR_FAA(short, short, "h") CK_PR_FAA(char, char, "b") #undef CK_PR_FAA #endif /* CK_PR_AARCH64_LLSC_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/aarch64/ck_pr_lse.h ================================================ /* * Copyright 2009-2016 Samy Al Bahra. * Copyright 2013-2016 Olivier Houchard. * Copyright 2016 Alexey Kopytov. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_AARCH64_LSE_H #define CK_PR_AARCH64_LSE_H #ifndef CK_PR_H #error Do not include this file directly, use ck_pr.h #endif CK_CC_INLINE static bool ck_pr_cas_64_2_value(uint64_t target[2], uint64_t compare[2], uint64_t set[2], uint64_t value[2]) { uint64_t tmp1; uint64_t tmp2; register uint64_t x0 __asm__ ("x0") = compare[0]; register uint64_t x1 __asm__ ("x1") = compare[1]; register uint64_t x2 __asm__ ("x2") = set[0]; register uint64_t x3 __asm__ ("x3") = set[1]; __asm__ __volatile__("casp %0, %1, %4, %5, [%6];" "eor %2, %0, %7;" "eor %3, %1, %8;" "orr %2, %2, %3;" : "+&r" (x0), "+&r" (x1), "=&r" (tmp1), "=&r" (tmp2) : "r" (x2), "r" (x3), "r" (target), "r" (compare[0]), "r" (compare[1]) : "memory"); value[0] = x0; value[1] = x1; return (!!tmp1); } CK_CC_INLINE static bool ck_pr_cas_ptr_2_value(void *target, void *compare, void *set, void *value) { return (ck_pr_cas_64_2_value(CK_CPP_CAST(uint64_t *, target), CK_CPP_CAST(uint64_t *, compare), CK_CPP_CAST(uint64_t *, set), CK_CPP_CAST(uint64_t *, value))); } CK_CC_INLINE static bool ck_pr_cas_64_2(uint64_t target[2], uint64_t compare[2], uint64_t set[2]) { register uint64_t x0 __asm__ ("x0") = compare[0]; register uint64_t x1 __asm__ ("x1") = compare[1]; register uint64_t x2 __asm__ ("x2") = set[0]; register uint64_t x3 __asm__ ("x3") = set[1]; __asm__ __volatile__("casp %0, %1, %2, %3, [%4];" "eor %0, %0, %5;" "eor %1, %1, %6;" "orr %0, %0, %1;" : "+&r" (x0), "+&r" (x1) : "r" (x2), "r" (x3), "r" (target), "r" (compare[0]), "r" (compare[1]) : "memory"); return (!!x0); } CK_CC_INLINE static bool ck_pr_cas_ptr_2(void *target, void *compare, void *set) { return (ck_pr_cas_64_2(CK_CPP_CAST(uint64_t *, target), CK_CPP_CAST(uint64_t *, compare), CK_CPP_CAST(uint64_t *, set))); } #define CK_PR_CAS(N, M, T, W, R) \ CK_CC_INLINE static bool \ ck_pr_cas_##N##_value(M *target, T compare, T set, M *value) \ { \ *(T *)value = compare; \ __asm__ __volatile__( \ "cas" W " %" R "0, %" R "2, [%1];" \ : "+&r" (*(T *)value) \ : "r" (target), \ "r" (set) \ : "memory"); \ return (*(T *)value == compare); \ } \ CK_CC_INLINE static bool \ ck_pr_cas_##N(M *target, T compare, T set) \ { \ T previous = compare; \ __asm__ __volatile__( \ "cas" W " %" R "0, %" R "2, [%1];" \ : "+&r" (previous) \ : "r" (target), \ "r" (set) \ : "memory"); \ return (previous == compare); \ } CK_PR_CAS(ptr, void, void *, "", "") #define CK_PR_CAS_S(N, M, W, R) CK_PR_CAS(N, M, M, W, R) CK_PR_CAS_S(64, uint64_t, "", "") #ifndef CK_PR_DISABLE_DOUBLE CK_PR_CAS_S(double, double, "", "") #endif CK_PR_CAS_S(32, uint32_t, "", "w") CK_PR_CAS_S(uint, unsigned int, "", "w") CK_PR_CAS_S(int, int, "", "w") CK_PR_CAS_S(16, uint16_t, "h", "w") CK_PR_CAS_S(8, uint8_t, "b", "w") CK_PR_CAS_S(short, short, "h", "w") CK_PR_CAS_S(char, char, "b", "w") #undef CK_PR_CAS_S #undef CK_PR_CAS #define CK_PR_FAS(N, M, T, W, R) \ CK_CC_INLINE static T \ ck_pr_fas_##N(M *target, T v) \ { \ T previous; \ __asm__ __volatile__( \ "swp" W " %" R "2, %" R "0, [%1];" \ : "=&r" (previous) \ : "r" (target), \ "r" (v) \ : "memory"); \ return (previous); \ } CK_PR_FAS(64, uint64_t, uint64_t, "", "") CK_PR_FAS(32, uint32_t, uint32_t, "", "w") CK_PR_FAS(ptr, void, void *, "", "") CK_PR_FAS(int, int, int, "", "w") CK_PR_FAS(uint, unsigned int, unsigned int, "", "w") CK_PR_FAS(16, uint16_t, uint16_t, "h", "w") CK_PR_FAS(8, uint8_t, uint8_t, "b", "w") CK_PR_FAS(short, short, short, "h", "w") CK_PR_FAS(char, char, char, "b", "w") #undef CK_PR_FAS #define CK_PR_UNARY(O, N, M, T, I, W, R, S) \ CK_CC_INLINE static void \ ck_pr_##O##_##N(M *target) \ { \ __asm__ __volatile__(I ";" \ "st" S W " " R "0, [%0];" \ : \ : "r" (target) \ : "x0", "memory"); \ return; \ } CK_PR_UNARY(inc, ptr, void, void *, "mov x0, 1", "", "x", "add") CK_PR_UNARY(dec, ptr, void, void *, "mov x0, -1", "", "x", "add") CK_PR_UNARY(not, ptr, void, void *, "mov x0, -1", "", "x", "eor") CK_PR_UNARY(inc, 64, uint64_t, uint64_t, "mov x0, 1", "", "x", "add") CK_PR_UNARY(dec, 64, uint64_t, uint64_t, "mov x0, -1", "", "x", "add") CK_PR_UNARY(not, 64, uint64_t, uint64_t, "mov x0, -1", "", "x", "eor") #define CK_PR_UNARY_S(S, T, W) \ CK_PR_UNARY(inc, S, T, T, "mov w0, 1", W, "w", "add") \ CK_PR_UNARY(dec, S, T, T, "mov w0, -1", W, "w", "add") \ CK_PR_UNARY(not, S, T, T, "mov w0, -1", W, "w", "eor") \ CK_PR_UNARY_S(32, uint32_t, "") CK_PR_UNARY_S(uint, unsigned int, "") CK_PR_UNARY_S(int, int, "") CK_PR_UNARY_S(16, uint16_t, "h") CK_PR_UNARY_S(8, uint8_t, "b") CK_PR_UNARY_S(short, short, "h") CK_PR_UNARY_S(char, char, "b") #undef CK_PR_UNARY_S #undef CK_PR_UNARY #define CK_PR_BINARY(O, N, M, T, S, W, R, I) \ CK_CC_INLINE static void \ ck_pr_##O##_##N(M *target, T delta) \ { \ __asm__ __volatile__(I ";" \ "st" S W " %" R "0, [%1];" \ : "+&r" (delta) \ : "r" (target) \ : "memory"); \ return; \ } CK_PR_BINARY(and, ptr, void, uintptr_t, "clr", "", "", "mvn %0, %0") CK_PR_BINARY(add, ptr, void, uintptr_t, "add", "", "", "") CK_PR_BINARY(or, ptr, void, uintptr_t, "set", "", "", "") CK_PR_BINARY(sub, ptr, void, uintptr_t, "add", "", "", "neg %0, %0") CK_PR_BINARY(xor, ptr, void, uintptr_t, "eor", "", "", "") CK_PR_BINARY(and, 64, uint64_t, uint64_t, "clr", "", "", "mvn %0, %0") CK_PR_BINARY(add, 64, uint64_t, uint64_t, "add", "", "", "") CK_PR_BINARY(or, 64, uint64_t, uint64_t, "set", "", "", "") CK_PR_BINARY(sub, 64, uint64_t, uint64_t, "add", "", "", "neg %0, %0") CK_PR_BINARY(xor, 64, uint64_t, uint64_t, "eor", "", "", "") #define CK_PR_BINARY_S(S, T, W) \ CK_PR_BINARY(and, S, T, T, "clr", W, "w", "mvn %w0, %w0") \ CK_PR_BINARY(add, S, T, T, "add", W, "w", "") \ CK_PR_BINARY(or, S, T, T, "set", W, "w", "") \ CK_PR_BINARY(sub, S, T, T, "add", W, "w", "neg %w0, %w0") \ CK_PR_BINARY(xor, S, T, T, "eor", W, "w", "") CK_PR_BINARY_S(32, uint32_t, "") CK_PR_BINARY_S(uint, unsigned int, "") CK_PR_BINARY_S(int, int, "") CK_PR_BINARY_S(16, uint16_t, "h") CK_PR_BINARY_S(8, uint8_t, "b") CK_PR_BINARY_S(short, short, "h") CK_PR_BINARY_S(char, char, "b") #undef CK_PR_BINARY_S #undef CK_PR_BINARY CK_CC_INLINE static void * ck_pr_faa_ptr(void *target, uintptr_t delta) { uintptr_t previous; __asm__ __volatile__( "ldadd %2, %0, [%1];" : "=r" (previous) : "r" (target), "r" (delta) : "memory"); return (void *)(previous); } CK_CC_INLINE static uint64_t ck_pr_faa_64(uint64_t *target, uint64_t delta) { uint64_t previous; __asm__ __volatile__( "ldadd %2, %0, [%1];" : "=r" (previous) : "r" (target), "r" (delta) : "memory"); return (previous); } #define CK_PR_FAA(S, T, W) \ CK_CC_INLINE static T \ ck_pr_faa_##S(T *target, T delta) \ { \ T previous; \ __asm__ __volatile__( \ "ldadd" W " %w2, %w0, [%1];" \ : "=r" (previous) \ : "r" (target), \ "r" (delta) \ : "memory"); \ return (previous); \ } CK_PR_FAA(32, uint32_t, "") CK_PR_FAA(uint, unsigned int, "") CK_PR_FAA(int, int, "") CK_PR_FAA(16, uint16_t, "h") CK_PR_FAA(8, uint8_t, "b") CK_PR_FAA(short, short, "h") CK_PR_FAA(char, char, "b") #undef CK_PR_FAA #endif /* CK_PR_AARCH64_LSE_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/arm/ck_f_pr.h ================================================ /* DO NOT EDIT. This is auto-generated from feature.sh */ #define CK_F_PR_ADD_16 #define CK_F_PR_ADD_32 #define CK_F_PR_ADD_8 #define CK_F_PR_ADD_CHAR #define CK_F_PR_ADD_INT #define CK_F_PR_ADD_PTR #define CK_F_PR_ADD_SHORT #define CK_F_PR_ADD_UINT #define CK_F_PR_AND_16 #define CK_F_PR_AND_32 #define CK_F_PR_AND_8 #define CK_F_PR_AND_CHAR #define CK_F_PR_AND_INT #define CK_F_PR_AND_PTR #define CK_F_PR_AND_SHORT #define CK_F_PR_AND_UINT #define CK_F_PR_BARRIER #define CK_F_PR_CAS_16 #define CK_F_PR_CAS_16_VALUE #define CK_F_PR_CAS_32 #define CK_F_PR_CAS_32_VALUE #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) #define CK_F_PR_CAS_64 #define CK_F_PR_CAS_64_VALUE #define CK_F_PR_CAS_DOUBLE #define CK_F_PR_CAS_DOUBLE_VALUE #endif #define CK_F_PR_CAS_8 #define CK_F_PR_CAS_8_VALUE #define CK_F_PR_CAS_CHAR #define CK_F_PR_CAS_CHAR_VALUE #define CK_F_PR_CAS_INT #define CK_F_PR_CAS_INT_VALUE #define CK_F_PR_CAS_PTR #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) #define CK_F_PR_CAS_PTR_2 #define CK_F_PR_CAS_PTR_2_VALUE #endif #define CK_F_PR_CAS_PTR_VALUE #define CK_F_PR_CAS_SHORT #define CK_F_PR_CAS_SHORT_VALUE #define CK_F_PR_CAS_UINT #define CK_F_PR_CAS_UINT_VALUE #define CK_F_PR_DEC_16 #define CK_F_PR_DEC_32 #define CK_F_PR_DEC_8 #define CK_F_PR_DEC_CHAR #define CK_F_PR_DEC_INT #define CK_F_PR_DEC_PTR #define CK_F_PR_DEC_SHORT #define CK_F_PR_DEC_UINT #define CK_F_PR_FAA_16 #define CK_F_PR_FAA_32 #define CK_F_PR_FAA_8 #define CK_F_PR_FAA_CHAR #define CK_F_PR_FAA_INT #define CK_F_PR_FAA_PTR #define CK_F_PR_FAA_SHORT #define CK_F_PR_FAA_UINT #define CK_F_PR_FAS_16 #define CK_F_PR_FAS_32 #define CK_F_PR_FAS_8 #define CK_F_PR_FAS_CHAR #define CK_F_PR_FAS_INT #define CK_F_PR_FAS_PTR #define CK_F_PR_FAS_SHORT #define CK_F_PR_FAS_UINT #define CK_F_PR_FENCE_ATOMIC #define CK_F_PR_FENCE_ATOMIC_LOAD #define CK_F_PR_FENCE_ATOMIC_STORE #define CK_F_PR_FENCE_LOAD #define CK_F_PR_FENCE_LOAD_ATOMIC #define CK_F_PR_FENCE_LOAD_DEPENDS #define CK_F_PR_FENCE_LOAD_STORE #define CK_F_PR_FENCE_MEMORY #define CK_F_PR_FENCE_STORE #define CK_F_PR_FENCE_STORE_ATOMIC #define CK_F_PR_FENCE_STORE_LOAD #define CK_F_PR_FENCE_STRICT_ATOMIC #define CK_F_PR_FENCE_STRICT_ATOMIC_LOAD #define CK_F_PR_FENCE_STRICT_ATOMIC_STORE #define CK_F_PR_FENCE_STRICT_LOAD #define CK_F_PR_FENCE_STRICT_LOAD_ATOMIC #define CK_F_PR_FENCE_STRICT_LOAD_STORE #define CK_F_PR_FENCE_STRICT_MEMORY #define CK_F_PR_FENCE_STRICT_STORE #define CK_F_PR_FENCE_STRICT_STORE_ATOMIC #define CK_F_PR_FENCE_STRICT_STORE_LOAD #define CK_F_PR_INC_16 #define CK_F_PR_INC_32 #define CK_F_PR_INC_8 #define CK_F_PR_INC_CHAR #define CK_F_PR_INC_INT #define CK_F_PR_INC_PTR #define CK_F_PR_INC_SHORT #define CK_F_PR_INC_UINT #define CK_F_PR_LOAD_16 #define CK_F_PR_LOAD_32 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) #define CK_F_PR_LOAD_64 #define CK_F_PR_LOAD_DOUBLE #endif #define CK_F_PR_LOAD_8 #define CK_F_PR_LOAD_CHAR #define CK_F_PR_LOAD_INT #define CK_F_PR_LOAD_PTR #define CK_F_PR_LOAD_SHORT #define CK_F_PR_LOAD_UINT #define CK_F_PR_NEG_16 #define CK_F_PR_NEG_32 #define CK_F_PR_NEG_8 #define CK_F_PR_NEG_CHAR #define CK_F_PR_NEG_INT #define CK_F_PR_NEG_PTR #define CK_F_PR_NEG_SHORT #define CK_F_PR_NEG_UINT #define CK_F_PR_NOT_16 #define CK_F_PR_NOT_32 #define CK_F_PR_NOT_8 #define CK_F_PR_NOT_CHAR #define CK_F_PR_NOT_INT #define CK_F_PR_NOT_PTR #define CK_F_PR_NOT_SHORT #define CK_F_PR_NOT_UINT #define CK_F_PR_OR_16 #define CK_F_PR_OR_32 #define CK_F_PR_OR_8 #define CK_F_PR_OR_CHAR #define CK_F_PR_OR_INT #define CK_F_PR_OR_PTR #define CK_F_PR_OR_SHORT #define CK_F_PR_OR_UINT #define CK_F_PR_STALL #define CK_F_PR_STORE_16 #define CK_F_PR_STORE_32 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) #define CK_F_PR_STORE_64 #define CK_F_PR_STORE_DOUBLE #endif #define CK_F_PR_STORE_8 #define CK_F_PR_STORE_CHAR #define CK_F_PR_STORE_INT #define CK_F_PR_STORE_PTR #define CK_F_PR_STORE_SHORT #define CK_F_PR_STORE_UINT #define CK_F_PR_SUB_16 #define CK_F_PR_SUB_32 #define CK_F_PR_SUB_8 #define CK_F_PR_SUB_CHAR #define CK_F_PR_SUB_INT #define CK_F_PR_SUB_PTR #define CK_F_PR_SUB_SHORT #define CK_F_PR_SUB_UINT #define CK_F_PR_XOR_16 #define CK_F_PR_XOR_32 #define CK_F_PR_XOR_8 #define CK_F_PR_XOR_CHAR #define CK_F_PR_XOR_INT #define CK_F_PR_XOR_PTR #define CK_F_PR_XOR_SHORT #define CK_F_PR_XOR_UINT ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/arm/ck_pr.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * Copyright 2013-2015 Olivier Houchard. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_ARM_H #define CK_PR_ARM_H #ifndef CK_PR_H #error Do not include this file directly, use ck_pr.h #endif #include #include /* * The following represent supported atomic operations. * These operations may be emulated. */ #include "ck_f_pr.h" /* * Minimum interface requirement met. */ #define CK_F_PR CK_CC_INLINE static void ck_pr_stall(void) { __asm__ __volatile__("" ::: "memory"); return; } #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) #define CK_ISB __asm __volatile("isb" : : "r" (0) : "memory") #define CK_DMB __asm __volatile("dmb" : : "r" (0) : "memory") #define CK_DSB __asm __volatile("dsb" : : "r" (0) : "memory") /* FreeBSD's toolchain doesn't accept dmb st, so use the opcode instead */ #ifdef __FreeBSD__ #define CK_DMB_ST __asm __volatile(".word 0xf57ff05e" : : "r" (0) : "memory") #else #define CK_DMB_ST __asm __volatile("dmb st" : : "r" (0) : "memory") #endif /* __FreeBSD__ */ #else /* armv6 doesn't have dsb/dmb/isb, and no way to wait only for stores */ #define CK_ISB \ __asm __volatile("mcr p15, 0, %0, c7, c5, 4" : : "r" (0) : "memory") #define CK_DSB \ __asm __volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (0) : "memory") #define CK_DMB \ __asm __volatile("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory") #define CK_DMB_ST CK_DMB #endif #define CK_PR_FENCE(T, I) \ CK_CC_INLINE static void \ ck_pr_fence_strict_##T(void) \ { \ I; \ } CK_PR_FENCE(atomic, CK_DMB_ST) CK_PR_FENCE(atomic_store, CK_DMB_ST) CK_PR_FENCE(atomic_load, CK_DMB_ST) CK_PR_FENCE(store_atomic, CK_DMB_ST) CK_PR_FENCE(load_atomic, CK_DMB) CK_PR_FENCE(store, CK_DMB_ST) CK_PR_FENCE(store_load, CK_DMB) CK_PR_FENCE(load, CK_DMB) CK_PR_FENCE(load_store, CK_DMB) CK_PR_FENCE(memory, CK_DMB) CK_PR_FENCE(acquire, CK_DMB) CK_PR_FENCE(release, CK_DMB) CK_PR_FENCE(acqrel, CK_DMB) CK_PR_FENCE(lock, CK_DMB) CK_PR_FENCE(unlock, CK_DMB) #undef CK_PR_FENCE #undef CK_ISB #undef CK_DSB #undef CK_DMB #undef CK_DMB_ST #define CK_PR_LOAD(S, M, T, C, I) \ CK_CC_INLINE static T \ ck_pr_md_load_##S(const M *target) \ { \ long r = 0; \ __asm__ __volatile__(I " %0, [%1];" \ : "=r" (r) \ : "r" (target) \ : "memory"); \ return ((T)r); \ } CK_PR_LOAD(ptr, void, void *, uint32_t, "ldr") #define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) CK_PR_LOAD_S(32, uint32_t, "ldr") CK_PR_LOAD_S(16, uint16_t, "ldrh") CK_PR_LOAD_S(8, uint8_t, "ldrb") CK_PR_LOAD_S(uint, unsigned int, "ldr") CK_PR_LOAD_S(int, int, "ldr") CK_PR_LOAD_S(short, short, "ldrh") CK_PR_LOAD_S(char, char, "ldrb") #undef CK_PR_LOAD_S #undef CK_PR_LOAD #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) #define CK_PR_DOUBLE_LOAD(T, N) \ CK_CC_INLINE static T \ ck_pr_md_load_##N(const T *target) \ { \ register T ret; \ \ __asm __volatile("ldrexd %0, [%1]" \ : "=&r" (ret) \ : "r" (target) \ : "memory", "cc"); \ return (ret); \ } CK_PR_DOUBLE_LOAD(uint64_t, 64) #ifndef CK_PR_DISABLE_DOUBLE CK_PR_DOUBLE_LOAD(double, double) #endif #undef CK_PR_DOUBLE_LOAD #endif #define CK_PR_STORE(S, M, T, C, I) \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ __asm__ __volatile__(I " %1, [%0]" \ : \ : "r" (target), \ "r" (v) \ : "memory"); \ return; \ } CK_PR_STORE(ptr, void, const void *, uint32_t, "str") #define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) CK_PR_STORE_S(32, uint32_t, "str") CK_PR_STORE_S(16, uint16_t, "strh") CK_PR_STORE_S(8, uint8_t, "strb") CK_PR_STORE_S(uint, unsigned int, "str") CK_PR_STORE_S(int, int, "str") CK_PR_STORE_S(short, short, "strh") CK_PR_STORE_S(char, char, "strb") #undef CK_PR_STORE_S #undef CK_PR_STORE #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) #define CK_PR_DOUBLE_STORE(T, N) \ CK_CC_INLINE static void \ ck_pr_md_store_##N(const T *target, T value) \ { \ T tmp; \ uint32_t flag; \ __asm __volatile("1: \n" \ "ldrexd %0, [%2]\n" \ "strexd %1, %3, [%2]\n" \ "teq %1, #0\n" \ "it ne \n" \ "bne 1b\n" \ : "=&r" (tmp), "=&r" (flag) \ : "r" (target), "r" (value) \ : "memory", "cc"); \ } CK_PR_DOUBLE_STORE(uint64_t, 64) #ifndef CK_PR_DISABLE_DOUBLE CK_PR_DOUBLE_STORE(double, double) #endif #undef CK_PR_DOUBLE_STORE #define CK_PR_DOUBLE_CAS_VALUE(T, N) \ CK_CC_INLINE static bool \ ck_pr_cas_##N##_value(T *target, T compare, T set, T *value) \ { \ T previous; \ int tmp; \ \ __asm__ __volatile__("1:" \ "ldrexd %0, [%4];" \ "cmp %Q0, %Q2;" \ "ittt eq;" \ "cmpeq %R0, %R2;" \ "strexdeq %1, %3, [%4];" \ "cmpeq %1, #1;" \ "beq 1b;" \ :"=&r" (previous), "=&r" (tmp) \ : "r" (compare), "r" (set) , \ "r"(target) \ : "memory", "cc"); \ *value = previous; \ return (*value == compare); \ } CK_PR_DOUBLE_CAS_VALUE(uint64_t, 64) #ifndef CK_PR_DISABLE_DOUBLE CK_PR_DOUBLE_CAS_VALUE(double, double) #endif #undef CK_PR_DOUBLE_CAS_VALUE CK_CC_INLINE static bool ck_pr_cas_ptr_2_value(void *target, void *compare, void *set, void *value) { uint32_t *_compare = CK_CPP_CAST(uint32_t *, compare); uint32_t *_set = CK_CPP_CAST(uint32_t *, set); uint64_t __compare = ((uint64_t)_compare[0]) | ((uint64_t)_compare[1] << 32); uint64_t __set = ((uint64_t)_set[0]) | ((uint64_t)_set[1] << 32); return (ck_pr_cas_64_value(CK_CPP_CAST(uint64_t *, target), __compare, __set, CK_CPP_CAST(uint64_t *, value))); } #define CK_PR_DOUBLE_CAS(T, N) \ CK_CC_INLINE static bool \ ck_pr_cas_##N(T *target, T compare, T set) \ { \ int ret; \ T tmp; \ \ __asm__ __volatile__("1:" \ "mov %0, #0;" \ "ldrexd %1, [%4];" \ "cmp %Q1, %Q2;" \ "itttt eq;" \ "cmpeq %R1, %R2;" \ "strexdeq %1, %3, [%4];" \ "moveq %0, #1;" \ "cmpeq %1, #1;" \ "beq 1b;" \ : "=&r" (ret), "=&r" (tmp) \ : "r" (compare), "r" (set) , \ "r"(target) \ : "memory", "cc"); \ \ return (ret); \ } CK_PR_DOUBLE_CAS(uint64_t, 64) #ifndef CK_PR_DISABLE_DOUBLE CK_PR_DOUBLE_CAS(double, double) #endif CK_CC_INLINE static bool ck_pr_cas_ptr_2(void *target, void *compare, void *set) { uint32_t *_compare = CK_CPP_CAST(uint32_t *, compare); uint32_t *_set = CK_CPP_CAST(uint32_t *, set); uint64_t __compare = ((uint64_t)_compare[0]) | ((uint64_t)_compare[1] << 32); uint64_t __set = ((uint64_t)_set[0]) | ((uint64_t)_set[1] << 32); return (ck_pr_cas_64(CK_CPP_CAST(uint64_t *, target), __compare, __set)); } #endif CK_CC_INLINE static bool ck_pr_cas_ptr_value(void *target, void *compare, void *set, void *value) { void *previous, *tmp; __asm__ __volatile__("1:" "ldrex %0, [%2];" "cmp %0, %4;" "itt eq;" "strexeq %1, %3, [%2];" "cmpeq %1, #1;" "beq 1b;" : "=&r" (previous), "=&r" (tmp) : "r" (target), "r" (set), "r" (compare) : "memory", "cc"); *(void **)value = previous; return (previous == compare); } CK_CC_INLINE static bool ck_pr_cas_ptr(void *target, void *compare, void *set) { void *previous, *tmp; __asm__ __volatile__("1:" "ldrex %0, [%2];" "cmp %0, %4;" "itt eq;" "strexeq %1, %3, [%2];" "cmpeq %1, #1;" "beq 1b;" : "=&r" (previous), "=&r" (tmp) : "r" (target), "r" (set), "r" (compare) : "memory", "cc"); return (previous == compare); } #define CK_PR_CAS(N, T, W) \ CK_CC_INLINE static bool \ ck_pr_cas_##N##_value(T *target, T compare, T set, T *value) \ { \ T previous = 0, tmp = 0; \ __asm__ __volatile__("1:" \ "ldrex" W " %0, [%2];" \ "cmp %0, %4;" \ "itt eq;" \ "strex" W "eq %1, %3, [%2];" \ "cmpeq %1, #1;" \ "beq 1b;" \ /* \ * Using "+&" instead of "=&" to avoid bogus \ * clang warnings. \ */ \ : "+&r" (previous), \ "+&r" (tmp) \ : "r" (target), \ "r" (set), \ "r" (compare) \ : "memory", "cc"); \ *value = previous; \ return (previous == compare); \ } \ CK_CC_INLINE static bool \ ck_pr_cas_##N(T *target, T compare, T set) \ { \ T previous = 0, tmp = 0; \ __asm__ __volatile__("1:" \ "ldrex" W " %0, [%2];" \ "cmp %0, %4;" \ "itt eq;" \ "strex" W "eq %1, %3, [%2];" \ "cmpeq %1, #1;" \ "beq 1b;" \ : "+&r" (previous), \ "+&r" (tmp) \ : "r" (target), \ "r" (set), \ "r" (compare) \ : "memory", "cc"); \ return (previous == compare); \ } CK_PR_CAS(32, uint32_t, "") CK_PR_CAS(uint, unsigned int, "") CK_PR_CAS(int, int, "") CK_PR_CAS(16, uint16_t, "h") CK_PR_CAS(8, uint8_t, "b") CK_PR_CAS(short, short, "h") CK_PR_CAS(char, char, "b") #undef CK_PR_CAS #define CK_PR_FAS(N, M, T, W) \ CK_CC_INLINE static T \ ck_pr_fas_##N(M *target, T v) \ { \ T previous = 0; \ T tmp = 0; \ __asm__ __volatile__("1:" \ "ldrex" W " %0, [%2];" \ "strex" W " %1, %3, [%2];" \ "cmp %1, #0;" \ "bne 1b;" \ : "+&r" (previous), \ "+&r" (tmp) \ : "r" (target), \ "r" (v) \ : "memory", "cc"); \ return (previous); \ } CK_PR_FAS(32, uint32_t, uint32_t, "") CK_PR_FAS(ptr, void, void *, "") CK_PR_FAS(int, int, int, "") CK_PR_FAS(uint, unsigned int, unsigned int, "") CK_PR_FAS(16, uint16_t, uint16_t, "h") CK_PR_FAS(8, uint8_t, uint8_t, "b") CK_PR_FAS(short, short, short, "h") CK_PR_FAS(char, char, char, "b") #undef CK_PR_FAS #define CK_PR_UNARY(O, N, M, T, I, W) \ CK_CC_INLINE static void \ ck_pr_##O##_##N(M *target) \ { \ T previous = 0; \ T tmp = 0; \ __asm__ __volatile__("1:" \ "ldrex" W " %0, [%2];" \ I ";" \ "strex" W " %1, %0, [%2];" \ "cmp %1, #0;" \ "bne 1b;" \ : "+&r" (previous), \ "+&r" (tmp) \ : "r" (target) \ : "memory", "cc"); \ return; \ } CK_PR_UNARY(inc, ptr, void, void *, "add %0, %0, #1", "") CK_PR_UNARY(dec, ptr, void, void *, "sub %0, %0, #1", "") CK_PR_UNARY(not, ptr, void, void *, "mvn %0, %0", "") CK_PR_UNARY(neg, ptr, void, void *, "neg %0, %0", "") #define CK_PR_UNARY_S(S, T, W) \ CK_PR_UNARY(inc, S, T, T, "add %0, %0, #1", W) \ CK_PR_UNARY(dec, S, T, T, "sub %0, %0, #1", W) \ CK_PR_UNARY(not, S, T, T, "mvn %0, %0", W) \ CK_PR_UNARY(neg, S, T, T, "neg %0, %0", W) \ CK_PR_UNARY_S(32, uint32_t, "") CK_PR_UNARY_S(uint, unsigned int, "") CK_PR_UNARY_S(int, int, "") CK_PR_UNARY_S(16, uint16_t, "h") CK_PR_UNARY_S(8, uint8_t, "b") CK_PR_UNARY_S(short, short, "h") CK_PR_UNARY_S(char, char, "b") #undef CK_PR_UNARY_S #undef CK_PR_UNARY #define CK_PR_BINARY(O, N, M, T, I, W) \ CK_CC_INLINE static void \ ck_pr_##O##_##N(M *target, T delta) \ { \ T previous = 0; \ T tmp = 0; \ __asm__ __volatile__("1:" \ "ldrex" W " %0, [%2];" \ I " %0, %0, %3;" \ "strex" W " %1, %0, [%2];" \ "cmp %1, #0;" \ "bne 1b;" \ : "+&r" (previous), \ "+&r" (tmp) \ : "r" (target), \ "r" (delta) \ : "memory", "cc"); \ return; \ } CK_PR_BINARY(and, ptr, void, uintptr_t, "and", "") CK_PR_BINARY(add, ptr, void, uintptr_t, "add", "") CK_PR_BINARY(or, ptr, void, uintptr_t, "orr", "") CK_PR_BINARY(sub, ptr, void, uintptr_t, "sub", "") CK_PR_BINARY(xor, ptr, void, uintptr_t, "eor", "") #define CK_PR_BINARY_S(S, T, W) \ CK_PR_BINARY(and, S, T, T, "and", W) \ CK_PR_BINARY(add, S, T, T, "add", W) \ CK_PR_BINARY(or, S, T, T, "orr", W) \ CK_PR_BINARY(sub, S, T, T, "sub", W) \ CK_PR_BINARY(xor, S, T, T, "eor", W) CK_PR_BINARY_S(32, uint32_t, "") CK_PR_BINARY_S(uint, unsigned int, "") CK_PR_BINARY_S(int, int, "") CK_PR_BINARY_S(16, uint16_t, "h") CK_PR_BINARY_S(8, uint8_t, "b") CK_PR_BINARY_S(short, short, "h") CK_PR_BINARY_S(char, char, "b") #undef CK_PR_BINARY_S #undef CK_PR_BINARY CK_CC_INLINE static void * ck_pr_faa_ptr(void *target, uintptr_t delta) { uintptr_t previous, r, tmp; __asm__ __volatile__("1:" "ldrex %0, [%3];" "add %1, %4, %0;" "strex %2, %1, [%3];" "cmp %2, #0;" "bne 1b;" : "=&r" (previous), "=&r" (r), "=&r" (tmp) : "r" (target), "r" (delta) : "memory", "cc"); return (void *)(previous); } #define CK_PR_FAA(S, T, W) \ CK_CC_INLINE static T \ ck_pr_faa_##S(T *target, T delta) \ { \ T previous = 0, r = 0, tmp = 0; \ __asm__ __volatile__("1:" \ "ldrex" W " %0, [%3];" \ "add %1, %4, %0;" \ "strex" W " %2, %1, [%3];" \ "cmp %2, #0;" \ "bne 1b;" \ : "+&r" (previous), \ "+&r" (r), \ "+&r" (tmp) \ : "r" (target), \ "r" (delta) \ : "memory", "cc"); \ return (previous); \ } CK_PR_FAA(32, uint32_t, "") CK_PR_FAA(uint, unsigned int, "") CK_PR_FAA(int, int, "") CK_PR_FAA(16, uint16_t, "h") CK_PR_FAA(8, uint8_t, "b") CK_PR_FAA(short, short, "h") CK_PR_FAA(char, char, "b") #undef CK_PR_FAA #endif /* CK_PR_ARM_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/ck_cc.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * Copyright 2014 Paul Khuong. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_GCC_CC_H #define CK_GCC_CC_H #include #ifdef __SUNPRO_C #define CK_CC_UNUSED #define CK_CC_USED #define CK_CC_IMM #define CK_CC_IMM_U32 #else #define CK_CC_UNUSED __attribute__((unused)) #define CK_CC_USED __attribute__((used)) #define CK_CC_IMM "i" #if defined(__x86_64__) || defined(__x86__) #define CK_CC_IMM_U32 "Z" #define CK_CC_IMM_S32 "e" #else #define CK_CC_IMM_U32 CK_CC_IMM #define CK_CC_IMM_S32 CK_CC_IMM #endif /* __x86_64__ || __x86__ */ #endif #ifdef __OPTIMIZE__ #define CK_CC_INLINE CK_CC_UNUSED inline #else #define CK_CC_INLINE CK_CC_UNUSED #endif #define CK_CC_FORCE_INLINE CK_CC_UNUSED __attribute__((always_inline)) inline #define CK_CC_RESTRICT __restrict__ /* * Packed attribute. */ #define CK_CC_PACKED __attribute__((packed)) /* * Weak reference. */ #define CK_CC_WEAKREF __attribute__((weakref)) /* * Alignment attribute. */ #define CK_CC_ALIGN(B) __attribute__((aligned(B))) /* * Cache align. */ #define CK_CC_CACHELINE CK_CC_ALIGN(CK_MD_CACHELINE) /* * These are functions which should be avoided. */ #ifdef __freestanding__ #pragma GCC poison malloc free #endif /* * Branch execution hints. */ #define CK_CC_LIKELY(x) (__builtin_expect(!!(x), 1)) #define CK_CC_UNLIKELY(x) (__builtin_expect(!!(x), 0)) /* * Some compilers are overly strict regarding aliasing semantics. * Unfortunately, in many cases it makes more sense to pay aliasing * cost rather than overly expensive register spillage. */ #define CK_CC_ALIASED __attribute__((__may_alias__)) /* * Compile-time typeof */ #define CK_CC_TYPEOF(X, DEFAULT) __typeof__(X) /* * Portability wrappers for bitwise ops. */ #define CK_F_CC_FFS #define CK_F_CC_CLZ #define CK_F_CC_CTZ #define CK_F_CC_POPCOUNT CK_CC_INLINE static int ck_cc_ffs(unsigned int x) { return __builtin_ffs(x); } CK_CC_INLINE static int ck_cc_clz(unsigned int x) { return __builtin_clz(x); } CK_CC_INLINE static int ck_cc_ctz(unsigned int x) { return __builtin_ctz(x); } CK_CC_INLINE static int ck_cc_popcount(unsigned int x) { return __builtin_popcount(x); } #endif /* CK_GCC_CC_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/ck_f_pr.h ================================================ /* DO NOT EDIT. This is auto-generated from feature.sh */ #define CK_F_PR_ADD_16 #define CK_F_PR_ADD_32 #define CK_F_PR_ADD_64 #define CK_F_PR_ADD_8 #define CK_F_PR_ADD_CHAR #define CK_F_PR_ADD_INT #define CK_F_PR_ADD_PTR #define CK_F_PR_ADD_UINT #define CK_F_PR_AND_16 #define CK_F_PR_AND_32 #define CK_F_PR_AND_64 #define CK_F_PR_AND_8 #define CK_F_PR_AND_CHAR #define CK_F_PR_AND_INT #define CK_F_PR_AND_PTR #define CK_F_PR_AND_UINT #define CK_F_PR_CAS_16 #define CK_F_PR_CAS_16_VALUE #define CK_F_PR_CAS_32 #define CK_F_PR_CAS_32_VALUE #define CK_F_PR_CAS_64 #define CK_F_PR_CAS_64_VALUE #define CK_F_PR_CAS_8 #define CK_F_PR_CAS_8_VALUE #define CK_F_PR_CAS_CHAR #define CK_F_PR_CAS_CHAR_VALUE #define CK_F_PR_CAS_INT #define CK_F_PR_CAS_INT_VALUE #define CK_F_PR_CAS_PTR #define CK_F_PR_CAS_PTR_VALUE #define CK_F_PR_CAS_UINT #define CK_F_PR_CAS_UINT_VALUE #define CK_F_PR_DEC_16 #define CK_F_PR_DEC_32 #define CK_F_PR_DEC_64 #define CK_F_PR_DEC_8 #define CK_F_PR_DEC_CHAR #define CK_F_PR_DEC_INT #define CK_F_PR_DEC_PTR #define CK_F_PR_DEC_UINT #define CK_F_PR_FAA_16 #define CK_F_PR_FAA_32 #define CK_F_PR_FAA_64 #define CK_F_PR_FAA_8 #define CK_F_PR_FAA_CHAR #define CK_F_PR_FAA_INT #define CK_F_PR_FAA_PTR #define CK_F_PR_FAA_UINT #define CK_F_PR_FENCE_LOAD #define CK_F_PR_FENCE_LOAD_DEPENDS #define CK_F_PR_FENCE_MEMORY #define CK_F_PR_FENCE_STORE #define CK_F_PR_FENCE_STRICT_LOAD #define CK_F_PR_FENCE_STRICT_MEMORY #define CK_F_PR_FENCE_STRICT_STORE #define CK_F_PR_INC_16 #define CK_F_PR_INC_32 #define CK_F_PR_INC_64 #define CK_F_PR_INC_8 #define CK_F_PR_INC_CHAR #define CK_F_PR_INC_INT #define CK_F_PR_INC_PTR #define CK_F_PR_INC_UINT #define CK_F_PR_LOAD_16 #define CK_F_PR_LOAD_32 #define CK_F_PR_LOAD_64 #define CK_F_PR_LOAD_8 #define CK_F_PR_LOAD_CHAR #define CK_F_PR_LOAD_INT #define CK_F_PR_LOAD_PTR #define CK_F_PR_LOAD_UINT #define CK_F_PR_OR_16 #define CK_F_PR_OR_32 #define CK_F_PR_OR_64 #define CK_F_PR_OR_8 #define CK_F_PR_OR_CHAR #define CK_F_PR_OR_INT #define CK_F_PR_OR_PTR #define CK_F_PR_OR_UINT #define CK_F_PR_STALL #define CK_F_PR_STORE_16 #define CK_F_PR_STORE_32 #define CK_F_PR_STORE_64 #define CK_F_PR_STORE_8 #define CK_F_PR_STORE_CHAR #define CK_F_PR_STORE_INT #define CK_F_PR_STORE_PTR #define CK_F_PR_STORE_UINT #define CK_F_PR_SUB_16 #define CK_F_PR_SUB_32 #define CK_F_PR_SUB_64 #define CK_F_PR_SUB_8 #define CK_F_PR_SUB_CHAR #define CK_F_PR_SUB_INT #define CK_F_PR_SUB_PTR #define CK_F_PR_SUB_UINT #define CK_F_PR_XOR_16 #define CK_F_PR_XOR_32 #define CK_F_PR_XOR_64 #define CK_F_PR_XOR_8 #define CK_F_PR_XOR_CHAR #define CK_F_PR_XOR_INT #define CK_F_PR_XOR_PTR #define CK_F_PR_XOR_UINT ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/ck_pr.h ================================================ /* * Copyright 2010 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_GCC_H #define CK_PR_GCC_H #ifndef CK_PR_H #error Do not include this file directly, use ck_pr.h #endif #include CK_CC_INLINE static void ck_pr_barrier(void) { __asm__ __volatile__("" ::: "memory"); return; } #ifndef CK_F_PR #define CK_F_PR #include #include /* * The following represent supported atomic operations. * These operations may be emulated. */ #include "ck_f_pr.h" #define CK_PR_ACCESS(x) (*(volatile __typeof__(x) *)&(x)) #define CK_PR_LOAD(S, M, T) \ CK_CC_INLINE static T \ ck_pr_md_load_##S(const M *target) \ { \ T r; \ ck_pr_barrier(); \ r = CK_PR_ACCESS(*(const T *)target); \ ck_pr_barrier(); \ return (r); \ } \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ ck_pr_barrier(); \ CK_PR_ACCESS(*(T *)target) = v; \ ck_pr_barrier(); \ return; \ } CK_CC_INLINE static void * ck_pr_md_load_ptr(const void *target) { void *r; ck_pr_barrier(); r = CK_CC_DECONST_PTR(CK_PR_ACCESS(target)); ck_pr_barrier(); return r; } CK_CC_INLINE static void ck_pr_md_store_ptr(void *target, const void *v) { ck_pr_barrier(); CK_PR_ACCESS(target) = CK_CC_DECONST_PTR(v); ck_pr_barrier(); return; } #define CK_PR_LOAD_S(S, T) CK_PR_LOAD(S, T, T) CK_PR_LOAD_S(char, char) CK_PR_LOAD_S(uint, unsigned int) CK_PR_LOAD_S(int, int) #ifndef CK_PR_DISABLE_DOUBLE CK_PR_LOAD_S(double, double) #endif CK_PR_LOAD_S(64, uint64_t) CK_PR_LOAD_S(32, uint32_t) CK_PR_LOAD_S(16, uint16_t) CK_PR_LOAD_S(8, uint8_t) #undef CK_PR_LOAD_S #undef CK_PR_LOAD CK_CC_INLINE static void ck_pr_stall(void) { ck_pr_barrier(); } /* * Load and store fences are equivalent to full fences in the GCC port. */ #define CK_PR_FENCE(T) \ CK_CC_INLINE static void \ ck_pr_fence_strict_##T(void) \ { \ __sync_synchronize(); \ } CK_PR_FENCE(atomic) CK_PR_FENCE(atomic_atomic) CK_PR_FENCE(atomic_load) CK_PR_FENCE(atomic_store) CK_PR_FENCE(store_atomic) CK_PR_FENCE(load_atomic) CK_PR_FENCE(load) CK_PR_FENCE(load_load) CK_PR_FENCE(load_store) CK_PR_FENCE(store) CK_PR_FENCE(store_store) CK_PR_FENCE(store_load) CK_PR_FENCE(memory) CK_PR_FENCE(acquire) CK_PR_FENCE(release) CK_PR_FENCE(acqrel) CK_PR_FENCE(lock) CK_PR_FENCE(unlock) #undef CK_PR_FENCE /* * Atomic compare and swap. */ #define CK_PR_CAS(S, M, T) \ CK_CC_INLINE static bool \ ck_pr_cas_##S(M *target, T compare, T set) \ { \ bool z; \ z = __sync_bool_compare_and_swap((T *)target, compare, set); \ return z; \ } CK_PR_CAS(ptr, void, void *) #define CK_PR_CAS_S(S, T) CK_PR_CAS(S, T, T) CK_PR_CAS_S(char, char) CK_PR_CAS_S(int, int) CK_PR_CAS_S(uint, unsigned int) CK_PR_CAS_S(64, uint64_t) CK_PR_CAS_S(32, uint32_t) CK_PR_CAS_S(16, uint16_t) CK_PR_CAS_S(8, uint8_t) #undef CK_PR_CAS_S #undef CK_PR_CAS /* * Compare and swap, set *v to old value of target. */ CK_CC_INLINE static bool ck_pr_cas_ptr_value(void *target, void *compare, void *set, void *v) { set = __sync_val_compare_and_swap((void **)target, compare, set); *(void **)v = set; return (set == compare); } #define CK_PR_CAS_O(S, T) \ CK_CC_INLINE static bool \ ck_pr_cas_##S##_value(T *target, T compare, T set, T *v) \ { \ set = __sync_val_compare_and_swap(target, compare, set);\ *v = set; \ return (set == compare); \ } CK_PR_CAS_O(char, char) CK_PR_CAS_O(int, int) CK_PR_CAS_O(uint, unsigned int) CK_PR_CAS_O(64, uint64_t) CK_PR_CAS_O(32, uint32_t) CK_PR_CAS_O(16, uint16_t) CK_PR_CAS_O(8, uint8_t) #undef CK_PR_CAS_O /* * Atomic fetch-and-add operations. */ #define CK_PR_FAA(S, M, T) \ CK_CC_INLINE static T \ ck_pr_faa_##S(M *target, T d) \ { \ d = __sync_fetch_and_add((T *)target, d); \ return (d); \ } CK_PR_FAA(ptr, void, void *) #define CK_PR_FAA_S(S, T) CK_PR_FAA(S, T, T) CK_PR_FAA_S(char, char) CK_PR_FAA_S(uint, unsigned int) CK_PR_FAA_S(int, int) CK_PR_FAA_S(64, uint64_t) CK_PR_FAA_S(32, uint32_t) CK_PR_FAA_S(16, uint16_t) CK_PR_FAA_S(8, uint8_t) #undef CK_PR_FAA_S #undef CK_PR_FAA /* * Atomic store-only binary operations. */ #define CK_PR_BINARY(K, S, M, T) \ CK_CC_INLINE static void \ ck_pr_##K##_##S(M *target, T d) \ { \ d = __sync_fetch_and_##K((T *)target, d); \ return; \ } #define CK_PR_BINARY_S(K, S, T) CK_PR_BINARY(K, S, T, T) #define CK_PR_GENERATE(K) \ CK_PR_BINARY(K, ptr, void, void *) \ CK_PR_BINARY_S(K, char, char) \ CK_PR_BINARY_S(K, int, int) \ CK_PR_BINARY_S(K, uint, unsigned int) \ CK_PR_BINARY_S(K, 64, uint64_t) \ CK_PR_BINARY_S(K, 32, uint32_t) \ CK_PR_BINARY_S(K, 16, uint16_t) \ CK_PR_BINARY_S(K, 8, uint8_t) CK_PR_GENERATE(add) CK_PR_GENERATE(sub) CK_PR_GENERATE(and) CK_PR_GENERATE(or) CK_PR_GENERATE(xor) #undef CK_PR_GENERATE #undef CK_PR_BINARY_S #undef CK_PR_BINARY #define CK_PR_UNARY(S, M, T) \ CK_CC_INLINE static void \ ck_pr_inc_##S(M *target) \ { \ ck_pr_add_##S(target, (T)1); \ return; \ } \ CK_CC_INLINE static void \ ck_pr_dec_##S(M *target) \ { \ ck_pr_sub_##S(target, (T)1); \ return; \ } #define CK_PR_UNARY_S(S, M) CK_PR_UNARY(S, M, M) CK_PR_UNARY(ptr, void, void *) CK_PR_UNARY_S(char, char) CK_PR_UNARY_S(int, int) CK_PR_UNARY_S(uint, unsigned int) CK_PR_UNARY_S(64, uint64_t) CK_PR_UNARY_S(32, uint32_t) CK_PR_UNARY_S(16, uint16_t) CK_PR_UNARY_S(8, uint8_t) #undef CK_PR_UNARY_S #undef CK_PR_UNARY #endif /* !CK_F_PR */ #endif /* CK_PR_GCC_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/ppc/ck_f_pr.h ================================================ /* DO NOT EDIT. This is auto-generated from feature.sh */ #define CK_F_PR_ADD_32 #define CK_F_PR_ADD_INT #define CK_F_PR_ADD_PTR #define CK_F_PR_ADD_UINT #define CK_F_PR_AND_32 #define CK_F_PR_AND_INT #define CK_F_PR_AND_PTR #define CK_F_PR_AND_UINT #define CK_F_PR_CAS_32 #define CK_F_PR_CAS_32_VALUE #define CK_F_PR_CAS_INT #define CK_F_PR_CAS_INT_VALUE #define CK_F_PR_CAS_PTR #define CK_F_PR_CAS_PTR_VALUE #define CK_F_PR_CAS_UINT #define CK_F_PR_CAS_UINT_VALUE #define CK_F_PR_DEC_32 #define CK_F_PR_DEC_INT #define CK_F_PR_DEC_PTR #define CK_F_PR_DEC_UINT #define CK_F_PR_FAA_32 #define CK_F_PR_FAA_INT #define CK_F_PR_FAA_PTR #define CK_F_PR_FAA_UINT #define CK_F_PR_FAS_32 #define CK_F_PR_FAS_INT #define CK_F_PR_FAS_PTR #define CK_F_PR_FAS_UINT #define CK_F_PR_FENCE_LOAD #define CK_F_PR_FENCE_LOAD_DEPENDS #define CK_F_PR_FENCE_MEMORY #define CK_F_PR_FENCE_STORE #define CK_F_PR_FENCE_STRICT_LOAD #define CK_F_PR_FENCE_STRICT_LOAD_DEPENDS #define CK_F_PR_FENCE_STRICT_MEMORY #define CK_F_PR_FENCE_STRICT_STORE #define CK_F_PR_INC_32 #define CK_F_PR_INC_INT #define CK_F_PR_INC_PTR #define CK_F_PR_INC_UINT #define CK_F_PR_LOAD_16 #define CK_F_PR_LOAD_32 #define CK_F_PR_LOAD_8 #define CK_F_PR_LOAD_CHAR #define CK_F_PR_LOAD_INT #define CK_F_PR_LOAD_PTR #define CK_F_PR_LOAD_SHORT #define CK_F_PR_LOAD_UINT #define CK_F_PR_NEG_32 #define CK_F_PR_NEG_INT #define CK_F_PR_NEG_PTR #define CK_F_PR_NEG_UINT #define CK_F_PR_NOT_32 #define CK_F_PR_NOT_INT #define CK_F_PR_NOT_PTR #define CK_F_PR_NOT_UINT #define CK_F_PR_OR_32 #define CK_F_PR_OR_INT #define CK_F_PR_OR_PTR #define CK_F_PR_OR_UINT #define CK_F_PR_STALL #define CK_F_PR_STORE_16 #define CK_F_PR_STORE_32 #define CK_F_PR_STORE_8 #define CK_F_PR_STORE_CHAR #define CK_F_PR_STORE_INT #define CK_F_PR_STORE_PTR #define CK_F_PR_STORE_SHORT #define CK_F_PR_STORE_UINT #define CK_F_PR_SUB_32 #define CK_F_PR_SUB_INT #define CK_F_PR_SUB_PTR #define CK_F_PR_SUB_UINT #define CK_F_PR_XOR_32 #define CK_F_PR_XOR_INT #define CK_F_PR_XOR_PTR #define CK_F_PR_XOR_UINT ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/ppc/ck_pr.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * Copyright 2012 João Fernandes. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_PPC_H #define CK_PR_PPC_H #ifndef CK_PR_H #error Do not include this file directly, use ck_pr.h #endif #include #include /* * The following represent supported atomic operations. * These operations may be emulated. */ #include "ck_f_pr.h" /* * Minimum interface requirement met. */ #define CK_F_PR /* * This bounces the hardware thread from low to medium * priority. I am unsure of the benefits of this approach * but it is used by the Linux kernel. */ CK_CC_INLINE static void ck_pr_stall(void) { __asm__ __volatile__("or 1, 1, 1;" "or 2, 2, 2;" ::: "memory"); return; } #define CK_PR_FENCE(T, I) \ CK_CC_INLINE static void \ ck_pr_fence_strict_##T(void) \ { \ __asm__ __volatile__(I ::: "memory"); \ } CK_PR_FENCE(atomic, "lwsync") CK_PR_FENCE(atomic_store, "lwsync") CK_PR_FENCE(atomic_load, "sync") CK_PR_FENCE(store_atomic, "lwsync") CK_PR_FENCE(load_atomic, "lwsync") CK_PR_FENCE(store, "lwsync") CK_PR_FENCE(store_load, "sync") CK_PR_FENCE(load, "lwsync") CK_PR_FENCE(load_store, "lwsync") CK_PR_FENCE(memory, "sync") CK_PR_FENCE(acquire, "lwsync") CK_PR_FENCE(release, "lwsync") CK_PR_FENCE(acqrel, "lwsync") CK_PR_FENCE(lock, "lwsync") CK_PR_FENCE(unlock, "lwsync") #undef CK_PR_FENCE #define CK_PR_LOAD(S, M, T, C, I) \ CK_CC_INLINE static T \ ck_pr_md_load_##S(const M *target) \ { \ T r; \ __asm__ __volatile__(I "%U1%X1 %0, %1" \ : "=r" (r) \ : "m" (*(const C *)target) \ : "memory"); \ return (r); \ } CK_PR_LOAD(ptr, void, void *, uint32_t, "lwz") #define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) CK_PR_LOAD_S(32, uint32_t, "lwz") CK_PR_LOAD_S(16, uint16_t, "lhz") CK_PR_LOAD_S(8, uint8_t, "lbz") CK_PR_LOAD_S(uint, unsigned int, "lwz") CK_PR_LOAD_S(int, int, "lwz") CK_PR_LOAD_S(short, short, "lhz") CK_PR_LOAD_S(char, char, "lbz") #undef CK_PR_LOAD_S #undef CK_PR_LOAD #define CK_PR_STORE(S, M, T, C, I) \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ __asm__ __volatile__(I "%U0%X0 %1, %0" \ : "=m" (*(C *)target) \ : "r" (v) \ : "memory"); \ return; \ } CK_PR_STORE(ptr, void, const void *, uint32_t, "stw") #define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) CK_PR_STORE_S(32, uint32_t, "stw") CK_PR_STORE_S(16, uint16_t, "sth") CK_PR_STORE_S(8, uint8_t, "stb") CK_PR_STORE_S(uint, unsigned int, "stw") CK_PR_STORE_S(int, int, "stw") CK_PR_STORE_S(short, short, "sth") CK_PR_STORE_S(char, char, "stb") #undef CK_PR_STORE_S #undef CK_PR_STORE #define CK_PR_CAS(N, T, M) \ CK_CC_INLINE static bool \ ck_pr_cas_##N##_value(M *target, T compare, T set, M *value) \ { \ T previous; \ __asm__ __volatile__("1:" \ "lwarx %0, 0, %1;" \ "cmpw 0, %0, %3;" \ "bne- 2f;" \ "stwcx. %2, 0, %1;" \ "bne- 1b;" \ "2:" \ : "=&r" (previous) \ : "r" (target), \ "r" (set), \ "r" (compare) \ : "memory", "cc"); \ *(T *)value = previous; \ return (previous == compare); \ } \ CK_CC_INLINE static bool \ ck_pr_cas_##N(M *target, T compare, T set) \ { \ T previous; \ __asm__ __volatile__("1:" \ "lwarx %0, 0, %1;" \ "cmpw 0, %0, %3;" \ "bne- 2f;" \ "stwcx. %2, 0, %1;" \ "bne- 1b;" \ "2:" \ : "=&r" (previous) \ : "r" (target), \ "r" (set), \ "r" (compare) \ : "memory", "cc"); \ return (previous == compare); \ } CK_PR_CAS(ptr, void *, void) #define CK_PR_CAS_S(a, b) CK_PR_CAS(a, b, b) CK_PR_CAS_S(32, uint32_t) CK_PR_CAS_S(uint, unsigned int) CK_PR_CAS_S(int, int) #undef CK_PR_CAS_S #undef CK_PR_CAS #define CK_PR_FAS(N, M, T, W) \ CK_CC_INLINE static T \ ck_pr_fas_##N(M *target, T v) \ { \ T previous; \ __asm__ __volatile__("1:" \ "l" W "arx %0, 0, %1;" \ "st" W "cx. %2, 0, %1;" \ "bne- 1b;" \ : "=&r" (previous) \ : "r" (target), \ "r" (v) \ : "memory", "cc"); \ return (previous); \ } CK_PR_FAS(32, uint32_t, uint32_t, "w") CK_PR_FAS(ptr, void, void *, "w") CK_PR_FAS(int, int, int, "w") CK_PR_FAS(uint, unsigned int, unsigned int, "w") #undef CK_PR_FAS #define CK_PR_UNARY(O, N, M, T, I, W) \ CK_CC_INLINE static void \ ck_pr_##O##_##N(M *target) \ { \ T previous; \ __asm__ __volatile__("1:" \ "l" W "arx %0, 0, %1;" \ I ";" \ "st" W "cx. %0, 0, %1;" \ "bne- 1b;" \ : "=&r" (previous) \ : "r" (target) \ : "memory", "cc"); \ return; \ } CK_PR_UNARY(inc, ptr, void, void *, "addic %0, %0, 1", "w") CK_PR_UNARY(dec, ptr, void, void *, "addic %0, %0, -1", "w") CK_PR_UNARY(not, ptr, void, void *, "not %0, %0", "w") CK_PR_UNARY(neg, ptr, void, void *, "neg %0, %0", "w") #define CK_PR_UNARY_S(S, T, W) \ CK_PR_UNARY(inc, S, T, T, "addic %0, %0, 1", W) \ CK_PR_UNARY(dec, S, T, T, "addic %0, %0, -1", W) \ CK_PR_UNARY(not, S, T, T, "not %0, %0", W) \ CK_PR_UNARY(neg, S, T, T, "neg %0, %0", W) CK_PR_UNARY_S(32, uint32_t, "w") CK_PR_UNARY_S(uint, unsigned int, "w") CK_PR_UNARY_S(int, int, "w") #undef CK_PR_UNARY_S #undef CK_PR_UNARY #define CK_PR_BINARY(O, N, M, T, I, W) \ CK_CC_INLINE static void \ ck_pr_##O##_##N(M *target, T delta) \ { \ T previous; \ __asm__ __volatile__("1:" \ "l" W "arx %0, 0, %1;" \ I " %0, %2, %0;" \ "st" W "cx. %0, 0, %1;" \ "bne- 1b;" \ : "=&r" (previous) \ : "r" (target), \ "r" (delta) \ : "memory", "cc"); \ return; \ } CK_PR_BINARY(and, ptr, void, uintptr_t, "and", "w") CK_PR_BINARY(add, ptr, void, uintptr_t, "add", "w") CK_PR_BINARY(or, ptr, void, uintptr_t, "or", "w") CK_PR_BINARY(sub, ptr, void, uintptr_t, "sub", "w") CK_PR_BINARY(xor, ptr, void, uintptr_t, "xor", "w") #define CK_PR_BINARY_S(S, T, W) \ CK_PR_BINARY(and, S, T, T, "and", W) \ CK_PR_BINARY(add, S, T, T, "add", W) \ CK_PR_BINARY(or, S, T, T, "or", W) \ CK_PR_BINARY(sub, S, T, T, "subf", W) \ CK_PR_BINARY(xor, S, T, T, "xor", W) CK_PR_BINARY_S(32, uint32_t, "w") CK_PR_BINARY_S(uint, unsigned int, "w") CK_PR_BINARY_S(int, int, "w") #undef CK_PR_BINARY_S #undef CK_PR_BINARY CK_CC_INLINE static void * ck_pr_faa_ptr(void *target, uintptr_t delta) { uintptr_t previous, r; __asm__ __volatile__("1:" "lwarx %0, 0, %2;" "add %1, %3, %0;" "stwcx. %1, 0, %2;" "bne- 1b;" : "=&r" (previous), "=&r" (r) : "r" (target), "r" (delta) : "memory", "cc"); return (void *)(previous); } #define CK_PR_FAA(S, T, W) \ CK_CC_INLINE static T \ ck_pr_faa_##S(T *target, T delta) \ { \ T previous, r; \ __asm__ __volatile__("1:" \ "l" W "arx %0, 0, %2;" \ "add %1, %3, %0;" \ "st" W "cx. %1, 0, %2;" \ "bne- 1b;" \ : "=&r" (previous), \ "=&r" (r) \ : "r" (target), \ "r" (delta) \ : "memory", "cc"); \ return (previous); \ } CK_PR_FAA(32, uint32_t, "w") CK_PR_FAA(uint, unsigned int, "w") CK_PR_FAA(int, int, "w") #undef CK_PR_FAA #endif /* CK_PR_PPC_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/ppc64/ck_f_pr.h ================================================ /* DO NOT EDIT. This is auto-generated from feature.sh */ #define CK_F_PR_ADD_32 #define CK_F_PR_ADD_64 #define CK_F_PR_ADD_INT #define CK_F_PR_ADD_PTR #define CK_F_PR_ADD_UINT #define CK_F_PR_AND_32 #define CK_F_PR_AND_64 #define CK_F_PR_AND_INT #define CK_F_PR_AND_PTR #define CK_F_PR_AND_UINT #define CK_F_PR_CAS_32 #define CK_F_PR_CAS_32_VALUE #define CK_F_PR_CAS_64 #define CK_F_PR_CAS_64_VALUE #define CK_F_PR_CAS_INT #define CK_F_PR_CAS_INT_VALUE #define CK_F_PR_CAS_PTR #define CK_F_PR_CAS_PTR_VALUE #define CK_F_PR_CAS_UINT #define CK_F_PR_CAS_UINT_VALUE #define CK_F_PR_DEC_32 #define CK_F_PR_DEC_64 #define CK_F_PR_DEC_INT #define CK_F_PR_DEC_PTR #define CK_F_PR_DEC_UINT #define CK_F_PR_FAA_32 #define CK_F_PR_FAA_64 #define CK_F_PR_FAA_INT #define CK_F_PR_FAA_PTR #define CK_F_PR_FAA_UINT #define CK_F_PR_FAS_32 #define CK_F_PR_FAS_64 #define CK_F_PR_FAS_INT #define CK_F_PR_FAS_PTR #define CK_F_PR_FAS_UINT #define CK_F_PR_FAS_DOUBLE #define CK_F_PR_FENCE_LOAD #define CK_F_PR_FENCE_LOAD_DEPENDS #define CK_F_PR_FENCE_MEMORY #define CK_F_PR_FENCE_STORE #define CK_F_PR_FENCE_STRICT_LOAD #define CK_F_PR_FENCE_STRICT_LOAD_DEPENDS #define CK_F_PR_FENCE_STRICT_MEMORY #define CK_F_PR_FENCE_STRICT_STORE #define CK_F_PR_INC_32 #define CK_F_PR_INC_64 #define CK_F_PR_INC_INT #define CK_F_PR_INC_PTR #define CK_F_PR_INC_UINT #define CK_F_PR_LOAD_16 #define CK_F_PR_LOAD_32 #define CK_F_PR_LOAD_64 #define CK_F_PR_LOAD_8 #define CK_F_PR_LOAD_CHAR #define CK_F_PR_LOAD_DOUBLE #define CK_F_PR_LOAD_INT #define CK_F_PR_LOAD_PTR #define CK_F_PR_LOAD_SHORT #define CK_F_PR_LOAD_UINT #define CK_F_PR_NEG_32 #define CK_F_PR_NEG_64 #define CK_F_PR_NEG_INT #define CK_F_PR_NEG_PTR #define CK_F_PR_NEG_UINT #define CK_F_PR_NOT_32 #define CK_F_PR_NOT_64 #define CK_F_PR_NOT_INT #define CK_F_PR_NOT_PTR #define CK_F_PR_NOT_UINT #define CK_F_PR_OR_32 #define CK_F_PR_OR_64 #define CK_F_PR_OR_INT #define CK_F_PR_OR_PTR #define CK_F_PR_OR_UINT #define CK_F_PR_STALL #define CK_F_PR_STORE_16 #define CK_F_PR_STORE_32 #define CK_F_PR_STORE_64 #define CK_F_PR_STORE_8 #define CK_F_PR_STORE_CHAR #define CK_F_PR_STORE_DOUBLE #define CK_F_PR_STORE_INT #define CK_F_PR_STORE_PTR #define CK_F_PR_STORE_SHORT #define CK_F_PR_STORE_UINT #define CK_F_PR_SUB_32 #define CK_F_PR_SUB_64 #define CK_F_PR_SUB_INT #define CK_F_PR_SUB_PTR #define CK_F_PR_SUB_UINT #define CK_F_PR_XOR_32 #define CK_F_PR_XOR_64 #define CK_F_PR_XOR_INT #define CK_F_PR_XOR_PTR #define CK_F_PR_XOR_UINT ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/ppc64/ck_pr.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_PPC64_H #define CK_PR_PPC64_H #ifndef CK_PR_H #error Do not include this file directly, use ck_pr.h #endif #include #include /* * The following represent supported atomic operations. * These operations may be emulated. */ #include "ck_f_pr.h" /* * Minimum interface requirement met. */ #define CK_F_PR /* * This bounces the hardware thread from low to medium * priority. I am unsure of the benefits of this approach * but it is used by the Linux kernel. */ CK_CC_INLINE static void ck_pr_stall(void) { __asm__ __volatile__("or 1, 1, 1;" "or 2, 2, 2;" ::: "memory"); return; } #define CK_PR_FENCE(T, I) \ CK_CC_INLINE static void \ ck_pr_fence_strict_##T(void) \ { \ __asm__ __volatile__(I ::: "memory"); \ } /* * These are derived from: * http://www.ibm.com/developerworks/systems/articles/powerpc.html */ CK_PR_FENCE(atomic, "lwsync") CK_PR_FENCE(atomic_store, "lwsync") CK_PR_FENCE(atomic_load, "sync") CK_PR_FENCE(store_atomic, "lwsync") CK_PR_FENCE(load_atomic, "lwsync") CK_PR_FENCE(store, "lwsync") CK_PR_FENCE(store_load, "sync") CK_PR_FENCE(load, "lwsync") CK_PR_FENCE(load_store, "lwsync") CK_PR_FENCE(memory, "sync") CK_PR_FENCE(acquire, "lwsync") CK_PR_FENCE(release, "lwsync") CK_PR_FENCE(acqrel, "lwsync") CK_PR_FENCE(lock, "lwsync") CK_PR_FENCE(unlock, "lwsync") #undef CK_PR_FENCE #define CK_PR_LOAD(S, M, T, C, I) \ CK_CC_INLINE static T \ ck_pr_md_load_##S(const M *target) \ { \ T r; \ __asm__ __volatile__(I "%U1%X1 %0, %1" \ : "=r" (r) \ : "m" (*(const C *)target) \ : "memory"); \ return (r); \ } CK_PR_LOAD(ptr, void, void *, uint64_t, "ld") #define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) CK_PR_LOAD_S(64, uint64_t, "ld") CK_PR_LOAD_S(32, uint32_t, "lwz") CK_PR_LOAD_S(16, uint16_t, "lhz") CK_PR_LOAD_S(8, uint8_t, "lbz") CK_PR_LOAD_S(uint, unsigned int, "lwz") CK_PR_LOAD_S(int, int, "lwz") CK_PR_LOAD_S(short, short, "lhz") CK_PR_LOAD_S(char, char, "lbz") #ifndef CK_PR_DISABLE_DOUBLE CK_PR_LOAD_S(double, double, "ld") #endif #undef CK_PR_LOAD_S #undef CK_PR_LOAD #define CK_PR_STORE(S, M, T, C, I) \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ __asm__ __volatile__(I "%U0%X0 %1, %0" \ : "=m" (*(C *)target) \ : "r" (v) \ : "memory"); \ return; \ } CK_PR_STORE(ptr, void, const void *, uint64_t, "std") #define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) CK_PR_STORE_S(64, uint64_t, "std") CK_PR_STORE_S(32, uint32_t, "stw") CK_PR_STORE_S(16, uint16_t, "sth") CK_PR_STORE_S(8, uint8_t, "stb") CK_PR_STORE_S(uint, unsigned int, "stw") CK_PR_STORE_S(int, int, "stw") CK_PR_STORE_S(short, short, "sth") CK_PR_STORE_S(char, char, "stb") #ifndef CK_PR_DISABLE_DOUBLE CK_PR_STORE_S(double, double, "std") #endif #undef CK_PR_STORE_S #undef CK_PR_STORE CK_CC_INLINE static bool ck_pr_cas_64_value(uint64_t *target, uint64_t compare, uint64_t set, uint64_t *value) { uint64_t previous; __asm__ __volatile__("1:" "ldarx %0, 0, %1;" "cmpd 0, %0, %3;" "bne- 2f;" "stdcx. %2, 0, %1;" "bne- 1b;" "2:" : "=&r" (previous) : "r" (target), "r" (set), "r" (compare) : "memory", "cc"); *value = previous; return (previous == compare); } CK_CC_INLINE static bool ck_pr_cas_ptr_value(void *target, void *compare, void *set, void *value) { void *previous; __asm__ __volatile__("1:" "ldarx %0, 0, %1;" "cmpd 0, %0, %3;" "bne- 2f;" "stdcx. %2, 0, %1;" "bne- 1b;" "2:" : "=&r" (previous) : "r" (target), "r" (set), "r" (compare) : "memory", "cc"); ck_pr_md_store_ptr(value, previous); return (previous == compare); } CK_CC_INLINE static bool ck_pr_cas_64(uint64_t *target, uint64_t compare, uint64_t set) { uint64_t previous; __asm__ __volatile__("1:" "ldarx %0, 0, %1;" "cmpd 0, %0, %3;" "bne- 2f;" "stdcx. %2, 0, %1;" "bne- 1b;" "2:" : "=&r" (previous) : "r" (target), "r" (set), "r" (compare) : "memory", "cc"); return (previous == compare); } CK_CC_INLINE static bool ck_pr_cas_ptr(void *target, void *compare, void *set) { void *previous; __asm__ __volatile__("1:" "ldarx %0, 0, %1;" "cmpd 0, %0, %3;" "bne- 2f;" "stdcx. %2, 0, %1;" "bne- 1b;" "2:" : "=&r" (previous) : "r" (target), "r" (set), "r" (compare) : "memory", "cc"); return (previous == compare); } #define CK_PR_CAS(N, T) \ CK_CC_INLINE static bool \ ck_pr_cas_##N##_value(T *target, T compare, T set, T *value) \ { \ T previous; \ __asm__ __volatile__("1:" \ "lwarx %0, 0, %1;" \ "cmpw 0, %0, %3;" \ "bne- 2f;" \ "stwcx. %2, 0, %1;" \ "bne- 1b;" \ "2:" \ : "=&r" (previous) \ : "r" (target), \ "r" (set), \ "r" (compare) \ : "memory", "cc"); \ *value = previous; \ return (previous == compare); \ } \ CK_CC_INLINE static bool \ ck_pr_cas_##N(T *target, T compare, T set) \ { \ T previous; \ __asm__ __volatile__("1:" \ "lwarx %0, 0, %1;" \ "cmpw 0, %0, %3;" \ "bne- 2f;" \ "stwcx. %2, 0, %1;" \ "bne- 1b;" \ "2:" \ : "=&r" (previous) \ : "r" (target), \ "r" (set), \ "r" (compare) \ : "memory", "cc"); \ return (previous == compare); \ } CK_PR_CAS(32, uint32_t) CK_PR_CAS(uint, unsigned int) CK_PR_CAS(int, int) #undef CK_PR_CAS #define CK_PR_FAS(N, M, T, W) \ CK_CC_INLINE static T \ ck_pr_fas_##N(M *target, T v) \ { \ T previous; \ __asm__ __volatile__("1:" \ "l" W "arx %0, 0, %1;" \ "st" W "cx. %2, 0, %1;" \ "bne- 1b;" \ : "=&r" (previous) \ : "r" (target), \ "r" (v) \ : "memory", "cc"); \ return (previous); \ } CK_PR_FAS(64, uint64_t, uint64_t, "d") CK_PR_FAS(32, uint32_t, uint32_t, "w") #ifndef CK_PR_DISABLE_DOUBLE CK_PR_FAS(double, double, double, "d") #endif CK_PR_FAS(ptr, void, void *, "d") CK_PR_FAS(int, int, int, "w") CK_PR_FAS(uint, unsigned int, unsigned int, "w") #undef CK_PR_FAS #define CK_PR_UNARY(O, N, M, T, I, W) \ CK_CC_INLINE static void \ ck_pr_##O##_##N(M *target) \ { \ T previous; \ __asm__ __volatile__("1:" \ "l" W "arx %0, 0, %1;" \ I ";" \ "st" W "cx. %0, 0, %1;" \ "bne- 1b;" \ : "=&r" (previous) \ : "r" (target) \ : "memory", "cc"); \ return; \ } CK_PR_UNARY(inc, ptr, void, void *, "addic %0, %0, 1", "d") CK_PR_UNARY(dec, ptr, void, void *, "addic %0, %0, -1", "d") CK_PR_UNARY(not, ptr, void, void *, "not %0, %0", "d") CK_PR_UNARY(neg, ptr, void, void *, "neg %0, %0", "d") #define CK_PR_UNARY_S(S, T, W) \ CK_PR_UNARY(inc, S, T, T, "addic %0, %0, 1", W) \ CK_PR_UNARY(dec, S, T, T, "addic %0, %0, -1", W) \ CK_PR_UNARY(not, S, T, T, "not %0, %0", W) \ CK_PR_UNARY(neg, S, T, T, "neg %0, %0", W) CK_PR_UNARY_S(64, uint64_t, "d") CK_PR_UNARY_S(32, uint32_t, "w") CK_PR_UNARY_S(uint, unsigned int, "w") CK_PR_UNARY_S(int, int, "w") #undef CK_PR_UNARY_S #undef CK_PR_UNARY #define CK_PR_BINARY(O, N, M, T, I, W) \ CK_CC_INLINE static void \ ck_pr_##O##_##N(M *target, T delta) \ { \ T previous; \ __asm__ __volatile__("1:" \ "l" W "arx %0, 0, %1;" \ I " %0, %2, %0;" \ "st" W "cx. %0, 0, %1;" \ "bne- 1b;" \ : "=&r" (previous) \ : "r" (target), \ "r" (delta) \ : "memory", "cc"); \ return; \ } CK_PR_BINARY(and, ptr, void, uintptr_t, "and", "d") CK_PR_BINARY(add, ptr, void, uintptr_t, "add", "d") CK_PR_BINARY(or, ptr, void, uintptr_t, "or", "d") CK_PR_BINARY(sub, ptr, void, uintptr_t, "sub", "d") CK_PR_BINARY(xor, ptr, void, uintptr_t, "xor", "d") #define CK_PR_BINARY_S(S, T, W) \ CK_PR_BINARY(and, S, T, T, "and", W) \ CK_PR_BINARY(add, S, T, T, "add", W) \ CK_PR_BINARY(or, S, T, T, "or", W) \ CK_PR_BINARY(sub, S, T, T, "subf", W) \ CK_PR_BINARY(xor, S, T, T, "xor", W) CK_PR_BINARY_S(64, uint64_t, "d") CK_PR_BINARY_S(32, uint32_t, "w") CK_PR_BINARY_S(uint, unsigned int, "w") CK_PR_BINARY_S(int, int, "w") #undef CK_PR_BINARY_S #undef CK_PR_BINARY CK_CC_INLINE static void * ck_pr_faa_ptr(void *target, uintptr_t delta) { uintptr_t previous, r; __asm__ __volatile__("1:" "ldarx %0, 0, %2;" "add %1, %3, %0;" "stdcx. %1, 0, %2;" "bne- 1b;" : "=&r" (previous), "=&r" (r) : "r" (target), "r" (delta) : "memory", "cc"); return (void *)(previous); } #define CK_PR_FAA(S, T, W) \ CK_CC_INLINE static T \ ck_pr_faa_##S(T *target, T delta) \ { \ T previous, r; \ __asm__ __volatile__("1:" \ "l" W "arx %0, 0, %2;" \ "add %1, %3, %0;" \ "st" W "cx. %1, 0, %2;" \ "bne- 1b;" \ : "=&r" (previous), \ "=&r" (r) \ : "r" (target), \ "r" (delta) \ : "memory", "cc"); \ return (previous); \ } CK_PR_FAA(64, uint64_t, "d") CK_PR_FAA(32, uint32_t, "w") CK_PR_FAA(uint, unsigned int, "w") CK_PR_FAA(int, int, "w") #undef CK_PR_FAA #endif /* CK_PR_PPC64_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/s390x/ck_f_pr.h ================================================ /* DO NOT EDIT. This is auto-generated from feature.sh */ #define CK_F_PR_ADD_32 #define CK_F_PR_ADD_64 #define CK_F_PR_ADD_INT #define CK_F_PR_ADD_PTR #define CK_F_PR_ADD_UINT #define CK_F_PR_AND_32 #define CK_F_PR_AND_64 #define CK_F_PR_AND_INT #define CK_F_PR_AND_PTR #define CK_F_PR_AND_UINT #define CK_F_PR_CAS_32 #define CK_F_PR_CAS_32_VALUE #define CK_F_PR_CAS_64 #define CK_F_PR_CAS_64_VALUE #define CK_F_PR_CAS_INT #define CK_F_PR_CAS_INT_VALUE #define CK_F_PR_CAS_PTR #define CK_F_PR_CAS_PTR_VALUE #define CK_F_PR_CAS_UINT #define CK_F_PR_CAS_UINT_VALUE #define CK_F_PR_DEC_32 #define CK_F_PR_DEC_64 #define CK_F_PR_DEC_INT #define CK_F_PR_DEC_PTR #define CK_F_PR_DEC_UINT #define CK_F_PR_FAA_32 #define CK_F_PR_FAA_64 #define CK_F_PR_FAA_INT #define CK_F_PR_FAA_PTR #define CK_F_PR_FAA_UINT #define CK_F_PR_FAS_32 #define CK_F_PR_FAS_64 #define CK_F_PR_FAS_INT #define CK_F_PR_FAS_PTR #define CK_F_PR_FAS_UINT #define CK_F_PR_FAS_DOUBLE #define CK_F_PR_FENCE_LOAD #define CK_F_PR_FENCE_LOAD_DEPENDS #define CK_F_PR_FENCE_MEMORY #define CK_F_PR_FENCE_STORE #define CK_F_PR_FENCE_STRICT_LOAD #define CK_F_PR_FENCE_STRICT_LOAD_DEPENDS #define CK_F_PR_FENCE_STRICT_MEMORY #define CK_F_PR_FENCE_STRICT_STORE #define CK_F_PR_INC_32 #define CK_F_PR_INC_64 #define CK_F_PR_INC_INT #define CK_F_PR_INC_PTR #define CK_F_PR_INC_UINT #define CK_F_PR_LOAD_16 #define CK_F_PR_LOAD_32 #define CK_F_PR_LOAD_64 #define CK_F_PR_LOAD_8 #define CK_F_PR_LOAD_CHAR #define CK_F_PR_LOAD_DOUBLE #define CK_F_PR_LOAD_INT #define CK_F_PR_LOAD_PTR #define CK_F_PR_LOAD_SHORT #define CK_F_PR_LOAD_UINT #define CK_F_PR_NEG_32 #define CK_F_PR_NEG_64 #define CK_F_PR_NEG_INT #define CK_F_PR_NEG_PTR #define CK_F_PR_NEG_UINT #define CK_F_PR_NOT_32 #define CK_F_PR_NOT_64 #define CK_F_PR_NOT_INT #define CK_F_PR_NOT_PTR #define CK_F_PR_NOT_UINT #define CK_F_PR_OR_32 #define CK_F_PR_OR_64 #define CK_F_PR_OR_INT #define CK_F_PR_OR_PTR #define CK_F_PR_OR_UINT #define CK_F_PR_STALL #define CK_F_PR_STORE_16 #define CK_F_PR_STORE_32 #define CK_F_PR_STORE_64 #define CK_F_PR_STORE_8 #define CK_F_PR_STORE_CHAR #define CK_F_PR_STORE_DOUBLE #define CK_F_PR_STORE_INT #define CK_F_PR_STORE_PTR #define CK_F_PR_STORE_SHORT #define CK_F_PR_STORE_UINT #define CK_F_PR_SUB_32 #define CK_F_PR_SUB_64 #define CK_F_PR_SUB_INT #define CK_F_PR_SUB_PTR #define CK_F_PR_SUB_UINT #define CK_F_PR_XOR_32 #define CK_F_PR_XOR_64 #define CK_F_PR_XOR_INT #define CK_F_PR_XOR_PTR #define CK_F_PR_XOR_UINT ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/s390x/ck_pr.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * Copyright 2017 Neale Ferguson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_S390X_H #define CK_PR_S390X_H #ifndef CK_PR_H #error Do not include this file directly, use ck_pr.h #endif #include #include /* * The following represent supported atomic operations. * These operations may be emulated. */ #include "ck_f_pr.h" /* * Minimum interface requirement met. */ #define CK_F_PR /* * This bounces the hardware thread from low to medium * priority. I am unsure of the benefits of this approach * but it is used by the Linux kernel. */ CK_CC_INLINE static void ck_pr_stall(void) { __sync_synchronize(); return; } #define CK_PR_FENCE(T) \ CK_CC_INLINE static void \ ck_pr_fence_strict_##T(void) \ { \ __sync_synchronize(); \ } /* * These are derived from: * http://www.ibm.com/developerworks/systems/articles/powerpc.html */ CK_PR_FENCE(atomic) CK_PR_FENCE(atomic_store) CK_PR_FENCE(atomic_load) CK_PR_FENCE(store_atomic) CK_PR_FENCE(load_atomic) CK_PR_FENCE(store) CK_PR_FENCE(store_load) CK_PR_FENCE(load) CK_PR_FENCE(load_store) CK_PR_FENCE(memory) CK_PR_FENCE(acquire) CK_PR_FENCE(release) CK_PR_FENCE(acqrel) CK_PR_FENCE(lock) CK_PR_FENCE(unlock) #undef CK_PR_FENCE #define CK_PR_LOAD(S, M, T, C, I) \ CK_CC_INLINE static T \ ck_pr_md_load_##S(const M *target) \ { \ T r; \ __asm__ __volatile__(I "\t%0, %1\n" \ : "=r" (r) \ : "Q" (*(const C *)target) \ : "memory"); \ return (r); \ } CK_PR_LOAD(ptr, void, void *, uint64_t, "lg") #define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) CK_PR_LOAD_S(64, uint64_t, "lg") CK_PR_LOAD_S(32, uint32_t, "llgf") CK_PR_LOAD_S(16, uint16_t, "llgh") CK_PR_LOAD_S(8, uint8_t, "llgc") CK_PR_LOAD_S(uint, unsigned int, "llgf") CK_PR_LOAD_S(int, int, "llgf") CK_PR_LOAD_S(short, short, "lgh") CK_PR_LOAD_S(char, char, "lgb") #ifndef CK_PR_DISABLE_DOUBLE CK_CC_INLINE static double ck_pr_md_load_double(const double *target) { double r; __asm__ __volatile__("ld %0, %1\n" : "=f" (r) : "Q" (*(const double *)target) : "memory"); return (r); } #endif #undef CK_PR_LOAD_S #undef CK_PR_LOAD #define CK_PR_STORE(S, M, T, C, I) \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ __asm__ __volatile__(I "\t%1, %0\n" \ : "=Q" (*(C *)target) \ : "r" (v) \ : "memory"); \ return; \ } CK_PR_STORE(ptr, void, const void *, uint64_t, "stg") #define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) CK_PR_STORE_S(64, uint64_t, "stg") CK_PR_STORE_S(32, uint32_t, "st") CK_PR_STORE_S(16, uint16_t, "sth") CK_PR_STORE_S(8, uint8_t, "stc") CK_PR_STORE_S(uint, unsigned int, "st") CK_PR_STORE_S(int, int, "st") CK_PR_STORE_S(short, short, "sth") CK_PR_STORE_S(char, char, "stc") #ifndef CK_PR_DISABLE_DOUBLE CK_CC_INLINE static void ck_pr_md_store_double(double *target, double v) { __asm__ __volatile__(" std %1, %0\n" : "=Q" (*(double *)target) : "f" (v) : "0", "memory"); } #endif #undef CK_PR_STORE_S #undef CK_PR_STORE CK_CC_INLINE static bool ck_pr_cas_64_value(uint64_t *target, uint64_t compare, uint64_t set, uint64_t *value) { *value = __sync_val_compare_and_swap(target,compare,set); return (*value == compare); } CK_CC_INLINE static bool ck_pr_cas_ptr_value(void *target, void *compare, void *set, void *value) { uintptr_t previous; previous = __sync_val_compare_and_swap((uintptr_t *) target, (uintptr_t) compare, (uintptr_t) set); *((uintptr_t *) value) = previous; return (previous == (uintptr_t) compare); } CK_CC_INLINE static bool ck_pr_cas_64(uint64_t *target, uint64_t compare, uint64_t set) { return(__sync_bool_compare_and_swap(target,compare,set)); } CK_CC_INLINE static bool ck_pr_cas_ptr(void *target, void *compare, void *set) { return(__sync_bool_compare_and_swap((uintptr_t *) target, (uintptr_t) compare, (uintptr_t) set)); } #define CK_PR_CAS(N, T) \ CK_CC_INLINE static bool \ ck_pr_cas_##N##_value(T *target, T compare, T set, T *value) \ { \ *value = __sync_val_compare_and_swap(target, \ compare, \ set); \ return(*value == compare); \ } \ CK_CC_INLINE static bool \ ck_pr_cas_##N(T *target, T compare, T set) \ { \ return(__sync_bool_compare_and_swap(target, \ compare, \ set)); \ } CK_PR_CAS(32, uint32_t) CK_PR_CAS(uint, unsigned int) CK_PR_CAS(int, int) #undef CK_PR_CAS CK_CC_INLINE static void * ck_pr_fas_ptr(void *target, void *v) { return((void *)__atomic_exchange_n((uintptr_t *) target, (uintptr_t) v, __ATOMIC_ACQUIRE)); } #define CK_PR_FAS(N, M, T) \ CK_CC_INLINE static T \ ck_pr_fas_##N(M *target, T v) \ { \ return(__atomic_exchange_n(target, v, __ATOMIC_ACQUIRE)); \ } CK_PR_FAS(64, uint64_t, uint64_t) CK_PR_FAS(32, uint32_t, uint32_t) CK_PR_FAS(int, int, int) CK_PR_FAS(uint, unsigned int, unsigned int) #ifndef CK_PR_DISABLE_DOUBLE CK_CC_INLINE static double ck_pr_fas_double(double *target, double *v) { double previous; __asm__ __volatile__ (" lg 1,%2\n" "0: lg 0,%1\n" " csg 0,1,%1\n" " jnz 0b\n" " ldgr %0,0\n" : "=f" (previous) : "Q" (target), "Q" (v) : "0", "1", "cc", "memory"); return (previous); } #endif #undef CK_PR_FAS /* * Atomic store-only binary operations. */ #define CK_PR_BINARY(K, S, M, T) \ CK_CC_INLINE static void \ ck_pr_##K##_##S(M *target, T d) \ { \ d = __sync_fetch_and_##K((T *)target, d); \ return; \ } #define CK_PR_BINARY_S(K, S, T) CK_PR_BINARY(K, S, T, T) #define CK_PR_GENERATE(K) \ CK_PR_BINARY(K, ptr, void, void *) \ CK_PR_BINARY_S(K, char, char) \ CK_PR_BINARY_S(K, int, int) \ CK_PR_BINARY_S(K, uint, unsigned int) \ CK_PR_BINARY_S(K, 64, uint64_t) \ CK_PR_BINARY_S(K, 32, uint32_t) \ CK_PR_BINARY_S(K, 16, uint16_t) \ CK_PR_BINARY_S(K, 8, uint8_t) CK_PR_GENERATE(add) CK_PR_GENERATE(sub) CK_PR_GENERATE(and) CK_PR_GENERATE(or) CK_PR_GENERATE(xor) #undef CK_PR_GENERATE #undef CK_PR_BINARY_S #undef CK_PR_BINARY #define CK_PR_UNARY(S, M, T) \ CK_CC_INLINE static void \ ck_pr_inc_##S(M *target) \ { \ ck_pr_add_##S(target, (T)1); \ return; \ } \ CK_CC_INLINE static void \ ck_pr_dec_##S(M *target) \ { \ ck_pr_sub_##S(target, (T)1); \ return; \ } #define CK_PR_UNARY_X(S, M) \ CK_CC_INLINE static void \ ck_pr_not_##S(M *target) \ { \ M newval; \ do { \ newval = ~(*target); \ } while (!__sync_bool_compare_and_swap(target, \ *target, \ newval)); \ } \ CK_CC_INLINE static void \ ck_pr_neg_##S(M *target) \ { \ M newval; \ do { \ newval = -(*target); \ } while (!__sync_bool_compare_and_swap(target, \ *target, \ newval)); \ } #define CK_PR_UNARY_S(S, M) CK_PR_UNARY(S, M, M) \ CK_PR_UNARY_X(S, M) CK_PR_UNARY(ptr, void, void *) CK_PR_UNARY_S(char, char) CK_PR_UNARY_S(int, int) CK_PR_UNARY_S(uint, unsigned int) CK_PR_UNARY_S(64, uint64_t) CK_PR_UNARY_S(32, uint32_t) CK_PR_UNARY_S(16, uint16_t) CK_PR_UNARY_S(8, uint8_t) #undef CK_PR_UNARY_S #undef CK_PR_UNARY CK_CC_INLINE static void * ck_pr_faa_ptr(void *target, uintptr_t delta) { uintptr_t previous; previous = __sync_fetch_and_add((uintptr_t *) target, delta); return (void *)(previous); } #define CK_PR_FAA(S, T) \ CK_CC_INLINE static T \ ck_pr_faa_##S(T *target, T delta) \ { \ T previous; \ \ previous = __sync_fetch_and_add(target, delta); \ \ return (previous); \ } CK_PR_FAA(64, uint64_t) CK_PR_FAA(32, uint32_t) CK_PR_FAA(uint, unsigned int) CK_PR_FAA(int, int) #undef CK_PR_FAA #endif /* CK_PR_S390X_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/sparcv9/ck_f_pr.h ================================================ #define CK_F_PR_CAS_64 #define CK_F_PR_CAS_64_VALUE #define CK_F_PR_CAS_PTR #define CK_F_PR_CAS_PTR_VALUE #define CK_F_PR_FAS_32 #define CK_F_PR_FAS_UINT #define CK_F_PR_FAS_INT #define CK_F_PR_CAS_32 #define CK_F_PR_CAS_32_VALUE #define CK_F_PR_CAS_UINT #define CK_F_PR_CAS_INT #define CK_F_PR_CAS_UINT_VALUE #define CK_F_PR_CAS_INT_VALUE #define CK_F_PR_STORE_64 #define CK_F_PR_STORE_32 #define CK_F_PR_STORE_DOUBLE #define CK_F_PR_STORE_UINT #define CK_F_PR_STORE_INT #define CK_F_PR_STORE_PTR #define CK_F_PR_LOAD_64 #define CK_F_PR_LOAD_32 #define CK_F_PR_LOAD_DOUBLE #define CK_F_PR_LOAD_UINT #define CK_F_PR_LOAD_INT #define CK_F_PR_LOAD_PTR ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/sparcv9/ck_pr.h ================================================ /* * Copyright 2009, 2010 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_SPARCV9_H #define CK_PR_SPARCV9_H #ifndef CK_PR_H #error Do not include this file directly, use ck_pr.h #endif #include #include /* * The following represent supported atomic operations. * These operations may be emulated. */ #include "ck_f_pr.h" /* * Minimum interface requirement met. */ #define CK_F_PR /* * Order loads at the least. */ CK_CC_INLINE static void ck_pr_stall(void) { __asm__ __volatile__("membar #LoadLoad" ::: "memory"); return; } #define CK_PR_FENCE(T, I) \ CK_CC_INLINE static void \ ck_pr_fence_strict_##T(void) \ { \ __asm__ __volatile__(I ::: "memory"); \ } /* * Atomic operations are treated as both load and store * operations on SPARCv9. */ CK_PR_FENCE(atomic, "membar #StoreStore") CK_PR_FENCE(atomic_store, "membar #StoreStore") CK_PR_FENCE(atomic_load, "membar #StoreLoad") CK_PR_FENCE(store_atomic, "membar #StoreStore") CK_PR_FENCE(load_atomic, "membar #LoadStore") CK_PR_FENCE(store, "membar #StoreStore") CK_PR_FENCE(store_load, "membar #StoreLoad") CK_PR_FENCE(load, "membar #LoadLoad") CK_PR_FENCE(load_store, "membar #LoadStore") CK_PR_FENCE(memory, "membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad") CK_PR_FENCE(acquire, "membar #LoadLoad | #LoadStore") CK_PR_FENCE(release, "membar #LoadStore | #StoreStore") CK_PR_FENCE(acqrel, "membar #LoadLoad | #LoadStore | #StoreStore") CK_PR_FENCE(lock, "membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad") CK_PR_FENCE(unlock, "membar #LoadStore | #StoreStore") #undef CK_PR_FENCE #define CK_PR_LOAD(S, M, T, C, I) \ CK_CC_INLINE static T \ ck_pr_md_load_##S(const M *target) \ { \ T r; \ __asm__ __volatile__(I " [%1], %0" \ : "=&r" (r) \ : "r" (target) \ : "memory"); \ return (r); \ } CK_PR_LOAD(ptr, void, void *, uint64_t, "ldx") #define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) CK_PR_LOAD_S(64, uint64_t, "ldx") CK_PR_LOAD_S(32, uint32_t, "lduw") CK_PR_LOAD_S(uint, unsigned int, "lduw") CK_PR_LOAD_S(double, double, "ldx") CK_PR_LOAD_S(int, int, "ldsw") #undef CK_PR_LOAD_S #undef CK_PR_LOAD #define CK_PR_STORE(S, M, T, C, I) \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ __asm__ __volatile__(I " %0, [%1]" \ : \ : "r" (v), \ "r" (target) \ : "memory"); \ return; \ } CK_PR_STORE(ptr, void, const void *, uint64_t, "stx") #define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) CK_PR_STORE_S(8, uint8_t, "stub") CK_PR_STORE_S(64, uint64_t, "stx") CK_PR_STORE_S(32, uint32_t, "stuw") CK_PR_STORE_S(uint, unsigned int, "stuw") CK_PR_STORE_S(double, double, "stx") CK_PR_STORE_S(int, int, "stsw") #undef CK_PR_STORE_S #undef CK_PR_STORE CK_CC_INLINE static bool ck_pr_cas_64_value(uint64_t *target, uint64_t compare, uint64_t set, uint64_t *value) { __asm__ __volatile__("casx [%1], %2, %0" : "+&r" (set) : "r" (target), "r" (compare) : "memory"); *value = set; return (compare == set); } CK_CC_INLINE static bool ck_pr_cas_64(uint64_t *target, uint64_t compare, uint64_t set) { __asm__ __volatile__("casx [%1], %2, %0" : "+&r" (set) : "r" (target), "r" (compare) : "memory"); return (compare == set); } CK_CC_INLINE static bool ck_pr_cas_ptr(void *target, void *compare, void *set) { return ck_pr_cas_64(target, (uint64_t)compare, (uint64_t)set); } CK_CC_INLINE static bool ck_pr_cas_ptr_value(void *target, void *compare, void *set, void *previous) { return ck_pr_cas_64_value(target, (uint64_t)compare, (uint64_t)set, previous); } #define CK_PR_CAS(N, T) \ CK_CC_INLINE static bool \ ck_pr_cas_##N##_value(T *target, T compare, T set, T *value) \ { \ __asm__ __volatile__("cas [%1], %2, %0" \ : "+&r" (set) \ : "r" (target), \ "r" (compare) \ : "memory"); \ *value = set; \ return (compare == set); \ } \ CK_CC_INLINE static bool \ ck_pr_cas_##N(T *target, T compare, T set) \ { \ __asm__ __volatile__("cas [%1], %2, %0" \ : "+&r" (set) \ : "r" (target), \ "r" (compare) \ : "memory"); \ return (compare == set); \ } CK_PR_CAS(32, uint32_t) CK_PR_CAS(uint, unsigned int) CK_PR_CAS(int, int) #undef CK_PR_CAS #define CK_PR_FAS(N, T) \ CK_CC_INLINE static T \ ck_pr_fas_##N(T *target, T update) \ { \ \ __asm__ __volatile__("swap [%1], %0" \ : "+&r" (update) \ : "r" (target) \ : "memory"); \ return (update); \ } CK_PR_FAS(int, int) CK_PR_FAS(uint, unsigned int) CK_PR_FAS(32, uint32_t) #undef CK_PR_FAS #endif /* CK_PR_SPARCV9_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/x86/ck_f_pr.h ================================================ /* DO NOT EDIT. This is auto-generated from feature.sh */ #define CK_F_PR_ADD_16 #define CK_F_PR_ADD_32 #define CK_F_PR_ADD_8 #define CK_F_PR_ADD_CHAR #define CK_F_PR_ADD_INT #define CK_F_PR_ADD_PTR #define CK_F_PR_ADD_UINT #define CK_F_PR_AND_16 #define CK_F_PR_AND_32 #define CK_F_PR_AND_8 #define CK_F_PR_AND_CHAR #define CK_F_PR_AND_INT #define CK_F_PR_AND_PTR #define CK_F_PR_AND_UINT #define CK_F_PR_BTC_16 #define CK_F_PR_BTC_32 #define CK_F_PR_BTC_INT #define CK_F_PR_BTC_PTR #define CK_F_PR_BTC_UINT #define CK_F_PR_BTR_16 #define CK_F_PR_BTR_32 #define CK_F_PR_BTR_INT #define CK_F_PR_BTR_PTR #define CK_F_PR_BTR_UINT #define CK_F_PR_BTS_16 #define CK_F_PR_BTS_32 #define CK_F_PR_BTS_INT #define CK_F_PR_BTS_PTR #define CK_F_PR_BTS_UINT #define CK_F_PR_CAS_16 #define CK_F_PR_CAS_16_VALUE #define CK_F_PR_CAS_32 #define CK_F_PR_CAS_32_VALUE #define CK_F_PR_CAS_8 #define CK_F_PR_CAS_8_VALUE #define CK_F_PR_CAS_CHAR #define CK_F_PR_CAS_CHAR_VALUE #define CK_F_PR_CAS_INT #define CK_F_PR_CAS_INT_VALUE #define CK_F_PR_CAS_PTR #define CK_F_PR_CAS_PTR_VALUE #define CK_F_PR_CAS_UINT #define CK_F_PR_CAS_UINT_VALUE #define CK_F_PR_DEC_16 #define CK_F_PR_DEC_16_ZERO #define CK_F_PR_DEC_32 #define CK_F_PR_DEC_32_ZERO #define CK_F_PR_DEC_8 #define CK_F_PR_DEC_8_ZERO #define CK_F_PR_DEC_CHAR #define CK_F_PR_DEC_CHAR_ZERO #define CK_F_PR_DEC_INT #define CK_F_PR_DEC_INT_ZERO #define CK_F_PR_DEC_PTR #define CK_F_PR_DEC_PTR_ZERO #define CK_F_PR_DEC_UINT #define CK_F_PR_DEC_UINT_ZERO #define CK_F_PR_FAA_16 #define CK_F_PR_FAA_32 #define CK_F_PR_FAA_8 #define CK_F_PR_FAA_CHAR #define CK_F_PR_FAA_INT #define CK_F_PR_FAA_PTR #define CK_F_PR_FAA_UINT #define CK_F_PR_FAS_16 #define CK_F_PR_FAS_32 #define CK_F_PR_FAS_8 #define CK_F_PR_FAS_CHAR #define CK_F_PR_FAS_INT #define CK_F_PR_FAS_PTR #define CK_F_PR_FAS_UINT #define CK_F_PR_FENCE_LOAD #define CK_F_PR_FENCE_LOAD_DEPENDS #define CK_F_PR_FENCE_MEMORY #define CK_F_PR_FENCE_STORE #define CK_F_PR_FENCE_STRICT_LOAD #define CK_F_PR_FENCE_STRICT_LOAD_DEPENDS #define CK_F_PR_FENCE_STRICT_MEMORY #define CK_F_PR_FENCE_STRICT_STORE #define CK_F_PR_INC_16 #define CK_F_PR_INC_16_ZERO #define CK_F_PR_INC_32 #define CK_F_PR_INC_32_ZERO #define CK_F_PR_INC_8 #define CK_F_PR_INC_8_ZERO #define CK_F_PR_INC_CHAR #define CK_F_PR_INC_CHAR_ZERO #define CK_F_PR_INC_INT #define CK_F_PR_INC_INT_ZERO #define CK_F_PR_INC_PTR #define CK_F_PR_INC_PTR_ZERO #define CK_F_PR_INC_UINT #define CK_F_PR_INC_UINT_ZERO #define CK_F_PR_LOAD_16 #define CK_F_PR_LOAD_32 #define CK_F_PR_LOAD_8 #define CK_F_PR_LOAD_CHAR #define CK_F_PR_LOAD_INT #define CK_F_PR_LOAD_PTR #define CK_F_PR_LOAD_UINT #define CK_F_PR_NEG_16 #define CK_F_PR_NEG_16_ZERO #define CK_F_PR_NEG_32 #define CK_F_PR_NEG_32_ZERO #define CK_F_PR_NEG_8 #define CK_F_PR_NEG_8_ZERO #define CK_F_PR_NEG_CHAR #define CK_F_PR_NEG_CHAR_ZERO #define CK_F_PR_NEG_INT #define CK_F_PR_NEG_INT_ZERO #define CK_F_PR_NEG_PTR #define CK_F_PR_NEG_PTR_ZERO #define CK_F_PR_NEG_UINT #define CK_F_PR_NEG_UINT_ZERO #define CK_F_PR_NOT_16 #define CK_F_PR_NOT_32 #define CK_F_PR_NOT_8 #define CK_F_PR_NOT_CHAR #define CK_F_PR_NOT_INT #define CK_F_PR_NOT_PTR #define CK_F_PR_NOT_UINT #define CK_F_PR_OR_16 #define CK_F_PR_OR_32 #define CK_F_PR_OR_8 #define CK_F_PR_OR_CHAR #define CK_F_PR_OR_INT #define CK_F_PR_OR_PTR #define CK_F_PR_OR_UINT #define CK_F_PR_STALL #define CK_F_PR_STORE_16 #define CK_F_PR_STORE_32 #define CK_F_PR_STORE_8 #define CK_F_PR_STORE_CHAR #define CK_F_PR_STORE_INT #define CK_F_PR_STORE_PTR #define CK_F_PR_STORE_UINT #define CK_F_PR_SUB_16 #define CK_F_PR_SUB_32 #define CK_F_PR_SUB_8 #define CK_F_PR_SUB_CHAR #define CK_F_PR_SUB_INT #define CK_F_PR_SUB_PTR #define CK_F_PR_SUB_UINT #define CK_F_PR_XOR_16 #define CK_F_PR_XOR_32 #define CK_F_PR_XOR_8 #define CK_F_PR_XOR_CHAR #define CK_F_PR_XOR_INT #define CK_F_PR_XOR_PTR #define CK_F_PR_XOR_UINT ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/x86/ck_pr.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * Copyright 2011 Devon H. O'Dell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_X86_H #define CK_PR_X86_H #ifndef CK_PR_H #error Do not include this file directly, use ck_pr.h #endif #include #include #include /* * The following represent supported atomic operations. * These operations may be emulated. */ #include "ck_f_pr.h" /* Minimum requirements for the CK_PR interface are met. */ #define CK_F_PR #ifdef CK_MD_UMP #define CK_PR_LOCK_PREFIX #else #define CK_PR_LOCK_PREFIX "lock " #endif /* * Prevent speculative execution in busy-wait loops (P4 <=) * or "predefined delay". */ CK_CC_INLINE static void ck_pr_stall(void) { __asm__ __volatile__("pause" ::: "memory"); return; } #define CK_PR_FENCE(T, I) \ CK_CC_INLINE static void \ ck_pr_fence_strict_##T(void) \ { \ __asm__ __volatile__(I ::: "memory"); \ } CK_PR_FENCE(atomic, "sfence") CK_PR_FENCE(atomic_store, "sfence") CK_PR_FENCE(atomic_load, "mfence") CK_PR_FENCE(store_atomic, "sfence") CK_PR_FENCE(load_atomic, "mfence") CK_PR_FENCE(load, "lfence") CK_PR_FENCE(load_store, "mfence") CK_PR_FENCE(store, "sfence") CK_PR_FENCE(store_load, "mfence") CK_PR_FENCE(memory, "mfence") CK_PR_FENCE(release, "mfence") CK_PR_FENCE(acquire, "mfence") CK_PR_FENCE(acqrel, "mfence") CK_PR_FENCE(lock, "mfence") CK_PR_FENCE(unlock, "mfence") #undef CK_PR_FENCE /* * Atomic fetch-and-store operations. */ #define CK_PR_FAS(S, M, T, C, I) \ CK_CC_INLINE static T \ ck_pr_fas_##S(M *target, T v) \ { \ __asm__ __volatile__(I " %0, %1" \ : "+m" (*(C *)target), \ "+q" (v) \ : \ : "memory"); \ return v; \ } CK_PR_FAS(ptr, void, void *, char, "xchgl") #define CK_PR_FAS_S(S, T, I) CK_PR_FAS(S, T, T, T, I) CK_PR_FAS_S(char, char, "xchgb") CK_PR_FAS_S(uint, unsigned int, "xchgl") CK_PR_FAS_S(int, int, "xchgl") CK_PR_FAS_S(32, uint32_t, "xchgl") CK_PR_FAS_S(16, uint16_t, "xchgw") CK_PR_FAS_S(8, uint8_t, "xchgb") #undef CK_PR_FAS_S #undef CK_PR_FAS #define CK_PR_LOAD(S, M, T, C, I) \ CK_CC_INLINE static T \ ck_pr_md_load_##S(const M *target) \ { \ T r; \ __asm__ __volatile__(I " %1, %0" \ : "=q" (r) \ : "m" (*(const C *)target) \ : "memory"); \ return (r); \ } CK_PR_LOAD(ptr, void, void *, char, "movl") #define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) CK_PR_LOAD_S(char, char, "movb") CK_PR_LOAD_S(uint, unsigned int, "movl") CK_PR_LOAD_S(int, int, "movl") CK_PR_LOAD_S(32, uint32_t, "movl") CK_PR_LOAD_S(16, uint16_t, "movw") CK_PR_LOAD_S(8, uint8_t, "movb") #undef CK_PR_LOAD_S #undef CK_PR_LOAD #define CK_PR_STORE(S, M, T, C, I) \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ __asm__ __volatile__(I " %1, %0" \ : "=m" (*(C *)target) \ : CK_CC_IMM "q" (v) \ : "memory"); \ return; \ } CK_PR_STORE(ptr, void, const void *, char, "movl") #define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) CK_PR_STORE_S(char, char, "movb") CK_PR_STORE_S(uint, unsigned int, "movl") CK_PR_STORE_S(int, int, "movl") CK_PR_STORE_S(32, uint32_t, "movl") CK_PR_STORE_S(16, uint16_t, "movw") CK_PR_STORE_S(8, uint8_t, "movb") #undef CK_PR_STORE_S #undef CK_PR_STORE /* * Atomic fetch-and-add operations. */ #define CK_PR_FAA(S, M, T, C, I) \ CK_CC_INLINE static T \ ck_pr_faa_##S(M *target, T d) \ { \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0" \ : "+m" (*(C *)target), \ "+q" (d) \ : \ : "memory", "cc"); \ return (d); \ } CK_PR_FAA(ptr, void, uintptr_t, char, "xaddl") #define CK_PR_FAA_S(S, T, I) CK_PR_FAA(S, T, T, T, I) CK_PR_FAA_S(char, char, "xaddb") CK_PR_FAA_S(uint, unsigned int, "xaddl") CK_PR_FAA_S(int, int, "xaddl") CK_PR_FAA_S(32, uint32_t, "xaddl") CK_PR_FAA_S(16, uint16_t, "xaddw") CK_PR_FAA_S(8, uint8_t, "xaddb") #undef CK_PR_FAA_S #undef CK_PR_FAA /* * Atomic store-only unary operations. */ #define CK_PR_UNARY(K, S, T, C, I) \ CK_PR_UNARY_R(K, S, T, C, I) \ CK_PR_UNARY_V(K, S, T, C, I) #define CK_PR_UNARY_R(K, S, T, C, I) \ CK_CC_INLINE static void \ ck_pr_##K##_##S(T *target) \ { \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0" \ : "+m" (*(C *)target) \ : \ : "memory", "cc"); \ return; \ } #define CK_PR_UNARY_V(K, S, T, C, I) \ CK_CC_INLINE static void \ ck_pr_##K##_##S##_zero(T *target, bool *r) \ { \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0; setz %1" \ : "+m" (*(C *)target), \ "=m" (*r) \ : \ : "memory", "cc"); \ return; \ } #define CK_PR_UNARY_S(K, S, T, I) CK_PR_UNARY(K, S, T, T, I) #define CK_PR_GENERATE(K) \ CK_PR_UNARY(K, ptr, void, char, #K "l") \ CK_PR_UNARY_S(K, char, char, #K "b") \ CK_PR_UNARY_S(K, int, int, #K "l") \ CK_PR_UNARY_S(K, uint, unsigned int, #K "l") \ CK_PR_UNARY_S(K, 32, uint32_t, #K "l") \ CK_PR_UNARY_S(K, 16, uint16_t, #K "w") \ CK_PR_UNARY_S(K, 8, uint8_t, #K "b") CK_PR_GENERATE(inc) CK_PR_GENERATE(dec) CK_PR_GENERATE(neg) /* not does not affect condition flags. */ #undef CK_PR_UNARY_V #define CK_PR_UNARY_V(a, b, c, d, e) CK_PR_GENERATE(not) #undef CK_PR_GENERATE #undef CK_PR_UNARY_S #undef CK_PR_UNARY_V #undef CK_PR_UNARY_R #undef CK_PR_UNARY /* * Atomic store-only binary operations. */ #define CK_PR_BINARY(K, S, M, T, C, I) \ CK_CC_INLINE static void \ ck_pr_##K##_##S(M *target, T d) \ { \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0" \ : "+m" (*(C *)target) \ : CK_CC_IMM "q" (d) \ : "memory", "cc"); \ return; \ } #define CK_PR_BINARY_S(K, S, T, I) CK_PR_BINARY(K, S, T, T, T, I) #define CK_PR_GENERATE(K) \ CK_PR_BINARY(K, ptr, void, uintptr_t, char, #K "l") \ CK_PR_BINARY_S(K, char, char, #K "b") \ CK_PR_BINARY_S(K, int, int, #K "l") \ CK_PR_BINARY_S(K, uint, unsigned int, #K "l") \ CK_PR_BINARY_S(K, 32, uint32_t, #K "l") \ CK_PR_BINARY_S(K, 16, uint16_t, #K "w") \ CK_PR_BINARY_S(K, 8, uint8_t, #K "b") CK_PR_GENERATE(add) CK_PR_GENERATE(sub) CK_PR_GENERATE(and) CK_PR_GENERATE(or) CK_PR_GENERATE(xor) #undef CK_PR_GENERATE #undef CK_PR_BINARY_S #undef CK_PR_BINARY /* * Atomic compare and swap. */ #define CK_PR_CAS(S, M, T, C, I) \ CK_CC_INLINE static bool \ ck_pr_cas_##S(M *target, T compare, T set) \ { \ bool z; \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %2, %0; setz %1" \ : "+m" (*(C *)target), \ "=a" (z) \ : "q" (set), \ "a" (compare) \ : "memory", "cc"); \ return z; \ } CK_PR_CAS(ptr, void, void *, char, "cmpxchgl") #define CK_PR_CAS_S(S, T, I) CK_PR_CAS(S, T, T, T, I) CK_PR_CAS_S(char, char, "cmpxchgb") CK_PR_CAS_S(int, int, "cmpxchgl") CK_PR_CAS_S(uint, unsigned int, "cmpxchgl") CK_PR_CAS_S(32, uint32_t, "cmpxchgl") CK_PR_CAS_S(16, uint16_t, "cmpxchgw") CK_PR_CAS_S(8, uint8_t, "cmpxchgb") #undef CK_PR_CAS_S #undef CK_PR_CAS /* * Compare and swap, set *v to old value of target. */ #define CK_PR_CAS_O(S, M, T, C, I, R) \ CK_CC_INLINE static bool \ ck_pr_cas_##S##_value(M *target, T compare, T set, M *v) \ { \ bool z; \ __asm__ __volatile__(CK_PR_LOCK_PREFIX "cmpxchg" I " %3, %0;" \ "mov %% " R ", %2;" \ "setz %1;" \ : "+m" (*(C *)target), \ "=a" (z), \ "=m" (*(C *)v) \ : "q" (set), \ "a" (compare) \ : "memory", "cc"); \ return (bool)z; \ } CK_PR_CAS_O(ptr, void, void *, char, "l", "eax") #define CK_PR_CAS_O_S(S, T, I, R) \ CK_PR_CAS_O(S, T, T, T, I, R) CK_PR_CAS_O_S(char, char, "b", "al") CK_PR_CAS_O_S(int, int, "l", "eax") CK_PR_CAS_O_S(uint, unsigned int, "l", "eax") CK_PR_CAS_O_S(32, uint32_t, "l", "eax") CK_PR_CAS_O_S(16, uint16_t, "w", "ax") CK_PR_CAS_O_S(8, uint8_t, "b", "al") #undef CK_PR_CAS_O_S #undef CK_PR_CAS_O /* * Atomic bit test operations. */ #define CK_PR_BT(K, S, T, P, C, I) \ CK_CC_INLINE static bool \ ck_pr_##K##_##S(T *target, unsigned int b) \ { \ bool c; \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I "; setc %1" \ : "+m" (*(C *)target), \ "=q" (c) \ : "q" ((P)b) \ : "memory", "cc"); \ return (bool)c; \ } #define CK_PR_BT_S(K, S, T, I) CK_PR_BT(K, S, T, T, T, I) #define CK_PR_GENERATE(K) \ CK_PR_BT(K, ptr, void, uint32_t, char, #K "l %2, %0") \ CK_PR_BT_S(K, uint, unsigned int, #K "l %2, %0") \ CK_PR_BT_S(K, int, int, #K "l %2, %0") \ CK_PR_BT_S(K, 32, uint32_t, #K "l %2, %0") \ CK_PR_BT_S(K, 16, uint16_t, #K "w %w2, %0") CK_PR_GENERATE(btc) CK_PR_GENERATE(bts) CK_PR_GENERATE(btr) #undef CK_PR_GENERATE #undef CK_PR_BT #endif /* CK_PR_X86_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/x86_64/ck_f_pr.h ================================================ /* DO NOT EDIT. This is auto-generated from feature.sh */ #define CK_F_PR_ADD_16 #define CK_F_PR_ADD_32 #define CK_F_PR_ADD_64 #define CK_F_PR_ADD_8 #define CK_F_PR_ADD_CHAR #define CK_F_PR_ADD_INT #define CK_F_PR_ADD_PTR #define CK_F_PR_ADD_UINT #define CK_F_PR_AND_16 #define CK_F_PR_AND_32 #define CK_F_PR_AND_64 #define CK_F_PR_AND_8 #define CK_F_PR_AND_CHAR #define CK_F_PR_AND_INT #define CK_F_PR_AND_PTR #define CK_F_PR_AND_UINT #define CK_F_PR_BTC_16 #define CK_F_PR_BTC_32 #define CK_F_PR_BTC_64 #define CK_F_PR_BTC_INT #define CK_F_PR_BTC_PTR #define CK_F_PR_BTC_UINT #define CK_F_PR_BTR_16 #define CK_F_PR_BTR_32 #define CK_F_PR_BTR_64 #define CK_F_PR_BTR_INT #define CK_F_PR_BTR_PTR #define CK_F_PR_BTR_UINT #define CK_F_PR_BTS_16 #define CK_F_PR_BTS_32 #define CK_F_PR_BTS_64 #define CK_F_PR_BTS_INT #define CK_F_PR_BTS_PTR #define CK_F_PR_BTS_UINT #define CK_F_PR_CAS_16 #define CK_F_PR_CAS_16_8 #define CK_F_PR_CAS_16_8_VALUE #define CK_F_PR_CAS_16_VALUE #define CK_F_PR_CAS_32 #define CK_F_PR_CAS_32_4 #define CK_F_PR_CAS_32_4_VALUE #define CK_F_PR_CAS_32_VALUE #define CK_F_PR_CAS_64 #define CK_F_PR_CAS_64_2 #define CK_F_PR_CAS_64_2_VALUE #define CK_F_PR_CAS_64_VALUE #define CK_F_PR_CAS_8 #define CK_F_PR_CAS_8_16 #define CK_F_PR_CAS_8_16_VALUE #define CK_F_PR_CAS_8_VALUE #define CK_F_PR_CAS_CHAR #define CK_F_PR_CAS_CHAR_16 #define CK_F_PR_CAS_CHAR_16_VALUE #define CK_F_PR_CAS_CHAR_VALUE #define CK_F_PR_CAS_INT #define CK_F_PR_CAS_INT_4 #define CK_F_PR_CAS_INT_4_VALUE #define CK_F_PR_CAS_INT_VALUE #define CK_F_PR_CAS_PTR #define CK_F_PR_CAS_PTR_2 #define CK_F_PR_CAS_PTR_2_VALUE #define CK_F_PR_CAS_PTR_VALUE #define CK_F_PR_CAS_DOUBLE #define CK_F_PR_CAS_DOUBLE_2 #define CK_F_PR_CAS_DOUBLE_VALUE #define CK_F_PR_CAS_UINT #define CK_F_PR_CAS_UINT_4 #define CK_F_PR_CAS_UINT_4_VALUE #define CK_F_PR_CAS_UINT_VALUE #define CK_F_PR_DEC_16 #define CK_F_PR_DEC_16_ZERO #define CK_F_PR_DEC_32 #define CK_F_PR_DEC_32_ZERO #define CK_F_PR_DEC_64 #define CK_F_PR_DEC_64_ZERO #define CK_F_PR_DEC_8 #define CK_F_PR_DEC_8_ZERO #define CK_F_PR_DEC_CHAR #define CK_F_PR_DEC_CHAR_ZERO #define CK_F_PR_DEC_INT #define CK_F_PR_DEC_INT_ZERO #define CK_F_PR_DEC_PTR #define CK_F_PR_DEC_PTR_ZERO #define CK_F_PR_DEC_UINT #define CK_F_PR_DEC_UINT_ZERO #define CK_F_PR_FAA_16 #define CK_F_PR_FAA_32 #define CK_F_PR_FAA_64 #define CK_F_PR_FAA_8 #define CK_F_PR_FAA_CHAR #define CK_F_PR_FAA_INT #define CK_F_PR_FAA_PTR #define CK_F_PR_FAA_UINT #define CK_F_PR_FAS_16 #define CK_F_PR_FAS_32 #define CK_F_PR_FAS_64 #define CK_F_PR_FAS_8 #define CK_F_PR_FAS_CHAR #define CK_F_PR_FAS_INT #define CK_F_PR_FAS_PTR #define CK_F_PR_FAS_UINT #define CK_F_PR_FAS_DOUBLE #define CK_F_PR_FENCE_LOAD #define CK_F_PR_FENCE_LOAD_DEPENDS #define CK_F_PR_FENCE_MEMORY #define CK_F_PR_FENCE_STORE #define CK_F_PR_FENCE_STRICT_LOAD #define CK_F_PR_FENCE_STRICT_LOAD_DEPENDS #define CK_F_PR_FENCE_STRICT_MEMORY #define CK_F_PR_FENCE_STRICT_STORE #define CK_F_PR_INC_16 #define CK_F_PR_INC_16_ZERO #define CK_F_PR_INC_32 #define CK_F_PR_INC_32_ZERO #define CK_F_PR_INC_64 #define CK_F_PR_INC_64_ZERO #define CK_F_PR_INC_8 #define CK_F_PR_INC_8_ZERO #define CK_F_PR_INC_CHAR #define CK_F_PR_INC_CHAR_ZERO #define CK_F_PR_INC_INT #define CK_F_PR_INC_INT_ZERO #define CK_F_PR_INC_PTR #define CK_F_PR_INC_PTR_ZERO #define CK_F_PR_INC_UINT #define CK_F_PR_INC_UINT_ZERO #define CK_F_PR_LOAD_16 #define CK_F_PR_LOAD_16_8 #define CK_F_PR_LOAD_32 #define CK_F_PR_LOAD_32_4 #define CK_F_PR_LOAD_64 #define CK_F_PR_LOAD_64_2 #define CK_F_PR_LOAD_8 #define CK_F_PR_LOAD_8_16 #define CK_F_PR_LOAD_CHAR #define CK_F_PR_LOAD_CHAR_16 #define CK_F_PR_LOAD_INT #define CK_F_PR_LOAD_INT_4 #define CK_F_PR_LOAD_PTR #define CK_F_PR_LOAD_PTR_2 #define CK_F_PR_LOAD_DOUBLE #define CK_F_PR_LOAD_UINT #define CK_F_PR_LOAD_UINT_4 #define CK_F_PR_NEG_16 #define CK_F_PR_NEG_16_ZERO #define CK_F_PR_NEG_32 #define CK_F_PR_NEG_32_ZERO #define CK_F_PR_NEG_64 #define CK_F_PR_NEG_64_ZERO #define CK_F_PR_NEG_8 #define CK_F_PR_NEG_8_ZERO #define CK_F_PR_NEG_CHAR #define CK_F_PR_NEG_CHAR_ZERO #define CK_F_PR_NEG_INT #define CK_F_PR_NEG_INT_ZERO #define CK_F_PR_NEG_PTR #define CK_F_PR_NEG_PTR_ZERO #define CK_F_PR_NEG_UINT #define CK_F_PR_NEG_UINT_ZERO #define CK_F_PR_NOT_16 #define CK_F_PR_NOT_32 #define CK_F_PR_NOT_64 #define CK_F_PR_NOT_8 #define CK_F_PR_NOT_CHAR #define CK_F_PR_NOT_INT #define CK_F_PR_NOT_PTR #define CK_F_PR_NOT_UINT #define CK_F_PR_OR_16 #define CK_F_PR_OR_32 #define CK_F_PR_OR_64 #define CK_F_PR_OR_8 #define CK_F_PR_OR_CHAR #define CK_F_PR_OR_INT #define CK_F_PR_OR_PTR #define CK_F_PR_OR_UINT #define CK_F_PR_STORE_16 #define CK_F_PR_STORE_32 #define CK_F_PR_STORE_64 #define CK_F_PR_STORE_8 #define CK_F_PR_STORE_CHAR #define CK_F_PR_STORE_INT #define CK_F_PR_STORE_DOUBLE #define CK_F_PR_STORE_PTR #define CK_F_PR_STORE_UINT #define CK_F_PR_SUB_16 #define CK_F_PR_SUB_32 #define CK_F_PR_SUB_64 #define CK_F_PR_SUB_8 #define CK_F_PR_SUB_CHAR #define CK_F_PR_SUB_INT #define CK_F_PR_SUB_PTR #define CK_F_PR_SUB_UINT #define CK_F_PR_XOR_16 #define CK_F_PR_XOR_32 #define CK_F_PR_XOR_64 #define CK_F_PR_XOR_8 #define CK_F_PR_XOR_CHAR #define CK_F_PR_XOR_INT #define CK_F_PR_XOR_PTR #define CK_F_PR_XOR_UINT ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/x86_64/ck_pr.h ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_PR_X86_64_H #define CK_PR_X86_64_H #ifndef CK_PR_H #error Do not include this file directly, use ck_pr.h #endif #include #include #include /* * The following represent supported atomic operations. * These operations may be emulated. */ #include "ck_f_pr.h" /* * Support for TSX extensions. */ #ifdef CK_MD_RTM_ENABLE #include "ck_pr_rtm.h" #endif /* Minimum requirements for the CK_PR interface are met. */ #define CK_F_PR #ifdef CK_MD_UMP #define CK_PR_LOCK_PREFIX #else #define CK_PR_LOCK_PREFIX "lock " #endif /* * Prevent speculative execution in busy-wait loops (P4 <=) * or "predefined delay". */ CK_CC_INLINE static void ck_pr_stall(void) { __asm__ __volatile__("pause" ::: "memory"); return; } #define CK_PR_FENCE(T, I) \ CK_CC_INLINE static void \ ck_pr_fence_strict_##T(void) \ { \ __asm__ __volatile__(I ::: "memory"); \ } CK_PR_FENCE(atomic, "sfence") CK_PR_FENCE(atomic_store, "sfence") CK_PR_FENCE(atomic_load, "mfence") CK_PR_FENCE(store_atomic, "sfence") CK_PR_FENCE(load_atomic, "mfence") CK_PR_FENCE(load, "lfence") CK_PR_FENCE(load_store, "mfence") CK_PR_FENCE(store, "sfence") CK_PR_FENCE(store_load, "mfence") CK_PR_FENCE(memory, "mfence") CK_PR_FENCE(release, "mfence") CK_PR_FENCE(acquire, "mfence") CK_PR_FENCE(acqrel, "mfence") CK_PR_FENCE(lock, "mfence") CK_PR_FENCE(unlock, "mfence") #undef CK_PR_FENCE /* * Read for ownership. Older compilers will generate the 32-bit * 3DNow! variant which is binary compatible with x86-64 variant * of prefetchw. */ #ifndef CK_F_PR_RFO #define CK_F_PR_RFO CK_CC_INLINE static void ck_pr_rfo(const void *m) { __asm__ __volatile__("prefetchw (%0)" : : "r" (m) : "memory"); return; } #endif /* CK_F_PR_RFO */ /* * Atomic fetch-and-store operations. */ #define CK_PR_FAS(S, M, T, C, I) \ CK_CC_INLINE static T \ ck_pr_fas_##S(M *target, T v) \ { \ __asm__ __volatile__(I " %0, %1" \ : "+m" (*(C *)target), \ "+q" (v) \ : \ : "memory"); \ return v; \ } CK_PR_FAS(ptr, void, void *, char, "xchgq") #define CK_PR_FAS_S(S, T, I) CK_PR_FAS(S, T, T, T, I) #ifndef CK_PR_DISABLE_DOUBLE CK_PR_FAS_S(double, double, "xchgq") #endif CK_PR_FAS_S(char, char, "xchgb") CK_PR_FAS_S(uint, unsigned int, "xchgl") CK_PR_FAS_S(int, int, "xchgl") CK_PR_FAS_S(64, uint64_t, "xchgq") CK_PR_FAS_S(32, uint32_t, "xchgl") CK_PR_FAS_S(16, uint16_t, "xchgw") CK_PR_FAS_S(8, uint8_t, "xchgb") #undef CK_PR_FAS_S #undef CK_PR_FAS /* * Atomic load-from-memory operations. */ #define CK_PR_LOAD(S, M, T, C, I) \ CK_CC_INLINE static T \ ck_pr_md_load_##S(const M *target) \ { \ T r; \ __asm__ __volatile__(I " %1, %0" \ : "=q" (r) \ : "m" (*(const C *)target) \ : "memory"); \ return (r); \ } CK_PR_LOAD(ptr, void, void *, char, "movq") #define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) CK_PR_LOAD_S(char, char, "movb") CK_PR_LOAD_S(uint, unsigned int, "movl") CK_PR_LOAD_S(int, int, "movl") #ifndef CK_PR_DISABLE_DOUBLE CK_PR_LOAD_S(double, double, "movq") #endif CK_PR_LOAD_S(64, uint64_t, "movq") CK_PR_LOAD_S(32, uint32_t, "movl") CK_PR_LOAD_S(16, uint16_t, "movw") CK_PR_LOAD_S(8, uint8_t, "movb") #undef CK_PR_LOAD_S #undef CK_PR_LOAD CK_CC_INLINE static void ck_pr_load_64_2(const uint64_t target[2], uint64_t v[2]) { __asm__ __volatile__("movq %%rdx, %%rcx;" "movq %%rax, %%rbx;" CK_PR_LOCK_PREFIX "cmpxchg16b %2;" : "=a" (v[0]), "=d" (v[1]) : "m" (*(const uint64_t *)target) : "rbx", "rcx", "memory", "cc"); return; } CK_CC_INLINE static void ck_pr_load_ptr_2(const void *t, void *v) { ck_pr_load_64_2(CK_CPP_CAST(const uint64_t *, t), CK_CPP_CAST(uint64_t *, v)); return; } #define CK_PR_LOAD_2(S, W, T) \ CK_CC_INLINE static void \ ck_pr_md_load_##S##_##W(const T t[2], T v[2]) \ { \ ck_pr_load_64_2((const uint64_t *)(const void *)t, \ (uint64_t *)(void *)v); \ return; \ } CK_PR_LOAD_2(char, 16, char) CK_PR_LOAD_2(int, 4, int) CK_PR_LOAD_2(uint, 4, unsigned int) CK_PR_LOAD_2(32, 4, uint32_t) CK_PR_LOAD_2(16, 8, uint16_t) CK_PR_LOAD_2(8, 16, uint8_t) #undef CK_PR_LOAD_2 /* * Atomic store-to-memory operations. */ #define CK_PR_STORE_IMM(S, M, T, C, I, K) \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ __asm__ __volatile__(I " %1, %0" \ : "=m" (*(C *)target) \ : K "q" (v) \ : "memory"); \ return; \ } #define CK_PR_STORE(S, M, T, C, I) \ CK_CC_INLINE static void \ ck_pr_md_store_##S(M *target, T v) \ { \ __asm__ __volatile__(I " %1, %0" \ : "=m" (*(C *)target) \ : "q" (v) \ : "memory"); \ return; \ } CK_PR_STORE_IMM(ptr, void, const void *, char, "movq", CK_CC_IMM_U32) #ifndef CK_PR_DISABLE_DOUBLE CK_PR_STORE(double, double, double, double, "movq") #endif #define CK_PR_STORE_S(S, T, I, K) CK_PR_STORE_IMM(S, T, T, T, I, K) CK_PR_STORE_S(char, char, "movb", CK_CC_IMM_S32) CK_PR_STORE_S(int, int, "movl", CK_CC_IMM_S32) CK_PR_STORE_S(uint, unsigned int, "movl", CK_CC_IMM_U32) CK_PR_STORE_S(64, uint64_t, "movq", CK_CC_IMM_U32) CK_PR_STORE_S(32, uint32_t, "movl", CK_CC_IMM_U32) CK_PR_STORE_S(16, uint16_t, "movw", CK_CC_IMM_U32) CK_PR_STORE_S(8, uint8_t, "movb", CK_CC_IMM_U32) #undef CK_PR_STORE_S #undef CK_PR_STORE_IMM #undef CK_PR_STORE /* * Atomic fetch-and-add operations. */ #define CK_PR_FAA(S, M, T, C, I) \ CK_CC_INLINE static T \ ck_pr_faa_##S(M *target, T d) \ { \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0" \ : "+m" (*(C *)target), \ "+q" (d) \ : \ : "memory", "cc"); \ return (d); \ } CK_PR_FAA(ptr, void, uintptr_t, char, "xaddq") #define CK_PR_FAA_S(S, T, I) CK_PR_FAA(S, T, T, T, I) CK_PR_FAA_S(char, char, "xaddb") CK_PR_FAA_S(uint, unsigned int, "xaddl") CK_PR_FAA_S(int, int, "xaddl") CK_PR_FAA_S(64, uint64_t, "xaddq") CK_PR_FAA_S(32, uint32_t, "xaddl") CK_PR_FAA_S(16, uint16_t, "xaddw") CK_PR_FAA_S(8, uint8_t, "xaddb") #undef CK_PR_FAA_S #undef CK_PR_FAA /* * Atomic store-only unary operations. */ #define CK_PR_UNARY(K, S, T, C, I) \ CK_PR_UNARY_R(K, S, T, C, I) \ CK_PR_UNARY_V(K, S, T, C, I) #define CK_PR_UNARY_R(K, S, T, C, I) \ CK_CC_INLINE static void \ ck_pr_##K##_##S(T *target) \ { \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0" \ : "+m" (*(C *)target) \ : \ : "memory", "cc"); \ return; \ } #define CK_PR_UNARY_V(K, S, T, C, I) \ CK_CC_INLINE static void \ ck_pr_##K##_##S##_zero(T *target, bool *r) \ { \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0; setz %1" \ : "+m" (*(C *)target), \ "=m" (*r) \ : \ : "memory", "cc"); \ return; \ } #define CK_PR_UNARY_S(K, S, T, I) CK_PR_UNARY(K, S, T, T, I) #define CK_PR_GENERATE(K) \ CK_PR_UNARY(K, ptr, void, char, #K "q") \ CK_PR_UNARY_S(K, char, char, #K "b") \ CK_PR_UNARY_S(K, int, int, #K "l") \ CK_PR_UNARY_S(K, uint, unsigned int, #K "l") \ CK_PR_UNARY_S(K, 64, uint64_t, #K "q") \ CK_PR_UNARY_S(K, 32, uint32_t, #K "l") \ CK_PR_UNARY_S(K, 16, uint16_t, #K "w") \ CK_PR_UNARY_S(K, 8, uint8_t, #K "b") CK_PR_GENERATE(inc) CK_PR_GENERATE(dec) CK_PR_GENERATE(neg) /* not does not affect condition flags. */ #undef CK_PR_UNARY_V #define CK_PR_UNARY_V(a, b, c, d, e) CK_PR_GENERATE(not) #undef CK_PR_GENERATE #undef CK_PR_UNARY_S #undef CK_PR_UNARY_V #undef CK_PR_UNARY_R #undef CK_PR_UNARY /* * Atomic store-only binary operations. */ #define CK_PR_BINARY(K, S, M, T, C, I, O) \ CK_CC_INLINE static void \ ck_pr_##K##_##S(M *target, T d) \ { \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0" \ : "+m" (*(C *)target) \ : O "q" (d) \ : "memory", "cc"); \ return; \ } #define CK_PR_BINARY_S(K, S, T, I, O) CK_PR_BINARY(K, S, T, T, T, I, O) #define CK_PR_GENERATE(K) \ CK_PR_BINARY(K, ptr, void, uintptr_t, char, #K "q", CK_CC_IMM_U32) \ CK_PR_BINARY_S(K, char, char, #K "b", CK_CC_IMM_S32) \ CK_PR_BINARY_S(K, int, int, #K "l", CK_CC_IMM_S32) \ CK_PR_BINARY_S(K, uint, unsigned int, #K "l", CK_CC_IMM_U32) \ CK_PR_BINARY_S(K, 64, uint64_t, #K "q", CK_CC_IMM_U32) \ CK_PR_BINARY_S(K, 32, uint32_t, #K "l", CK_CC_IMM_U32) \ CK_PR_BINARY_S(K, 16, uint16_t, #K "w", CK_CC_IMM_U32) \ CK_PR_BINARY_S(K, 8, uint8_t, #K "b", CK_CC_IMM_U32) CK_PR_GENERATE(add) CK_PR_GENERATE(sub) CK_PR_GENERATE(and) CK_PR_GENERATE(or) CK_PR_GENERATE(xor) #undef CK_PR_GENERATE #undef CK_PR_BINARY_S #undef CK_PR_BINARY /* * Atomic compare and swap. */ #define CK_PR_CAS(S, M, T, C, I) \ CK_CC_INLINE static bool \ ck_pr_cas_##S(M *target, T compare, T set) \ { \ bool z; \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %2, %0; setz %1" \ : "+m" (*(C *)target), \ "=a" (z) \ : "q" (set), \ "a" (compare) \ : "memory", "cc"); \ return z; \ } CK_PR_CAS(ptr, void, void *, char, "cmpxchgq") #define CK_PR_CAS_S(S, T, I) CK_PR_CAS(S, T, T, T, I) CK_PR_CAS_S(char, char, "cmpxchgb") CK_PR_CAS_S(int, int, "cmpxchgl") CK_PR_CAS_S(uint, unsigned int, "cmpxchgl") #ifndef CK_PR_DISABLE_DOUBLE CK_PR_CAS_S(double, double, "cmpxchgq") #endif CK_PR_CAS_S(64, uint64_t, "cmpxchgq") CK_PR_CAS_S(32, uint32_t, "cmpxchgl") CK_PR_CAS_S(16, uint16_t, "cmpxchgw") CK_PR_CAS_S(8, uint8_t, "cmpxchgb") #undef CK_PR_CAS_S #undef CK_PR_CAS /* * Compare and swap, set *v to old value of target. */ #define CK_PR_CAS_O(S, M, T, C, I, R) \ CK_CC_INLINE static bool \ ck_pr_cas_##S##_value(M *target, T compare, T set, M *v) \ { \ bool z; \ __asm__ __volatile__(CK_PR_LOCK_PREFIX "cmpxchg" I " %3, %0;" \ "mov %% " R ", %2;" \ "setz %1;" \ : "+m" (*(C *)target), \ "=a" (z), \ "=m" (*(C *)v) \ : "q" (set), \ "a" (compare) \ : "memory", "cc"); \ return z; \ } CK_PR_CAS_O(ptr, void, void *, char, "q", "rax") #define CK_PR_CAS_O_S(S, T, I, R) \ CK_PR_CAS_O(S, T, T, T, I, R) CK_PR_CAS_O_S(char, char, "b", "al") CK_PR_CAS_O_S(int, int, "l", "eax") CK_PR_CAS_O_S(uint, unsigned int, "l", "eax") #ifndef CK_PR_DISABLE_DOUBLE CK_PR_CAS_O_S(double, double, "q", "rax") #endif CK_PR_CAS_O_S(64, uint64_t, "q", "rax") CK_PR_CAS_O_S(32, uint32_t, "l", "eax") CK_PR_CAS_O_S(16, uint16_t, "w", "ax") CK_PR_CAS_O_S(8, uint8_t, "b", "al") #undef CK_PR_CAS_O_S #undef CK_PR_CAS_O /* * Contrary to C-interface, alignment requirements are that of uint64_t[2]. */ CK_CC_INLINE static bool ck_pr_cas_64_2(uint64_t target[2], uint64_t compare[2], uint64_t set[2]) { bool z; __asm__ __volatile__("movq 0(%4), %%rax;" "movq 8(%4), %%rdx;" CK_PR_LOCK_PREFIX "cmpxchg16b %0; setz %1" : "+m" (*target), "=q" (z) : "b" (set[0]), "c" (set[1]), "q" (compare) : "memory", "cc", "%rax", "%rdx"); return z; } CK_CC_INLINE static bool ck_pr_cas_ptr_2(void *t, void *c, void *s) { return ck_pr_cas_64_2(CK_CPP_CAST(uint64_t *, t), CK_CPP_CAST(uint64_t *, c), CK_CPP_CAST(uint64_t *, s)); } CK_CC_INLINE static bool ck_pr_cas_64_2_value(uint64_t target[2], uint64_t compare[2], uint64_t set[2], uint64_t v[2]) { bool z; __asm__ __volatile__(CK_PR_LOCK_PREFIX "cmpxchg16b %0;" "setz %3" : "+m" (*target), "=a" (v[0]), "=d" (v[1]), "=q" (z) : "a" (compare[0]), "d" (compare[1]), "b" (set[0]), "c" (set[1]) : "memory", "cc"); return z; } CK_CC_INLINE static bool ck_pr_cas_ptr_2_value(void *t, void *c, void *s, void *v) { return ck_pr_cas_64_2_value(CK_CPP_CAST(uint64_t *,t), CK_CPP_CAST(uint64_t *,c), CK_CPP_CAST(uint64_t *,s), CK_CPP_CAST(uint64_t *,v)); } #define CK_PR_CAS_V(S, W, T) \ CK_CC_INLINE static bool \ ck_pr_cas_##S##_##W(T t[W], T c[W], T s[W]) \ { \ return ck_pr_cas_64_2((uint64_t *)(void *)t, \ (uint64_t *)(void *)c, \ (uint64_t *)(void *)s); \ } \ CK_CC_INLINE static bool \ ck_pr_cas_##S##_##W##_value(T *t, T c[W], T s[W], T *v) \ { \ return ck_pr_cas_64_2_value((uint64_t *)(void *)t, \ (uint64_t *)(void *)c, \ (uint64_t *)(void *)s, \ (uint64_t *)(void *)v); \ } #ifndef CK_PR_DISABLE_DOUBLE CK_PR_CAS_V(double, 2, double) #endif CK_PR_CAS_V(char, 16, char) CK_PR_CAS_V(int, 4, int) CK_PR_CAS_V(uint, 4, unsigned int) CK_PR_CAS_V(32, 4, uint32_t) CK_PR_CAS_V(16, 8, uint16_t) CK_PR_CAS_V(8, 16, uint8_t) #undef CK_PR_CAS_V /* * Atomic bit test operations. */ #define CK_PR_BT(K, S, T, P, C, I) \ CK_CC_INLINE static bool \ ck_pr_##K##_##S(T *target, unsigned int b) \ { \ bool c; \ __asm__ __volatile__(CK_PR_LOCK_PREFIX I "; setc %1" \ : "+m" (*(C *)target), \ "=q" (c) \ : "q" ((P)b) \ : "memory", "cc"); \ return c; \ } #define CK_PR_BT_S(K, S, T, I) CK_PR_BT(K, S, T, T, T, I) #define CK_PR_GENERATE(K) \ CK_PR_BT(K, ptr, void, uint64_t, char, #K "q %2, %0") \ CK_PR_BT_S(K, uint, unsigned int, #K "l %2, %0") \ CK_PR_BT_S(K, int, int, #K "l %2, %0") \ CK_PR_BT_S(K, 64, uint64_t, #K "q %2, %0") \ CK_PR_BT_S(K, 32, uint32_t, #K "l %2, %0") \ CK_PR_BT_S(K, 16, uint16_t, #K "w %w2, %0") CK_PR_GENERATE(btc) CK_PR_GENERATE(bts) CK_PR_GENERATE(btr) #undef CK_PR_GENERATE #undef CK_PR_BT #endif /* CK_PR_X86_64_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/gcc/x86_64/ck_pr_rtm.h ================================================ /* * Copyright 2013-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 2012,2013 Intel Corporation * Author: Andi Kleen * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef CK_PR_X86_64_RTM_H #define CK_PR_X86_64_RTM_H #ifndef CK_PR_X86_64_H #error Do not include this file directly, use ck_pr.h #endif #define CK_F_PR_RTM #include #include #define CK_PR_RTM_STARTED (~0U) #define CK_PR_RTM_EXPLICIT (1 << 0) #define CK_PR_RTM_RETRY (1 << 1) #define CK_PR_RTM_CONFLICT (1 << 2) #define CK_PR_RTM_CAPACITY (1 << 3) #define CK_PR_RTM_DEBUG (1 << 4) #define CK_PR_RTM_NESTED (1 << 5) #define CK_PR_RTM_CODE(x) (((x) >> 24) & 0xFF) CK_CC_INLINE static unsigned int ck_pr_rtm_begin(void) { unsigned int r = CK_PR_RTM_STARTED; __asm__ __volatile__(".byte 0xc7,0xf8;" ".long 0;" : "+a" (r) : : "memory"); return r; } CK_CC_INLINE static void ck_pr_rtm_end(void) { __asm__ __volatile__(".byte 0x0f,0x01,0xd5" ::: "memory"); return; } CK_CC_INLINE static void ck_pr_rtm_abort(const unsigned int status) { __asm__ __volatile__(".byte 0xc6,0xf8,%P0" :: "i" (status) : "memory"); return; } CK_CC_INLINE static bool ck_pr_rtm_test(void) { bool r; __asm__ __volatile__(".byte 0x0f,0x01,0xd6;" "setnz %0" : "=r" (r) : : "memory"); return r; } #endif /* CK_PR_X86_64_RTM_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/spinlock/anderson.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_SPINLOCK_ANDERSON_H #define CK_SPINLOCK_ANDERSON_H #include #include #include #include #include #ifndef CK_F_SPINLOCK_ANDERSON #define CK_F_SPINLOCK_ANDERSON /* * This is an implementation of Anderson's array-based queuing lock. */ struct ck_spinlock_anderson_thread { unsigned int locked; unsigned int position; }; typedef struct ck_spinlock_anderson_thread ck_spinlock_anderson_thread_t; struct ck_spinlock_anderson { struct ck_spinlock_anderson_thread *slots; unsigned int count; unsigned int wrap; unsigned int mask; char pad[CK_MD_CACHELINE - sizeof(unsigned int) * 3 - sizeof(void *)]; unsigned int next; }; typedef struct ck_spinlock_anderson ck_spinlock_anderson_t; CK_CC_INLINE static void ck_spinlock_anderson_init(struct ck_spinlock_anderson *lock, struct ck_spinlock_anderson_thread *slots, unsigned int count) { unsigned int i; slots[0].locked = false; slots[0].position = 0; for (i = 1; i < count; i++) { slots[i].locked = true; slots[i].position = i; } lock->slots = slots; lock->count = count; lock->mask = count - 1; lock->next = 0; /* * If the number of threads is not a power of two then compute * appropriate wrap-around value in the case of next slot counter * overflow. */ if (count & (count - 1)) lock->wrap = (UINT_MAX % count) + 1; else lock->wrap = 0; ck_pr_barrier(); return; } CK_CC_INLINE static bool ck_spinlock_anderson_locked(struct ck_spinlock_anderson *lock) { unsigned int position; bool r; position = ck_pr_load_uint(&lock->next) & lock->mask; r = ck_pr_load_uint(&lock->slots[position].locked); ck_pr_fence_acquire(); return r; } CK_CC_INLINE static void ck_spinlock_anderson_lock(struct ck_spinlock_anderson *lock, struct ck_spinlock_anderson_thread **slot) { unsigned int position, next; unsigned int count = lock->count; /* * If count is not a power of 2, then it is possible for an overflow * to reallocate beginning slots to more than one thread. To avoid this * use a compare-and-swap. */ if (lock->wrap != 0) { position = ck_pr_load_uint(&lock->next); do { if (position == UINT_MAX) next = lock->wrap; else next = position + 1; } while (ck_pr_cas_uint_value(&lock->next, position, next, &position) == false); position %= count; } else { position = ck_pr_faa_uint(&lock->next, 1); position &= lock->mask; } /* Serialize with respect to previous thread's store. */ ck_pr_fence_load(); /* * Spin until slot is marked as unlocked. First slot is initialized to * false. */ while (ck_pr_load_uint(&lock->slots[position].locked) == true) ck_pr_stall(); /* Prepare slot for potential re-use by another thread. */ ck_pr_store_uint(&lock->slots[position].locked, true); ck_pr_fence_lock(); *slot = lock->slots + position; return; } CK_CC_INLINE static void ck_spinlock_anderson_unlock(struct ck_spinlock_anderson *lock, struct ck_spinlock_anderson_thread *slot) { unsigned int position; ck_pr_fence_unlock(); /* Mark next slot as available. */ if (lock->wrap == 0) position = (slot->position + 1) & lock->mask; else position = (slot->position + 1) % lock->count; ck_pr_store_uint(&lock->slots[position].locked, false); return; } #endif /* CK_F_SPINLOCK_ANDERSON */ #endif /* CK_SPINLOCK_ANDERSON_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/spinlock/cas.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_SPINLOCK_CAS_H #define CK_SPINLOCK_CAS_H #include #include #include #include #include #ifndef CK_F_SPINLOCK_CAS #define CK_F_SPINLOCK_CAS /* * This is a simple CACAS (TATAS) spinlock implementation. */ struct ck_spinlock_cas { unsigned int value; }; typedef struct ck_spinlock_cas ck_spinlock_cas_t; #define CK_SPINLOCK_CAS_INITIALIZER {false} CK_CC_INLINE static void ck_spinlock_cas_init(struct ck_spinlock_cas *lock) { lock->value = false; ck_pr_barrier(); return; } CK_CC_INLINE static bool ck_spinlock_cas_trylock(struct ck_spinlock_cas *lock) { unsigned int value; value = ck_pr_fas_uint(&lock->value, true); ck_pr_fence_lock(); return !value; } CK_CC_INLINE static bool ck_spinlock_cas_locked(struct ck_spinlock_cas *lock) { bool r = ck_pr_load_uint(&lock->value); ck_pr_fence_acquire(); return r; } CK_CC_INLINE static void ck_spinlock_cas_lock(struct ck_spinlock_cas *lock) { while (ck_pr_cas_uint(&lock->value, false, true) == false) { while (ck_pr_load_uint(&lock->value) == true) ck_pr_stall(); } ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_cas_lock_eb(struct ck_spinlock_cas *lock) { ck_backoff_t backoff = CK_BACKOFF_INITIALIZER; while (ck_pr_cas_uint(&lock->value, false, true) == false) ck_backoff_eb(&backoff); ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_cas_unlock(struct ck_spinlock_cas *lock) { /* Set lock state to unlocked. */ ck_pr_fence_unlock(); ck_pr_store_uint(&lock->value, false); return; } CK_ELIDE_PROTOTYPE(ck_spinlock_cas, ck_spinlock_cas_t, ck_spinlock_cas_locked, ck_spinlock_cas_lock, ck_spinlock_cas_locked, ck_spinlock_cas_unlock) CK_ELIDE_TRYLOCK_PROTOTYPE(ck_spinlock_cas, ck_spinlock_cas_t, ck_spinlock_cas_locked, ck_spinlock_cas_trylock) #endif /* CK_F_SPINLOCK_CAS */ #endif /* CK_SPINLOCK_CAS_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/spinlock/clh.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_SPINLOCK_CLH_H #define CK_SPINLOCK_CLH_H #include #include #include #include #include #ifndef CK_F_SPINLOCK_CLH #define CK_F_SPINLOCK_CLH struct ck_spinlock_clh { unsigned int wait; struct ck_spinlock_clh *previous; }; typedef struct ck_spinlock_clh ck_spinlock_clh_t; CK_CC_INLINE static void ck_spinlock_clh_init(struct ck_spinlock_clh **lock, struct ck_spinlock_clh *unowned) { unowned->previous = NULL; unowned->wait = false; *lock = unowned; ck_pr_barrier(); return; } CK_CC_INLINE static bool ck_spinlock_clh_locked(struct ck_spinlock_clh **queue) { struct ck_spinlock_clh *head; bool r; head = ck_pr_load_ptr(queue); r = ck_pr_load_uint(&head->wait); ck_pr_fence_acquire(); return r; } CK_CC_INLINE static void ck_spinlock_clh_lock(struct ck_spinlock_clh **queue, struct ck_spinlock_clh *thread) { struct ck_spinlock_clh *previous; /* Indicate to the next thread on queue that they will have to block. */ thread->wait = true; ck_pr_fence_store_atomic(); /* * Mark current request as last request. Save reference to previous * request. */ previous = ck_pr_fas_ptr(queue, thread); thread->previous = previous; /* Wait until previous thread is done with lock. */ ck_pr_fence_load(); while (ck_pr_load_uint(&previous->wait) == true) ck_pr_stall(); ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_clh_unlock(struct ck_spinlock_clh **thread) { struct ck_spinlock_clh *previous; /* * If there are waiters, they are spinning on the current node wait * flag. The flag is cleared so that the successor may complete an * acquisition. If the caller is pre-empted then the predecessor field * may be updated by a successor's lock operation. In order to avoid * this, save a copy of the predecessor before setting the flag. */ previous = thread[0]->previous; /* * We have to pay this cost anyways, use it as a compiler barrier too. */ ck_pr_fence_unlock(); ck_pr_store_uint(&(*thread)->wait, false); /* * Predecessor is guaranteed not to be spinning on previous request, * so update caller to use previous structure. This allows successor * all the time in the world to successfully read updated wait flag. */ *thread = previous; return; } #endif /* CK_F_SPINLOCK_CLH */ #endif /* CK_SPINLOCK_CLH_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/spinlock/dec.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_SPINLOCK_DEC_H #define CK_SPINLOCK_DEC_H #include #include #include #include #include #ifndef CK_F_SPINLOCK_DEC #define CK_F_SPINLOCK_DEC /* * This is similar to the CACAS lock but makes use of an atomic decrement * operation to check if the lock value was decremented to 0 from 1. The * idea is that a decrement operation is cheaper than a compare-and-swap. */ struct ck_spinlock_dec { unsigned int value; }; typedef struct ck_spinlock_dec ck_spinlock_dec_t; #define CK_SPINLOCK_DEC_INITIALIZER {1} CK_CC_INLINE static void ck_spinlock_dec_init(struct ck_spinlock_dec *lock) { lock->value = 1; ck_pr_barrier(); return; } CK_CC_INLINE static bool ck_spinlock_dec_trylock(struct ck_spinlock_dec *lock) { unsigned int value; value = ck_pr_fas_uint(&lock->value, 0); ck_pr_fence_lock(); return value == 1; } CK_CC_INLINE static bool ck_spinlock_dec_locked(struct ck_spinlock_dec *lock) { bool r; r = ck_pr_load_uint(&lock->value) != 1; ck_pr_fence_acquire(); return r; } CK_CC_INLINE static void ck_spinlock_dec_lock(struct ck_spinlock_dec *lock) { bool r; for (;;) { /* * Only one thread is guaranteed to decrement lock to 0. * Overflow must be protected against. No more than * UINT_MAX lock requests can happen while the lock is held. */ ck_pr_dec_uint_zero(&lock->value, &r); if (r == true) break; /* Load value without generating write cycles. */ while (ck_pr_load_uint(&lock->value) != 1) ck_pr_stall(); } ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_dec_lock_eb(struct ck_spinlock_dec *lock) { ck_backoff_t backoff = CK_BACKOFF_INITIALIZER; bool r; for (;;) { ck_pr_dec_uint_zero(&lock->value, &r); if (r == true) break; while (ck_pr_load_uint(&lock->value) != 1) ck_backoff_eb(&backoff); } ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_dec_unlock(struct ck_spinlock_dec *lock) { ck_pr_fence_unlock(); /* * Unconditionally set lock value to 1 so someone can decrement lock * to 0. */ ck_pr_store_uint(&lock->value, 1); return; } CK_ELIDE_PROTOTYPE(ck_spinlock_dec, ck_spinlock_dec_t, ck_spinlock_dec_locked, ck_spinlock_dec_lock, ck_spinlock_dec_locked, ck_spinlock_dec_unlock) CK_ELIDE_TRYLOCK_PROTOTYPE(ck_spinlock_dec, ck_spinlock_dec_t, ck_spinlock_dec_locked, ck_spinlock_dec_trylock) #endif /* CK_F_SPINLOCK_DEC */ #endif /* CK_SPINLOCK_DEC_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/spinlock/fas.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_SPINLOCK_FAS_H #define CK_SPINLOCK_FAS_H #include #include #include #include #include #ifndef CK_F_SPINLOCK_FAS #define CK_F_SPINLOCK_FAS struct ck_spinlock_fas { unsigned int value; }; typedef struct ck_spinlock_fas ck_spinlock_fas_t; #define CK_SPINLOCK_FAS_INITIALIZER {false} CK_CC_INLINE static void ck_spinlock_fas_init(struct ck_spinlock_fas *lock) { lock->value = false; ck_pr_barrier(); return; } CK_CC_INLINE static bool ck_spinlock_fas_trylock(struct ck_spinlock_fas *lock) { bool value; value = ck_pr_fas_uint(&lock->value, true); ck_pr_fence_lock(); return !value; } CK_CC_INLINE static bool ck_spinlock_fas_locked(struct ck_spinlock_fas *lock) { bool r; r = ck_pr_load_uint(&lock->value); ck_pr_fence_acquire(); return r; } CK_CC_INLINE static void ck_spinlock_fas_lock(struct ck_spinlock_fas *lock) { while (ck_pr_fas_uint(&lock->value, true) == true) { while (ck_pr_load_uint(&lock->value) == true) ck_pr_stall(); } ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_fas_lock_eb(struct ck_spinlock_fas *lock) { ck_backoff_t backoff = CK_BACKOFF_INITIALIZER; while (ck_pr_fas_uint(&lock->value, true) == true) ck_backoff_eb(&backoff); ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_fas_unlock(struct ck_spinlock_fas *lock) { ck_pr_fence_unlock(); ck_pr_store_uint(&lock->value, false); return; } CK_ELIDE_PROTOTYPE(ck_spinlock_fas, ck_spinlock_fas_t, ck_spinlock_fas_locked, ck_spinlock_fas_lock, ck_spinlock_fas_locked, ck_spinlock_fas_unlock) CK_ELIDE_TRYLOCK_PROTOTYPE(ck_spinlock_fas, ck_spinlock_fas_t, ck_spinlock_fas_locked, ck_spinlock_fas_trylock) #endif /* CK_F_SPINLOCK_FAS */ #endif /* CK_SPINLOCK_FAS_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/spinlock/hclh.h ================================================ /* * Copyright 2013-2015 Olivier Houchard * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_SPINLOCK_HCLH_H #define CK_SPINLOCK_HCLH_H #include #include #include #include #ifndef CK_F_SPINLOCK_HCLH #define CK_F_SPINLOCK_HCLH struct ck_spinlock_hclh { unsigned int wait; unsigned int splice; int cluster_id; struct ck_spinlock_hclh *previous; }; typedef struct ck_spinlock_hclh ck_spinlock_hclh_t; CK_CC_INLINE static void ck_spinlock_hclh_init(struct ck_spinlock_hclh **lock, struct ck_spinlock_hclh *unowned, int cluster_id) { unowned->previous = NULL; unowned->wait = false; unowned->splice = false; unowned->cluster_id = cluster_id; *lock = unowned; ck_pr_barrier(); return; } CK_CC_INLINE static bool ck_spinlock_hclh_locked(struct ck_spinlock_hclh **queue) { struct ck_spinlock_hclh *head; bool r; head = ck_pr_load_ptr(queue); r = ck_pr_load_uint(&head->wait); ck_pr_fence_acquire(); return r; } CK_CC_INLINE static void ck_spinlock_hclh_lock(struct ck_spinlock_hclh **glob_queue, struct ck_spinlock_hclh **local_queue, struct ck_spinlock_hclh *thread) { struct ck_spinlock_hclh *previous, *local_tail; /* Indicate to the next thread on queue that they will have to block. */ thread->wait = true; thread->splice = false; thread->cluster_id = (*local_queue)->cluster_id; /* Serialize with respect to update of local queue. */ ck_pr_fence_store_atomic(); /* Mark current request as last request. Save reference to previous request. */ previous = ck_pr_fas_ptr(local_queue, thread); thread->previous = previous; /* Wait until previous thread from the local queue is done with lock. */ ck_pr_fence_load(); if (previous->previous != NULL && previous->cluster_id == thread->cluster_id) { while (ck_pr_load_uint(&previous->wait) == true) ck_pr_stall(); /* We're head of the global queue, we're done */ if (ck_pr_load_uint(&previous->splice) == false) return; } /* Now we need to splice the local queue into the global queue. */ local_tail = ck_pr_load_ptr(local_queue); previous = ck_pr_fas_ptr(glob_queue, local_tail); ck_pr_store_uint(&local_tail->splice, true); /* Wait until previous thread from the global queue is done with lock. */ while (ck_pr_load_uint(&previous->wait) == true) ck_pr_stall(); ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_hclh_unlock(struct ck_spinlock_hclh **thread) { struct ck_spinlock_hclh *previous; /* * If there are waiters, they are spinning on the current node wait * flag. The flag is cleared so that the successor may complete an * acquisition. If the caller is pre-empted then the predecessor field * may be updated by a successor's lock operation. In order to avoid * this, save a copy of the predecessor before setting the flag. */ previous = thread[0]->previous; /* We have to pay this cost anyways, use it as a compiler barrier too. */ ck_pr_fence_unlock(); ck_pr_store_uint(&(*thread)->wait, false); /* * Predecessor is guaranteed not to be spinning on previous request, * so update caller to use previous structure. This allows successor * all the time in the world to successfully read updated wait flag. */ *thread = previous; return; } #endif /* CK_F_SPINLOCK_HCLH */ #endif /* CK_SPINLOCK_HCLH_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/spinlock/mcs.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_SPINLOCK_MCS_H #define CK_SPINLOCK_MCS_H #include #include #include #include #ifndef CK_F_SPINLOCK_MCS #define CK_F_SPINLOCK_MCS struct ck_spinlock_mcs { unsigned int locked; struct ck_spinlock_mcs *next; }; typedef struct ck_spinlock_mcs * ck_spinlock_mcs_t; typedef struct ck_spinlock_mcs ck_spinlock_mcs_context_t; #define CK_SPINLOCK_MCS_INITIALIZER (NULL) CK_CC_INLINE static void ck_spinlock_mcs_init(struct ck_spinlock_mcs **queue) { *queue = NULL; ck_pr_barrier(); return; } CK_CC_INLINE static bool ck_spinlock_mcs_trylock(struct ck_spinlock_mcs **queue, struct ck_spinlock_mcs *node) { bool r; node->locked = true; node->next = NULL; ck_pr_fence_store_atomic(); r = ck_pr_cas_ptr(queue, NULL, node); ck_pr_fence_lock(); return r; } CK_CC_INLINE static bool ck_spinlock_mcs_locked(struct ck_spinlock_mcs **queue) { bool r; r = ck_pr_load_ptr(queue) != NULL; ck_pr_fence_acquire(); return r; } CK_CC_INLINE static void ck_spinlock_mcs_lock(struct ck_spinlock_mcs **queue, struct ck_spinlock_mcs *node) { struct ck_spinlock_mcs *previous; /* * In the case that there is a successor, let them know they must * wait for us to unlock. */ node->locked = true; node->next = NULL; ck_pr_fence_store_atomic(); /* * Swap current tail with current lock request. If the swap operation * returns NULL, it means the queue was empty. If the queue was empty, * then the operation is complete. */ previous = ck_pr_fas_ptr(queue, node); if (previous != NULL) { /* * Let the previous lock holder know that we are waiting on * them. */ ck_pr_store_ptr(&previous->next, node); while (ck_pr_load_uint(&node->locked) == true) ck_pr_stall(); } ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_mcs_unlock(struct ck_spinlock_mcs **queue, struct ck_spinlock_mcs *node) { struct ck_spinlock_mcs *next; ck_pr_fence_unlock(); next = ck_pr_load_ptr(&node->next); if (next == NULL) { /* * If there is no request following us then it is a possibilty * that we are the current tail. In this case, we may just * mark the spinlock queue as empty. */ if (ck_pr_load_ptr(queue) == node && ck_pr_cas_ptr(queue, node, NULL) == true) { return; } /* * If the node is not the current tail then a lock operation * is in-progress. In this case, busy-wait until the queue is * in a consistent state to wake up the incoming lock * request. */ for (;;) { next = ck_pr_load_ptr(&node->next); if (next != NULL) break; ck_pr_stall(); } } /* Allow the next lock operation to complete. */ ck_pr_store_uint(&next->locked, false); return; } #endif /* CK_F_SPINLOCK_MCS */ #endif /* CK_SPINLOCK_MCS_H */ ================================================ FILE: third_party/concurrency_kit/ck/include/spinlock/ticket.h ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_SPINLOCK_TICKET_H #define CK_SPINLOCK_TICKET_H #include #include #include #include #include #include #ifndef CK_F_SPINLOCK_TICKET #define CK_F_SPINLOCK_TICKET /* * If 16-bit or 32-bit increment is supported, implement support for * trylock functionality on availability of 32-bit or 64-bit fetch-and-add * and compare-and-swap. This code path is only applied to x86*. */ #if defined(CK_MD_TSO) && (defined(__x86__) || defined(__x86_64__)) #if defined(CK_F_PR_FAA_32) && defined(CK_F_PR_INC_16) && defined(CK_F_PR_CAS_32) #define CK_SPINLOCK_TICKET_TYPE uint32_t #define CK_SPINLOCK_TICKET_TYPE_BASE uint16_t #define CK_SPINLOCK_TICKET_INC(x) ck_pr_inc_16(x) #define CK_SPINLOCK_TICKET_CAS(x, y, z) ck_pr_cas_32(x, y, z) #define CK_SPINLOCK_TICKET_FAA(x, y) ck_pr_faa_32(x, y) #define CK_SPINLOCK_TICKET_LOAD(x) ck_pr_load_32(x) #define CK_SPINLOCK_TICKET_INCREMENT (0x00010000UL) #define CK_SPINLOCK_TICKET_MASK (0xFFFFUL) #define CK_SPINLOCK_TICKET_SHIFT (16) #elif defined(CK_F_PR_FAA_64) && defined(CK_F_PR_INC_32) && defined(CK_F_PR_CAS_64) #define CK_SPINLOCK_TICKET_TYPE uint64_t #define CK_SPINLOCK_TICKET_TYPE_BASE uint32_t #define CK_SPINLOCK_TICKET_INC(x) ck_pr_inc_32(x) #define CK_SPINLOCK_TICKET_CAS(x, y, z) ck_pr_cas_64(x, y, z) #define CK_SPINLOCK_TICKET_FAA(x, y) ck_pr_faa_64(x, y) #define CK_SPINLOCK_TICKET_LOAD(x) ck_pr_load_64(x) #define CK_SPINLOCK_TICKET_INCREMENT (0x0000000100000000ULL) #define CK_SPINLOCK_TICKET_MASK (0xFFFFFFFFULL) #define CK_SPINLOCK_TICKET_SHIFT (32) #endif #endif /* CK_MD_TSO */ #if defined(CK_SPINLOCK_TICKET_TYPE) #define CK_F_SPINLOCK_TICKET_TRYLOCK struct ck_spinlock_ticket { CK_SPINLOCK_TICKET_TYPE value; }; typedef struct ck_spinlock_ticket ck_spinlock_ticket_t; #define CK_SPINLOCK_TICKET_INITIALIZER { .value = 0 } CK_CC_INLINE static void ck_spinlock_ticket_init(struct ck_spinlock_ticket *ticket) { ticket->value = 0; ck_pr_barrier(); return; } CK_CC_INLINE static bool ck_spinlock_ticket_locked(struct ck_spinlock_ticket *ticket) { CK_SPINLOCK_TICKET_TYPE request, position; request = CK_SPINLOCK_TICKET_LOAD(&ticket->value); position = request & CK_SPINLOCK_TICKET_MASK; request >>= CK_SPINLOCK_TICKET_SHIFT; ck_pr_fence_acquire(); return request != position; } CK_CC_INLINE static void ck_spinlock_ticket_lock(struct ck_spinlock_ticket *ticket) { CK_SPINLOCK_TICKET_TYPE request, position; /* Get our ticket number and set next ticket number. */ request = CK_SPINLOCK_TICKET_FAA(&ticket->value, CK_SPINLOCK_TICKET_INCREMENT); position = request & CK_SPINLOCK_TICKET_MASK; request >>= CK_SPINLOCK_TICKET_SHIFT; while (request != position) { ck_pr_stall(); position = CK_SPINLOCK_TICKET_LOAD(&ticket->value) & CK_SPINLOCK_TICKET_MASK; } ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_ticket_lock_pb(struct ck_spinlock_ticket *ticket, unsigned int c) { CK_SPINLOCK_TICKET_TYPE request, position; ck_backoff_t backoff; /* Get our ticket number and set next ticket number. */ request = CK_SPINLOCK_TICKET_FAA(&ticket->value, CK_SPINLOCK_TICKET_INCREMENT); position = request & CK_SPINLOCK_TICKET_MASK; request >>= CK_SPINLOCK_TICKET_SHIFT; while (request != position) { ck_pr_stall(); position = CK_SPINLOCK_TICKET_LOAD(&ticket->value) & CK_SPINLOCK_TICKET_MASK; backoff = (request - position) & CK_SPINLOCK_TICKET_MASK; backoff <<= c; ck_backoff_eb(&backoff); } ck_pr_fence_lock(); return; } CK_CC_INLINE static bool ck_spinlock_ticket_trylock(struct ck_spinlock_ticket *ticket) { CK_SPINLOCK_TICKET_TYPE snapshot, request, position; snapshot = CK_SPINLOCK_TICKET_LOAD(&ticket->value); position = snapshot & CK_SPINLOCK_TICKET_MASK; request = snapshot >> CK_SPINLOCK_TICKET_SHIFT; if (position != request) return false; if (CK_SPINLOCK_TICKET_CAS(&ticket->value, snapshot, snapshot + CK_SPINLOCK_TICKET_INCREMENT) == false) { return false; } ck_pr_fence_lock(); return true; } CK_CC_INLINE static void ck_spinlock_ticket_unlock(struct ck_spinlock_ticket *ticket) { ck_pr_fence_unlock(); CK_SPINLOCK_TICKET_INC((CK_SPINLOCK_TICKET_TYPE_BASE *)(void *)&ticket->value); return; } #undef CK_SPINLOCK_TICKET_TYPE #undef CK_SPINLOCK_TICKET_TYPE_BASE #undef CK_SPINLOCK_TICKET_INC #undef CK_SPINLOCK_TICKET_FAA #undef CK_SPINLOCK_TICKET_LOAD #undef CK_SPINLOCK_TICKET_INCREMENT #undef CK_SPINLOCK_TICKET_MASK #undef CK_SPINLOCK_TICKET_SHIFT #else /* * MESI benefits from cacheline padding between next and current. This avoids * invalidation of current from the cache due to incoming lock requests. */ struct ck_spinlock_ticket { unsigned int next; unsigned int position; }; typedef struct ck_spinlock_ticket ck_spinlock_ticket_t; #define CK_SPINLOCK_TICKET_INITIALIZER {.next = 0, .position = 0} CK_CC_INLINE static void ck_spinlock_ticket_init(struct ck_spinlock_ticket *ticket) { ticket->next = 0; ticket->position = 0; ck_pr_barrier(); return; } CK_CC_INLINE static bool ck_spinlock_ticket_locked(struct ck_spinlock_ticket *ticket) { bool r; r = ck_pr_load_uint(&ticket->position) != ck_pr_load_uint(&ticket->next); ck_pr_fence_acquire(); return r; } CK_CC_INLINE static void ck_spinlock_ticket_lock(struct ck_spinlock_ticket *ticket) { unsigned int request; /* Get our ticket number and set next ticket number. */ request = ck_pr_faa_uint(&ticket->next, 1); /* * Busy-wait until our ticket number is current. * We can get away without a fence here assuming * our position counter does not overflow. */ while (ck_pr_load_uint(&ticket->position) != request) ck_pr_stall(); ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_ticket_lock_pb(struct ck_spinlock_ticket *ticket, unsigned int c) { ck_backoff_t backoff; unsigned int request, position; request = ck_pr_faa_uint(&ticket->next, 1); for (;;) { position = ck_pr_load_uint(&ticket->position); if (position == request) break; backoff = request - position; backoff <<= c; /* * Ideally, back-off from generating cache traffic for at least * the amount of time necessary for the number of pending lock * acquisition and relinquish operations (assuming an empty * critical section). */ ck_backoff_eb(&backoff); } ck_pr_fence_lock(); return; } CK_CC_INLINE static void ck_spinlock_ticket_unlock(struct ck_spinlock_ticket *ticket) { unsigned int update; ck_pr_fence_unlock(); /* * Update current ticket value so next lock request can proceed. * Overflow behavior is assumed to be roll-over, in which case, * it is only an issue if there are 2^32 pending lock requests. */ update = ck_pr_load_uint(&ticket->position); ck_pr_store_uint(&ticket->position, update + 1); return; } #endif /* !CK_F_SPINLOCK_TICKET_TRYLOCK */ CK_ELIDE_PROTOTYPE(ck_spinlock_ticket, ck_spinlock_ticket_t, ck_spinlock_ticket_locked, ck_spinlock_ticket_lock, ck_spinlock_ticket_locked, ck_spinlock_ticket_unlock) CK_ELIDE_TRYLOCK_PROTOTYPE(ck_spinlock_ticket, ck_spinlock_ticket_t, ck_spinlock_ticket_locked, ck_spinlock_ticket_trylock) #endif /* CK_F_SPINLOCK_TICKET */ #endif /* CK_SPINLOCK_TICKET_H */ ================================================ FILE: third_party/concurrency_kit/ck/regressions/Makefile.unsupported ================================================ .PHONY: all clean check all: @echo Regressions are currently unsupported for out-of-source builds clean: all check: all ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_array/validate/serial.c ================================================ #include #include #include #include #include "../../common.h" #ifndef ITERATION #define ITERATION 128 #endif static void my_free(void *p, size_t m, bool d) { (void)m; (void)d; free(p); return; } static void * my_malloc(size_t b) { return malloc(b); } static void * my_realloc(void *r, size_t a, size_t b, bool d) { (void)a; (void)d; return realloc(r, b); } int main(void) { void *r; uintptr_t i; ck_array_t array; ck_array_iterator_t iterator; struct ck_malloc m = { .malloc = my_malloc, .free = NULL, .realloc = my_realloc }; if (ck_array_init(&array, CK_ARRAY_MODE_SPMC, &m, 4) == true) ck_error("ck_array_init with NULL free succeeded\n"); m.free = my_free; if (ck_array_init(&array, CK_ARRAY_MODE_SPMC, &m, 4) == false) ck_error("ck_array_init\n"); for (i = 0; i < ITERATION; i++) { if (ck_array_put(&array, (void *)i) == false) ck_error("ck_error_put\n"); if (ck_array_remove(&array, (void *)i) == false) ck_error("ck_error_remove after put\n"); } i = 0; CK_ARRAY_FOREACH(&array, &iterator, &r) i++; if (i != 0) ck_error("Non-empty array after put -> remove workload.\n"); ck_array_commit(&array); i = 0; CK_ARRAY_FOREACH(&array, &iterator, &r) i++; if (i != 0) ck_error("Non-empty array after put -> remove -> commit workload.\n"); for (i = 0; i < ITERATION; i++) { if (ck_array_put(&array, (void *)i) == false) ck_error("ck_error_put\n"); } i = 0; CK_ARRAY_FOREACH(&array, &iterator, &r) i++; if (i != 0) ck_error("Non-empty array after put workload.\n"); for (i = 0; i < ITERATION; i++) { if (ck_array_remove(&array, (void *)i) == false) ck_error("ck_error_remove after put\n"); } i = 0; CK_ARRAY_FOREACH(&array, &iterator, &r) i++; if (i != 0) ck_error("Non-empty array after put -> remove workload.\n"); ck_array_commit(&array); i = 0; CK_ARRAY_FOREACH(&array, &iterator, &r) i++; if (i != 0) ck_error("Non-empty array after put -> remove -> commit workload.\n"); for (i = 0; i < ITERATION; i++) { if (ck_array_put(&array, (void *)i) == false) ck_error("ck_error_put\n"); } ck_array_commit(&array); i = 0; CK_ARRAY_FOREACH(&array, &iterator, &r) { i++; } if (i != ITERATION) ck_error("Incorrect item count in iteration\n"); ck_array_remove(&array, (void *)(uintptr_t)0); ck_array_remove(&array, (void *)(uintptr_t)1); ck_array_commit(&array); i = 0; CK_ARRAY_FOREACH(&array, &iterator, &r) i++; if (i != ITERATION - 2 || ck_array_length(&array) != ITERATION - 2) ck_error("Incorrect item count in iteration after remove\n"); if (ck_array_put_unique(&array, (void *)UINTPTR_MAX) != 0) ck_error("Unique value put failed.\n"); if (ck_array_put_unique(&array, (void *)(uintptr_t)4) != 1) ck_error("put of 4 not detected as non-unique.\n"); if (ck_array_put_unique(&array, (void *)UINTPTR_MAX) != 1) ck_error("put of UINTPTR_MAX not detected as non-unique.\n"); ck_array_commit(&array); i = 0; CK_ARRAY_FOREACH(&array, &iterator, &r) { i++; } if (i != ITERATION - 1 || ck_array_length(&array) != ITERATION - 1) ck_error("Incorrect item count in iteration after unique put\n"); if (ck_array_initialized(&array) == false) ck_error("Error, expected array to be initialized.\n"); for (i = 0; i < ITERATION * 4; i++) { ck_array_remove(&array, (void *)i); } for (i = 0; i < ITERATION * 16; i++) { ck_array_put(&array, (void *)i); } ck_array_commit(&array); for (i = 0; i < ITERATION * 128; i++) { ck_array_put(&array, (void *)i); if (ck_array_put_unique(&array, (void *)i) != 1) ck_error("put_unique for non-unique value should fail.\n"); } for (i = 0; i < ITERATION * 64; i++) { bool f = ck_array_remove(&array, (void *)i); if (f == false && i < ITERATION * 144) ck_error("Remove failed for existing entry.\n"); if (f == true && i > ITERATION * 144) ck_error("Remove succeeded for non-existing entry.\n"); } ck_array_commit(&array); ck_array_deinit(&array, false); if (ck_array_initialized(&array) == true) ck_error("Error, expected array to be uninitialized.\n"); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_backoff/validate/validate.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "../../common.h" int main(void) { ck_backoff_t backoff = CK_BACKOFF_INITIALIZER; const ck_backoff_t ceiling = CK_BACKOFF_CEILING + 1; unsigned int i = 0; fprintf(stderr, "Ceiling is: %u (%#x)\n", CK_BACKOFF_CEILING, CK_BACKOFF_CEILING); for (;;) { ck_backoff_t previous = backoff; ck_backoff_eb(&backoff); printf("EB %u\n", backoff); if (previous == ceiling) { if (backoff != ceiling) ck_error("[C] GB: expected %u, got %u\n", ceiling, backoff); if (i++ >= 1) break; } else if (previous != backoff >> 1) { ck_error("[N] GB: expected %u (%u), got %u\n", previous << 1, previous, backoff); } } return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_barrier/benchmark/throughput.c ================================================ /* * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "../../common.h" #if defined(CK_F_PR_INC_64) && defined(CK_F_PR_LOAD_64) static int done = 0; static struct affinity a; static int nthr; static int tid; static ck_barrier_centralized_t barrier = CK_BARRIER_CENTRALIZED_INITIALIZER; struct counter { uint64_t value; } CK_CC_CACHELINE; struct counter *counters; static void * thread(void *null CK_CC_UNUSED) { ck_barrier_centralized_state_t state = CK_BARRIER_CENTRALIZED_STATE_INITIALIZER; int id; id = ck_pr_faa_int(&tid, 1); aff_iterate(&a); while (ck_pr_load_int(&done) == 0) { ck_barrier_centralized(&barrier, &state, nthr); ck_pr_inc_64(&counters[id].value); ck_barrier_centralized(&barrier, &state, nthr); ck_pr_inc_64(&counters[id].value); ck_barrier_centralized(&barrier, &state, nthr); ck_pr_inc_64(&counters[id].value); ck_barrier_centralized(&barrier, &state, nthr); ck_pr_inc_64(&counters[id].value); ck_barrier_centralized(&barrier, &state, nthr); ck_pr_inc_64(&counters[id].value); ck_barrier_centralized(&barrier, &state, nthr); ck_pr_inc_64(&counters[id].value); ck_barrier_centralized(&barrier, &state, nthr); ck_pr_inc_64(&counters[id].value); ck_barrier_centralized(&barrier, &state, nthr); ck_pr_inc_64(&counters[id].value); } return (NULL); } int main(int argc, char *argv[]) { pthread_t *threads; uint64_t count; int i; if (argc != 3) { ck_error("Correct usage: \n"); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } counters = calloc(sizeof(struct counter), nthr); if (counters == NULL) { ck_error("ERROR: Could not allocate counters\n"); } a.delta = atoi(argv[2]); fprintf(stderr, "Creating threads (barrier)..."); for (i = 0; i < nthr; ++i) { if (pthread_create(&threads[i], NULL, thread, NULL)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); common_sleep(10); count = 0; ck_pr_store_int(&done, 1); for (i = 0; i < nthr; ++i) count += ck_pr_load_64(&counters[i].value); printf("%d %16" PRIu64 "\n", nthr, count); return (0); } #else int main(void) { fputs("Unsupported.", stderr); return 0; } #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_barrier/validate/barrier_centralized.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 5000000 #endif #ifndef ENTRIES #define ENTRIES 512 #endif static struct affinity a; static int nthr; static int counters[ENTRIES]; static ck_barrier_centralized_t barrier = CK_BARRIER_CENTRALIZED_INITIALIZER; static int barrier_wait; static void * thread(void *null CK_CC_UNUSED) { ck_barrier_centralized_state_t state = CK_BARRIER_CENTRALIZED_STATE_INITIALIZER; int j, counter; int i = 0; aff_iterate(&a); ck_pr_inc_int(&barrier_wait); while (ck_pr_load_int(&barrier_wait) != nthr) ck_pr_stall(); for (j = 0; j < ITERATE; j++) { i = j++ & (ENTRIES - 1); ck_pr_inc_int(&counters[i]); ck_barrier_centralized(&barrier, &state, nthr); counter = ck_pr_load_int(&counters[i]); if (counter != nthr * (j / ENTRIES + 1)) { ck_error("FAILED [%d:%d]: %d != %d\n", i, j - 1, counter, nthr); } } return (NULL); } int main(int argc, char *argv[]) { pthread_t *threads; int i; if (argc < 3) { ck_error("Usage: correct \n"); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } a.delta = atoi(argv[2]); fprintf(stderr, "Creating threads (barrier)..."); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, thread, NULL)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); fprintf(stderr, "Waiting for threads to finish correctness regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_barrier/validate/barrier_combining.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 5000000 #endif #ifndef ENTRIES #define ENTRIES 512 #endif static struct affinity a; static int nthr; static int ngroups; static int counters[ENTRIES]; static ck_barrier_combining_t barrier; static int barrier_wait; static void * thread(void *group) { ck_barrier_combining_state_t state = CK_BARRIER_COMBINING_STATE_INITIALIZER; int j, counter; int i = 0; aff_iterate(&a); ck_pr_inc_int(&barrier_wait); while (ck_pr_load_int(&barrier_wait) != (nthr * ngroups)) ck_pr_stall(); for (j = 0; j < ITERATE; j++) { i = j++ & (ENTRIES - 1); ck_pr_inc_int(&counters[i]); ck_barrier_combining(&barrier, group, &state); counter = ck_pr_load_int(&counters[i]); if (counter != nthr * ngroups * (j / ENTRIES + 1)) { ck_error("FAILED [%d:%d]: %d != %d\n", i, j - 1, counter, nthr * ngroups); } } return (NULL); } int main(int argc, char *argv[]) { pthread_t *threads; ck_barrier_combining_group_t *groupings; ck_barrier_combining_group_t *init_root; int i; init_root = malloc(sizeof(ck_barrier_combining_group_t)); if (init_root == NULL) { ck_error("ERROR: Could not allocate initial barrier structure\n"); } ck_barrier_combining_init(&barrier, init_root); if (argc < 4) { ck_error("Usage: correct \n"); } ngroups = atoi(argv[1]); if (ngroups <= 0) { ck_error("ERROR: Number of groups must be greater than 0\n"); } nthr = atoi(argv[2]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } groupings = malloc(sizeof(ck_barrier_combining_group_t) * ngroups); if (groupings == NULL) { ck_error("Could not allocate thread barrier grouping structures\n"); } threads = malloc(sizeof(pthread_t) * nthr * ngroups); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } a.delta = atoi(argv[3]); for (i = 0; i < ngroups; i++) ck_barrier_combining_group_init(&barrier, groupings + i, nthr); fprintf(stderr, "Creating threads (barrier)..."); for (i = 0; i < (nthr * ngroups); i++) { if (pthread_create(&threads[i], NULL, thread, groupings + (i % ngroups))) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); fprintf(stderr, "Waiting for threads to finish correctness regression..."); for (i = 0; i < (nthr * ngroups); i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_barrier/validate/barrier_dissemination.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 5000000 #endif #ifndef ENTRIES #define ENTRIES 512 #endif static struct affinity a; static int nthr; static int counters[ENTRIES]; static int barrier_wait; static void * thread(void *b) { ck_barrier_dissemination_t *barrier = b; ck_barrier_dissemination_state_t state; int j, k, counter; int i = 0; aff_iterate(&a); ck_barrier_dissemination_subscribe(barrier, &state); ck_pr_inc_int(&barrier_wait); while (ck_pr_load_int(&barrier_wait) != nthr) ck_pr_stall(); for (j = 0, k = 0; j < ITERATE; j++, k++) { i = j++ & (ENTRIES - 1); ck_pr_inc_int(&counters[i]); ck_barrier_dissemination(barrier, &state); counter = ck_pr_load_int(&counters[i]); if (counter != nthr * (j / ENTRIES + 1)) { ck_error("FAILED [%d:%d]: %d != %d\n", i, j - 1, counter, nthr); } } return (NULL); } int main(int argc, char *argv[]) { ck_barrier_dissemination_t *barrier; ck_barrier_dissemination_flag_t **barrier_internal; pthread_t *threads; int i, size; if (argc < 3) { ck_error("Usage: correct \n"); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } a.delta = atoi(argv[2]); barrier = malloc(sizeof(ck_barrier_dissemination_t) * nthr); if (barrier == NULL) { ck_error("ERROR: Could not allocate barrier structures\n"); } barrier_internal = malloc(sizeof(ck_barrier_dissemination_flag_t *) * nthr); if (barrier_internal == NULL) { ck_error("ERROR: Could not allocate barrier structures\n"); } size = ck_barrier_dissemination_size(nthr); for (i = 0; i < nthr; ++i) { barrier_internal[i] = malloc(sizeof(ck_barrier_dissemination_flag_t) * size); if (barrier_internal[i] == NULL) { ck_error("ERROR: Could not allocate barrier structures\n"); } } ck_barrier_dissemination_init(barrier, barrier_internal, nthr); fprintf(stderr, "Creating threads (barrier)..."); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, thread, barrier)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); fprintf(stderr, "Waiting for threads to finish correctness regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_barrier/validate/barrier_mcs.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 5000000 #endif #ifndef ENTRIES #define ENTRIES 512 #endif static struct affinity a; static int nthr; static int counters[ENTRIES]; static int barrier_wait; static void * thread(void *b) { ck_barrier_mcs_t *barrier = b; ck_barrier_mcs_state_t state; int j, counter; int i = 0; aff_iterate(&a); ck_barrier_mcs_subscribe(barrier, &state); ck_pr_inc_int(&barrier_wait); while (ck_pr_load_int(&barrier_wait) != nthr) ck_pr_stall(); for (j = 0; j < ITERATE; j++) { i = j++ & (ENTRIES - 1); ck_pr_inc_int(&counters[i]); ck_barrier_mcs(barrier, &state); counter = ck_pr_load_int(&counters[i]); if (counter != nthr * (j / ENTRIES + 1)) { ck_error("FAILED [%d:%d]: %d != %d\n", i, j - 1, counter, nthr); } } return (NULL); } int main(int argc, char *argv[]) { pthread_t *threads; ck_barrier_mcs_t *barrier; int i; if (argc < 3) { ck_error("Usage: correct \n"); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } barrier = malloc(sizeof(ck_barrier_mcs_t) * nthr); if (barrier == NULL) { ck_error("ERROR: Could not allocate barrier structures\n"); } ck_barrier_mcs_init(barrier, nthr); a.delta = atoi(argv[2]); fprintf(stderr, "Creating threads (barrier)..."); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, thread, barrier)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); fprintf(stderr, "Waiting for threads to finish correctness regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_barrier/validate/barrier_tournament.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 5000000 #endif #ifndef ENTRIES #define ENTRIES 512 #endif static struct affinity a; static int nthr; static int counters[ENTRIES]; static int barrier_wait; static ck_barrier_tournament_t barrier; static void * thread(CK_CC_UNUSED void *unused) { ck_barrier_tournament_state_t state; int j, counter; int i = 0; aff_iterate(&a); ck_barrier_tournament_subscribe(&barrier, &state); ck_pr_inc_int(&barrier_wait); while (ck_pr_load_int(&barrier_wait) != nthr) ck_pr_stall(); for (j = 0; j < ITERATE; j++) { i = j++ & (ENTRIES - 1); ck_pr_inc_int(&counters[i]); ck_barrier_tournament(&barrier, &state); counter = ck_pr_load_int(&counters[i]); if (counter != nthr * (j / ENTRIES + 1)) { ck_error("FAILED [%d:%d]: %d != %d\n", i, j - 1, counter, nthr); } } ck_pr_inc_int(&barrier_wait); while (ck_pr_load_int(&barrier_wait) != nthr * 2) ck_pr_stall(); return (NULL); } int main(int argc, char *argv[]) { pthread_t *threads; ck_barrier_tournament_round_t **rounds; int i; unsigned int size; if (argc < 3) { ck_error("Usage: correct \n"); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } a.delta = atoi(argv[2]); threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } rounds = malloc(sizeof(ck_barrier_tournament_round_t *) * nthr); if (rounds == NULL) { ck_error("ERROR: Could not allocate barrier structures\n"); } size = ck_barrier_tournament_size(nthr); for (i = 0; i < nthr; ++i) { rounds[i] = malloc(sizeof(ck_barrier_tournament_round_t) * size); if (rounds[i] == NULL) { ck_error("ERROR: Could not allocate barrier structures\n"); } } ck_barrier_tournament_init(&barrier, rounds, nthr); fprintf(stderr, "Creating threads (barrier)..."); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, thread, NULL)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); fprintf(stderr, "Waiting for threads to finish correctness regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_bitmap/validate/serial.c ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * Copyright 2012-2014 AppNexus, Inc. * Copyright 2012 Shreyas Prasad. * Copyright 2014 Paul Khuong. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "../../common.h" #ifndef STATIC_LENGTH #define STATIC_LENGTH 256 #endif static unsigned int length = 256; static ck_bitmap_t *g_bits; static void check_iteration(ck_bitmap_t *bits, unsigned int len, bool initial) { ck_bitmap_iterator_t iter; unsigned int i = 0, j; len += 1; if (initial == true) { if (bits == g_bits) len = length; else len = STATIC_LENGTH; } ck_bitmap_iterator_init(&iter, bits); for (j = 0; ck_bitmap_next(bits, &iter, &i) == true; j++) { if (i == j) continue; ck_error("[4] ERROR: Expected bit %u, got bit %u\n", j, i); } if (j != len) { ck_error("[5] ERROR: Expected length %u, got length %u\n", len, j); } return; } static void test(ck_bitmap_t *bits, unsigned int n_length, bool initial) { bool r; unsigned int i; CK_BITMAP_INSTANCE(8) u; CK_BITMAP_INIT(&u, 8, false); CK_BITMAP_SET(&u, 1); CK_BITMAP_SET(&u, 4); for (i = 0; i < n_length; i++) { if (ck_bitmap_test(bits, i) == !initial) { ck_error("[0] ERROR [%u]: Expected %u got %u\n", i, initial, !initial); } } for (i = 0; i < n_length; i++) { ck_bitmap_set(bits, i); if (ck_bitmap_test(bits, i) == false) { ck_error("[1] ERROR: Expected bit to be set: %u\n", i); } ck_bitmap_reset(bits, i); if (ck_bitmap_test(bits, i) == true) { ck_error("[2] ERROR: Expected bit to be cleared: %u\n", i); } r = ck_bitmap_bts(bits, i); if (r == true) { ck_error("[3] ERROR: Expected bit to be cleared before 1st bts: %u\n", i); } if (ck_bitmap_test(bits, i) == false) { ck_error("[4] ERROR: Expected bit to be set: %u\n", i); } r = ck_bitmap_bts(bits, i); if (r == false) { ck_error("[5] ERROR: Expected bit to be set before 2nd bts: %u\n", i); } if (ck_bitmap_test(bits, i) == false) { ck_error("[6] ERROR: Expected bit to be set: %u\n", i); } ck_bitmap_reset(bits, i); if (ck_bitmap_test(bits, i) == true) { ck_error("[7] ERROR: Expected bit to be cleared: %u\n", i); } ck_bitmap_set(bits, i); if (ck_bitmap_test(bits, i) == false) { ck_error("[8] ERROR: Expected bit to be set: %u\n", i); } check_iteration(bits, i, initial); } for (i = 0; i < n_length; i++) { if (ck_bitmap_test(bits, i) == false) { ck_error("[9] ERROR: Expected bit to be set: %u\n", i); } } ck_bitmap_clear(bits); for (i = 0; i < n_length; i++) { if (ck_bitmap_test(bits, i) == true) { ck_error("[10] ERROR: Expected bit to be reset: %u\n", i); } } ck_bitmap_union(bits, CK_BITMAP(&u)); if (ck_bitmap_test(bits, 1) == false || ck_bitmap_test(bits, 4) == false) { ck_error("ERROR: Expected union semantics.\n"); } return; } static void test_init(bool init) { ck_bitmap_t *bitmap; size_t bytes; unsigned int i; bytes = ck_bitmap_size(length); bitmap = malloc(bytes); memset(bitmap, random(), bytes); ck_bitmap_init(bitmap, length, init); if (ck_bitmap_bits(bitmap) != length) { ck_error("ERROR: Expected length %u got %u\n", length, ck_bitmap_bits(bitmap)); } for (i = 0; i < length; i++) { if (ck_bitmap_test(bitmap, i) != init) { ck_error("ERROR: Expected bit %i at index %u, got %i\n", (int)init, i, (int)(!init)); } } free(bitmap); } static ck_bitmap_t * random_init(void) { ck_bitmap_t *bitmap; unsigned int i; bitmap = malloc(ck_bitmap_size(length)); ck_bitmap_init(bitmap, length, false); for (i = 0; i < length; i++) { if (random() & 1) { ck_bitmap_set(bitmap, i); } } return bitmap; } static ck_bitmap_t * copy(const ck_bitmap_t *src) { ck_bitmap_t *bitmap; size_t bytes = ck_bitmap_size(ck_bitmap_bits(src)); bitmap = malloc(bytes); memcpy(bitmap, src, bytes); return bitmap; } static void test_counts(const ck_bitmap_t *x, const ck_bitmap_t *y) { unsigned int count = 0; unsigned int count_intersect = 0; unsigned int i; for (i = 0; i <= length * 2; i++) { unsigned actual_limit = i; unsigned int r; bool check; if (actual_limit > ck_bitmap_bits(x)) actual_limit = ck_bitmap_bits(x); check = ck_bitmap_empty(x, i); if (check != (count == 0)) { ck_error("ck_bitmap_empty(%u): got %i expected %i\n", i, (int)check, (int)(count == 0)); } check = ck_bitmap_full(x, i); if (check != (count == actual_limit)) { ck_error("ck_bitmap_full(%u): got %i expected %i\n", i, (int)check, (int)(count == i)); } r = ck_bitmap_count(x, i); if (r != count) { ck_error("ck_bitmap_count(%u): got %u expected %u\n", i, r, count); } r = ck_bitmap_count_intersect(x, y, i); if (r != count_intersect) { ck_error("ck_bitmap_count_intersect(%u): got %u expected %u\n", i, r, count_intersect); } if (i < length) { count += ck_bitmap_test(x, i); count_intersect += ck_bitmap_test(x, i) & ck_bitmap_test(y, i); } } } static void random_test(unsigned int seed) { ck_bitmap_t *x, *x_copy, *y; unsigned int i; srandom(seed); test_init(false); test_init(true); x = random_init(); y = random_init(); #define TEST(routine, expected) do { \ x_copy = copy(x); \ routine(x_copy, y); \ for (i = 0; i < length; i++) { \ bool xi = ck_bitmap_test(x, i); \ bool yi = ck_bitmap_test(y, i); \ bool ri = ck_bitmap_test(x_copy, i); \ bool wanted = expected(xi, yi); \ \ if (ri != wanted) { \ ck_error("In " #routine " at %u: " \ "got %i expected %i\n", \ i, ri, wanted); \ } \ } \ free(x_copy); \ } while (0) #define OR(x, y) (x | y) #define AND(x, y) (x & y) #define ANDC2(x, y) (x & (~y)) TEST(ck_bitmap_union, OR); TEST(ck_bitmap_intersection, AND); TEST(ck_bitmap_intersection_negate, ANDC2); #undef ANDC2 #undef AND #undef OR #undef TEST test_counts(x, y); for (i = 0; i < 4; i++) { ck_bitmap_init(x, length, i & 1); ck_bitmap_init(y, length, i >> 1); test_counts(x, y); } free(y); free(x); } int main(int argc, char *argv[]) { unsigned int bytes, base; size_t i, j; if (argc >= 2) { length = atoi(argv[1]); } base = ck_bitmap_base(length); bytes = ck_bitmap_size(length); fprintf(stderr, "Configuration: %u bytes\n", bytes); g_bits = malloc(bytes); memset(g_bits->map, 0xFF, base); ck_bitmap_init(g_bits, length, false); test(g_bits, length, false); memset(g_bits->map, 0x00, base); ck_bitmap_init(g_bits, length, true); test(g_bits, length, true); ck_bitmap_test(g_bits, length - 1); CK_BITMAP_INSTANCE(STATIC_LENGTH) sb; fprintf(stderr, "Static configuration: %zu bytes\n", sizeof(sb)); memset(CK_BITMAP_BUFFER(&sb), 0xFF, ck_bitmap_base(STATIC_LENGTH)); CK_BITMAP_INIT(&sb, STATIC_LENGTH, false); test(CK_BITMAP(&sb), STATIC_LENGTH, false); memset(CK_BITMAP_BUFFER(&sb), 0x00, ck_bitmap_base(STATIC_LENGTH)); CK_BITMAP_INIT(&sb, STATIC_LENGTH, true); test(CK_BITMAP(&sb), STATIC_LENGTH, true); CK_BITMAP_CLEAR(&sb); if (CK_BITMAP_TEST(&sb, 1) == true) { ck_error("ERROR: Expected bit to be reset.\n"); } CK_BITMAP_SET(&sb, 1); if (CK_BITMAP_TEST(&sb, 1) == false) { ck_error("ERROR: Expected bit to be set.\n"); } CK_BITMAP_RESET(&sb, 1); if (CK_BITMAP_TEST(&sb, 1) == true) { ck_error("ERROR: Expected bit to be reset.\n"); } for (i = 0; i < 4 * sizeof(unsigned int) * CHAR_BIT; i++) { length = i; for (j = 0; j < 10; j++) { random_test(i * 10 + j); } } return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_brlock/benchmark/latency.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS 1000000 #endif int main(void) { uint64_t s_b, e_b, i; ck_brlock_t brlock = CK_BRLOCK_INITIALIZER; ck_brlock_reader_t r[8]; ck_rwlock_t naive; for (i = 0; i < sizeof(r) / sizeof(*r); i++) ck_brlock_read_register(&brlock, &r[i]); for (i = 0; i < STEPS; i++) { ck_brlock_write_lock(&brlock); ck_brlock_write_unlock(&brlock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_brlock_write_lock(&brlock); ck_brlock_write_unlock(&brlock); } e_b = rdtsc(); printf("WRITE: brlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); ck_rwlock_init(&naive); for (i = 0; i < STEPS; i++) { ck_rwlock_write_lock(&naive); ck_rwlock_write_unlock(&naive); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_rwlock_write_lock(&naive); ck_rwlock_write_unlock(&naive); } e_b = rdtsc(); printf("WRITE: naive %15" PRIu64 "\n", (e_b - s_b) / STEPS); for (i = 0; i < STEPS; i++) { ck_brlock_read_lock(&brlock, &r[0]); ck_brlock_read_unlock(&r[0]); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_brlock_read_lock(&brlock, &r[0]); ck_brlock_read_unlock(&r[0]); } e_b = rdtsc(); printf("READ: brlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); for (i = 0; i < STEPS; i++) { ck_rwlock_read_lock(&naive); ck_rwlock_read_unlock(&naive); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_rwlock_read_lock(&naive); ck_rwlock_read_unlock(&naive); } e_b = rdtsc(); printf("READ: naive %15" PRIu64 "\n", (e_b - s_b) / STEPS); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_brlock/benchmark/throughput.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS 1000000 #endif static int barrier; static int threads; static unsigned int flag CK_CC_CACHELINE; static ck_brlock_t brlock = CK_BRLOCK_INITIALIZER; static struct affinity affinity; static void * thread_brlock(void *pun) { uint64_t s_b, e_b, a, i; ck_brlock_reader_t r; uint64_t *value = pun; if (aff_iterate(&affinity) != 0) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } ck_brlock_read_register(&brlock, &r); ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads) ck_pr_stall(); for (i = 1, a = 0;; i++) { s_b = rdtsc(); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); ck_brlock_read_lock(&brlock, &r); ck_brlock_read_unlock(&r); e_b = rdtsc(); a += (e_b - s_b) >> 4; if (ck_pr_load_uint(&flag) == 1) break; } ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads * 2) ck_pr_stall(); *value = (a / i); return NULL; } int main(int argc, char *argv[]) { int t; pthread_t *p; uint64_t *latency; if (argc != 3) { ck_error("Usage: throughput \n"); } threads = atoi(argv[2]); if (threads <= 0) { ck_error("ERROR: Threads must be a value > 0.\n"); } p = malloc(sizeof(pthread_t) * threads); if (p == NULL) { ck_error("ERROR: Failed to initialize thread.\n"); } latency = malloc(sizeof(uint64_t) * threads); if (latency == NULL) { ck_error("ERROR: Failed to create latency buffer.\n"); } affinity.delta = atoi(argv[1]); affinity.request = 0; fprintf(stderr, "Creating threads (brlock)..."); for (t = 0; t < threads; t++) { if (pthread_create(&p[t], NULL, thread_brlock, latency + t) != 0) { ck_error("ERROR: Could not create thread %d\n", t); } } fprintf(stderr, "done\n"); common_sleep(10); ck_pr_store_uint(&flag, 1); fprintf(stderr, "Waiting for threads to finish acquisition regression..."); for (t = 0; t < threads; t++) pthread_join(p[t], NULL); fprintf(stderr, "done\n\n"); for (t = 1; t <= threads; t++) printf("%10u %20" PRIu64 "\n", t, latency[t - 1]); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_brlock/validate/validate.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 1000000 #endif static struct affinity a; static unsigned int locked = 0; static int nthr; static ck_brlock_t lock = CK_BRLOCK_INITIALIZER; static void * thread(void *null CK_CC_UNUSED) { ck_brlock_reader_t r; int i = ITERATE; unsigned int l; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } ck_brlock_read_register(&lock, &r); while (i--) { ck_brlock_write_lock(&lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } ck_brlock_write_unlock(&lock); ck_brlock_read_lock(&lock, &r); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } ck_brlock_read_unlock(&r); } ck_brlock_read_unregister(&lock, &r); return (NULL); } int main(int argc, char *argv[]) { pthread_t *threads; int i; if (argc != 3) { ck_error("Usage: validate \n"); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } a.delta = atoi(argv[2]); fprintf(stderr, "Creating threads (mutual exclusion)..."); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, thread, NULL)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); fprintf(stderr, "Waiting for threads to finish correctness regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_bytelock/benchmark/latency.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS 1000000 #endif int main(void) { uint64_t s_b, e_b, i; ck_bytelock_t bytelock = CK_BYTELOCK_INITIALIZER; ck_rwlock_t naive; for (i = 0; i < STEPS; i++) { ck_bytelock_write_lock(&bytelock, 1); ck_bytelock_write_unlock(&bytelock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_bytelock_write_lock(&bytelock, 1); ck_bytelock_write_unlock(&bytelock); } e_b = rdtsc(); printf("WRITE: bytelock %15" PRIu64 "\n", (e_b - s_b) / STEPS); ck_rwlock_init(&naive); for (i = 0; i < STEPS; i++) { ck_rwlock_write_lock(&naive); ck_rwlock_write_unlock(&naive); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_rwlock_write_lock(&naive); ck_rwlock_write_unlock(&naive); } e_b = rdtsc(); printf("WRITE: naive %15" PRIu64 "\n", (e_b - s_b) / STEPS); for (i = 0; i < STEPS; i++) { ck_bytelock_read_lock(&bytelock, 1); ck_bytelock_read_unlock(&bytelock, 1); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_bytelock_read_lock(&bytelock, 1); ck_bytelock_read_unlock(&bytelock, 1); } e_b = rdtsc(); printf("READ: bytelock %15" PRIu64 "\n", (e_b - s_b) / STEPS); for (i = 0; i < STEPS; i++) { ck_rwlock_read_lock(&naive); ck_rwlock_read_unlock(&naive); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_rwlock_read_lock(&naive); ck_rwlock_read_unlock(&naive); } e_b = rdtsc(); printf("READ: naive %15" PRIu64 "\n", (e_b - s_b) / STEPS); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_bytelock/validate/validate.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 5000000 #endif struct block { unsigned int tid; }; static struct affinity a; static unsigned int locked = 0; static int nthr; static ck_bytelock_t lock CK_CC_CACHELINE = CK_BYTELOCK_INITIALIZER; static void * thread(void *null) { struct block *context = null; int i = ITERATE; unsigned int l; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } if (context->tid == (unsigned int)nthr - 1) context->tid = sizeof(lock.readers) + 1; while (i--) { ck_bytelock_write_lock(&lock, context->tid); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } ck_bytelock_write_unlock(&lock); ck_bytelock_read_lock(&lock, context->tid); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } ck_bytelock_read_unlock(&lock, context->tid); } return (NULL); } int main(int argc, char *argv[]) { pthread_t *threads; struct block *context; int i; if (argc != 3) { ck_error("Usage: correct \n"); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } context = malloc(sizeof(struct block) * nthr); if (context == NULL) { ck_error("ERROR: Could not allocate thread contexts\n"); } a.delta = atoi(argv[2]); fprintf(stderr, "Creating threads (mutual exclusion)..."); for (i = 0; i < nthr; i++) { context[i].tid = i + 1; if (pthread_create(&threads[i], NULL, thread, context + i)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); fprintf(stderr, "Waiting for threads to finish correctness regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_cohort/benchmark/ck_cohort.c ================================================ #include "../ck_cohort.h" #include #ifdef THROUGHPUT #include "../../ck_spinlock/benchmark/throughput.h" #elif defined(LATENCY) #include "../../ck_spinlock/benchmark/latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_cohort/benchmark/throughput.c ================================================ /* * Copyright 2013-2015 Samy Al Bahra. * Copyright 2013 Brendon Scheinman. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #define max(x, y) (((x) > (y)) ? (x) : (y)) static struct affinity a; static unsigned int ready; struct counters { uint64_t value; } CK_CC_CACHELINE; static struct counters *count; static uint64_t nthr; static unsigned int n_cohorts; static unsigned int barrier; static int critical CK_CC_CACHELINE; static void ck_spinlock_fas_lock_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; ck_spinlock_fas_lock(lock); return; } static void ck_spinlock_fas_unlock_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; ck_spinlock_fas_unlock(lock); return; } static bool ck_spinlock_fas_locked_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; return ck_spinlock_fas_locked(lock); } CK_COHORT_PROTOTYPE(basic, ck_spinlock_fas_lock_with_context, ck_spinlock_fas_unlock_with_context, ck_spinlock_fas_locked_with_context, ck_spinlock_fas_lock_with_context, ck_spinlock_fas_unlock_with_context, ck_spinlock_fas_locked_with_context) struct cohort_record { CK_COHORT_INSTANCE(basic) cohort; } CK_CC_CACHELINE; static struct cohort_record *cohorts; static ck_spinlock_t global_lock = CK_SPINLOCK_INITIALIZER; struct block { unsigned int tid; }; static void * fairness(void *null) { struct block *context = null; unsigned int i = context->tid; volatile int j; long int base; unsigned int core; CK_COHORT_INSTANCE(basic) *cohort; if (aff_iterate_core(&a, &core)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } cohort = &((cohorts + (core / (int)(a.delta)) % n_cohorts)->cohort); while (ck_pr_load_uint(&ready) == 0); ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) != nthr); while (ck_pr_load_uint(&ready)) { CK_COHORT_LOCK(basic, cohort, NULL, NULL); count[i].value++; if (critical) { base = common_lrand48() % critical; for (j = 0; j < base; j++); } CK_COHORT_UNLOCK(basic, cohort, NULL, NULL); } return NULL; } int main(int argc, char *argv[]) { uint64_t v, d; unsigned int i; pthread_t *threads; struct block *context; ck_spinlock_t *local_lock; if (argc != 5) { ck_error("Usage: ck_cohort " " \n"); } n_cohorts = atoi(argv[1]); if (n_cohorts <= 0) { ck_error("ERROR: Number of cohorts must be greater than 0\n"); } nthr = n_cohorts * atoi(argv[2]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } critical = atoi(argv[4]); if (critical < 0) { ck_error("ERROR: critical section cannot be negative\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } cohorts = malloc(sizeof(struct cohort_record) * n_cohorts); if (cohorts == NULL) { ck_error("ERROR: Could not allocate cohort structures\n"); } context = malloc(sizeof(struct block) * nthr); if (context == NULL) { ck_error("ERROR: Could not allocate thread contexts\n"); } a.delta = atoi(argv[2]); a.request = 0; count = malloc(sizeof(*count) * nthr); if (count == NULL) { ck_error("ERROR: Could not create acquisition buffer\n"); } memset(count, 0, sizeof(*count) * nthr); fprintf(stderr, "Creating cohorts..."); for (i = 0 ; i < n_cohorts ; i++) { local_lock = malloc(max(CK_MD_CACHELINE, sizeof(ck_spinlock_t))); if (local_lock == NULL) { ck_error("ERROR: Could not allocate local lock\n"); } CK_COHORT_INIT(basic, &((cohorts + i)->cohort), &global_lock, local_lock, CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT); local_lock = NULL; } fprintf(stderr, "done\n"); fprintf(stderr, "Creating threads (fairness)..."); for (i = 0; i < nthr; i++) { context[i].tid = i; if (pthread_create(&threads[i], NULL, fairness, context + i)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); ck_pr_store_uint(&ready, 1); common_sleep(10); ck_pr_store_uint(&ready, 0); fprintf(stderr, "Waiting for threads to finish acquisition regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done\n\n"); for (i = 0, v = 0; i < nthr; i++) { printf("%d %15" PRIu64 "\n", i, count[i].value); v += count[i].value; } printf("\n# total : %15" PRIu64 "\n", v); printf("# throughput : %15" PRIu64 " a/s\n", (v /= nthr) / 10); for (i = 0, d = 0; i < nthr; i++) d += (count[i].value - v) * (count[i].value - v); printf("# average : %15" PRIu64 "\n", v); printf("# deviation : %.2f (%.2f%%)\n\n", sqrt(d / nthr), (sqrt(d / nthr) / v) * 100.00); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_cohort/ck_cohort.h ================================================ #define LOCK_NAME "ck_cohort" #define LOCK_DEFINE \ static ck_spinlock_fas_t global_fas_lock = CK_SPINLOCK_FAS_INITIALIZER; \ static ck_spinlock_fas_t local_fas_lock = CK_SPINLOCK_FAS_INITIALIZER; \ static void \ ck_spinlock_fas_lock_with_context(ck_spinlock_fas_t *lock, void *context) \ { \ (void)context; \ ck_spinlock_fas_lock(lock); \ } \ \ static void \ ck_spinlock_fas_unlock_with_context(ck_spinlock_fas_t *lock, void *context) \ { \ (void)context; \ ck_spinlock_fas_unlock(lock); \ } \ \ static bool \ ck_spinlock_fas_locked_with_context(ck_spinlock_fas_t *lock, void *context) \ { \ (void)context; \ return ck_spinlock_fas_locked(lock); \ } \ CK_COHORT_PROTOTYPE(fas_fas, \ ck_spinlock_fas_lock_with_context, ck_spinlock_fas_unlock_with_context, \ ck_spinlock_fas_locked_with_context, ck_spinlock_fas_lock_with_context, \ ck_spinlock_fas_unlock_with_context, ck_spinlock_fas_locked_with_context) \ static CK_COHORT_INSTANCE(fas_fas) CK_CC_CACHELINE cohort = CK_COHORT_INITIALIZER #define LOCK_INIT CK_COHORT_INIT(fas_fas, &cohort, &global_fas_lock, &local_fas_lock, \ CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT) #define LOCK CK_COHORT_LOCK(fas_fas, &cohort, NULL, NULL) #define UNLOCK CK_COHORT_UNLOCK(fas_fas, &cohort, NULL, NULL) ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_cohort/validate/validate.c ================================================ /* * Copyright 2013-2015 Samy Al Bahra. * Copyright 2013 Brendon Scheinman. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 1000000 #endif static struct affinity a; static unsigned int locked; static int nthr; static ck_spinlock_fas_t global_fas_lock = CK_SPINLOCK_FAS_INITIALIZER; static void ck_spinlock_fas_lock_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; ck_spinlock_fas_lock(lock); } static void ck_spinlock_fas_unlock_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; ck_spinlock_fas_unlock(lock); } static bool ck_spinlock_fas_locked_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; return ck_spinlock_fas_locked(lock); } static bool ck_spinlock_fas_trylock_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; return ck_spinlock_fas_trylock(lock); } CK_COHORT_TRYLOCK_PROTOTYPE(fas_fas, ck_spinlock_fas_lock_with_context, ck_spinlock_fas_unlock_with_context, ck_spinlock_fas_locked_with_context, ck_spinlock_fas_trylock_with_context, ck_spinlock_fas_lock_with_context, ck_spinlock_fas_unlock_with_context, ck_spinlock_fas_locked_with_context, ck_spinlock_fas_trylock_with_context) static CK_COHORT_INSTANCE(fas_fas) *cohorts; static int n_cohorts; static void * thread(void *null CK_CC_UNUSED) { int i = ITERATE; unsigned int l; unsigned int core; CK_COHORT_INSTANCE(fas_fas) *cohort; if (aff_iterate_core(&a, &core)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } cohort = cohorts + (core / (int)(a.delta)) % n_cohorts; while (i--) { if (i & 1) { CK_COHORT_LOCK(fas_fas, cohort, NULL, NULL); } else { while (CK_COHORT_TRYLOCK(fas_fas, cohort, NULL, NULL, NULL) == false) { ck_pr_stall(); } } { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } CK_COHORT_UNLOCK(fas_fas, cohort, NULL, NULL); } return (NULL); } int main(int argc, char *argv[]) { pthread_t *threads; int threads_per_cohort; ck_spinlock_fas_t *local_lock; int i; if (argc != 4) { ck_error("Usage: validate \n"); } n_cohorts = atoi(argv[1]); if (n_cohorts <= 0) { fprintf(stderr, "setting number of cohorts per thread to 1\n"); n_cohorts = 1; } threads_per_cohort = atoi(argv[2]); if (threads_per_cohort <= 0) { ck_error("ERROR: Threads per cohort must be greater than 0\n"); } nthr = n_cohorts * threads_per_cohort; threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } a.delta = atoi(argv[3]); fprintf(stderr, "Creating cohorts..."); cohorts = malloc(sizeof(CK_COHORT_INSTANCE(fas_fas)) * n_cohorts); for (i = 0 ; i < n_cohorts ; i++) { local_lock = malloc(sizeof(ck_spinlock_fas_t)); CK_COHORT_INIT(fas_fas, cohorts + i, &global_fas_lock, local_lock, CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT); } fprintf(stderr, "done\n"); fprintf(stderr, "Creating threads..."); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, thread, NULL)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); fprintf(stderr, "Waiting for threads to finish correctness regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_epoch/validate/ck_epoch_call.c ================================================ /* * Copyright 2014 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "../../common.h" static ck_epoch_t epoch; static unsigned int counter; static ck_epoch_record_t record[2]; static void cb(ck_epoch_entry_t *p) { /* Test that we can reregister the callback. */ if (counter == 0) ck_epoch_call(&record[1], p, cb); printf("Counter value: %u -> %u\n", counter, counter + 1); counter++; return; } int main(void) { ck_epoch_entry_t entry; ck_epoch_entry_t another; ck_epoch_register(&epoch, &record[0], NULL); ck_epoch_register(&epoch, &record[1], NULL); ck_epoch_call(&record[1], &entry, cb); ck_epoch_barrier(&record[1]); ck_epoch_barrier(&record[1]); /* Make sure that strict works. */ ck_epoch_call_strict(&record[1], &entry, cb); ck_epoch_call_strict(&record[1], &another, cb); ck_epoch_barrier(&record[1]); if (counter != 4) ck_error("Expected counter value 4, read %u.\n", counter); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_epoch/validate/ck_epoch_poll.c ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" static unsigned int n_rd; static unsigned int n_wr; static unsigned int n_threads; static unsigned int barrier; static unsigned int e_barrier; static unsigned int readers; static unsigned int writers; #ifndef PAIRS_S #define PAIRS_S 100000 #endif #ifndef ITERATE_S #define ITERATE_S 20 #endif struct node { unsigned int value; ck_stack_entry_t stack_entry; ck_epoch_entry_t epoch_entry; }; static ck_stack_t stack = CK_STACK_INITIALIZER; static ck_epoch_t stack_epoch; CK_STACK_CONTAINER(struct node, stack_entry, stack_container) CK_EPOCH_CONTAINER(struct node, epoch_entry, epoch_container) static struct affinity a; static const char animate[] = "-/|\\"; static void destructor(ck_epoch_entry_t *p) { struct node *e = epoch_container(p); free(e); return; } static void * read_thread(void *unused CK_CC_UNUSED) { unsigned int j; ck_epoch_record_t record CK_CC_CACHELINE; ck_stack_entry_t *cursor, *n; ck_epoch_register(&stack_epoch, &record, NULL); if (aff_iterate(&a)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < n_threads); while (CK_STACK_ISEMPTY(&stack) == true) { if (ck_pr_load_uint(&readers) != 0) break; ck_pr_stall(); } j = 0; for (;;) { ck_epoch_begin(&record, NULL); CK_STACK_FOREACH(&stack, cursor) { if (cursor == NULL) continue; n = CK_STACK_NEXT(cursor); j += ck_pr_load_ptr(&n) != NULL; } ck_epoch_end(&record, NULL); if (j != 0 && ck_pr_load_uint(&readers) == 0) ck_pr_store_uint(&readers, 1); if (CK_STACK_ISEMPTY(&stack) == true && ck_pr_load_uint(&e_barrier) != 0) break; } ck_pr_inc_uint(&e_barrier); while (ck_pr_load_uint(&e_barrier) < n_threads); fprintf(stderr, "[R] Observed entries: %u\n", j); return (NULL); } static void * write_thread(void *unused CK_CC_UNUSED) { struct node **entry, *e; unsigned int i, j, tid; ck_epoch_record_t record; ck_stack_entry_t *s; ck_epoch_register(&stack_epoch, &record, NULL); if (aff_iterate(&a)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } tid = ck_pr_faa_uint(&writers, 1); ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < n_threads); entry = malloc(sizeof(struct node *) * PAIRS_S); if (entry == NULL) { ck_error("Failed allocation.\n"); } for (j = 0; j < ITERATE_S; j++) { for (i = 0; i < PAIRS_S; i++) { entry[i] = malloc(sizeof(struct node)); if (entry == NULL) { ck_error("Failed individual allocation\n"); } } for (i = 0; i < PAIRS_S; i++) { ck_stack_push_upmc(&stack, &entry[i]->stack_entry); } while (ck_pr_load_uint(&readers) == 0) ck_pr_stall(); if (tid == 0) { fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b[W] %2.2f: %c", (double)j / ITERATE_S, animate[i % strlen(animate)]); } for (i = 0; i < PAIRS_S; i++) { ck_epoch_begin(&record, NULL); s = ck_stack_pop_upmc(&stack); e = stack_container(s); ck_epoch_end(&record, NULL); ck_epoch_call(&record, &e->epoch_entry, destructor); ck_epoch_poll(&record); } } ck_epoch_barrier(&record); if (tid == 0) { fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b[W] Peak: %u (%2.2f%%)\n Reclamations: %u\n\n", record.n_peak, (double)record.n_peak / ((double)PAIRS_S * ITERATE_S) * 100, record.n_dispatch); } ck_pr_inc_uint(&e_barrier); while (ck_pr_load_uint(&e_barrier) < n_threads); return (NULL); } int main(int argc, char *argv[]) { unsigned int i; pthread_t *threads; if (argc != 4) { ck_error("Usage: stack <#readers> <#writers> \n"); } n_rd = atoi(argv[1]); n_wr = atoi(argv[2]); n_threads = n_wr + n_rd; a.delta = atoi(argv[3]); a.request = 0; threads = malloc(sizeof(pthread_t) * n_threads); ck_epoch_init(&stack_epoch); for (i = 0; i < n_rd; i++) pthread_create(threads + i, NULL, read_thread, NULL); do { pthread_create(threads + i, NULL, write_thread, NULL); } while (++i < n_wr + n_rd); for (i = 0; i < n_threads; i++) pthread_join(threads[i], NULL); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_epoch/validate/ck_epoch_section.c ================================================ /* * Copyright 2015 John Esmet. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "../../common.h" static ck_epoch_t epc; static ck_epoch_record_t record, record2; static unsigned int cleanup_calls; static void setup_test(void) { ck_epoch_init(&epc); ck_epoch_register(&epc, &record, NULL); ck_epoch_register(&epc, &record2, NULL); cleanup_calls = 0; return; } static void teardown_test(void) { memset(&epc, 0, sizeof(ck_epoch_t)); ck_epoch_unregister(&record); memset(&record, 0, sizeof(ck_epoch_record_t)); memset(&record2, 0, sizeof(ck_epoch_record_t)); cleanup_calls = 0; return; } static void cleanup(ck_epoch_entry_t *e) { (void) e; cleanup_calls++; return; } static void test_simple_read_section(void) { ck_epoch_entry_t entry; ck_epoch_section_t section; memset(&entry, 0, sizeof(ck_epoch_entry_t)); setup_test(); ck_epoch_begin(&record, §ion); ck_epoch_call(&record, &entry, cleanup); assert(cleanup_calls == 0); if (ck_epoch_end(&record, §ion) == false) ck_error("expected no more sections"); ck_epoch_barrier(&record); assert(cleanup_calls == 1); teardown_test(); return; } static void test_nested_read_section(void) { ck_epoch_entry_t entry1, entry2; ck_epoch_section_t section1, section2; memset(&entry1, 0, sizeof(ck_epoch_entry_t)); memset(&entry2, 0, sizeof(ck_epoch_entry_t)); setup_test(); ck_epoch_begin(&record, §ion1); ck_epoch_call(&record, &entry1, cleanup); assert(cleanup_calls == 0); ck_epoch_begin(&record, §ion2); ck_epoch_call(&record, &entry2, cleanup); assert(cleanup_calls == 0); ck_epoch_end(&record, §ion2); assert(cleanup_calls == 0); ck_epoch_end(&record, §ion1); assert(cleanup_calls == 0); ck_epoch_barrier(&record); assert(cleanup_calls == 2); teardown_test(); return; } struct obj { ck_epoch_entry_t entry; unsigned int destroyed; }; static void * barrier_work(void *arg) { unsigned int *run; run = (unsigned int *)arg; while (ck_pr_load_uint(run) != 0) { /* * Need to use record2, as record is local * to the test thread. */ ck_epoch_barrier(&record2); usleep(5 * 1000); } return NULL; } static void * reader_work(void *arg) { ck_epoch_record_t local_record; ck_epoch_section_t section; struct obj *o; ck_epoch_register(&epc, &local_record, NULL); o = (struct obj *)arg; /* * Begin a read section. The calling thread has an open read section, * so the object should not be destroyed for the lifetime of this * thread. */ ck_epoch_begin(&local_record, §ion); usleep((common_rand() % 100) * 1000); assert(ck_pr_load_uint(&o->destroyed) == 0); ck_epoch_end(&local_record, §ion); ck_epoch_unregister(&local_record); return NULL; } static void obj_destroy(ck_epoch_entry_t *e) { struct obj *o; o = (struct obj *)e; ck_pr_fas_uint(&o->destroyed, 1); return; } static void test_single_reader_with_barrier_thread(void) { const int num_sections = 10; struct obj o; unsigned int run; pthread_t thread; ck_epoch_section_t sections[num_sections]; int shuffled[num_sections]; run = 1; memset(&o, 0, sizeof(struct obj)); common_srand(time(NULL)); setup_test(); if (pthread_create(&thread, NULL, barrier_work, &run) != 0) { abort(); } /* Start a bunch of sections. */ for (int i = 0; i < num_sections; i++) { ck_epoch_begin(&record, §ions[i]); shuffled[i] = i; if (i == num_sections / 2) { usleep(1 * 1000); } } /* Generate a shuffle. */ for (int i = num_sections - 1; i >= 0; i--) { int k = common_rand() % (i + 1); int tmp = shuffled[k]; shuffled[k] = shuffled[i]; shuffled[i] = tmp; } ck_epoch_call(&record, &o.entry, obj_destroy); /* Close the sections in shuffle-order. */ for (int i = 0; i < num_sections; i++) { ck_epoch_end(&record, §ions[shuffled[i]]); if (i != num_sections - 1) { assert(ck_pr_load_uint(&o.destroyed) == 0); usleep(3 * 1000); } } ck_pr_store_uint(&run, 0); if (pthread_join(thread, NULL) != 0) { abort(); } ck_epoch_barrier(&record); assert(ck_pr_load_uint(&o.destroyed) == 1); teardown_test(); return; } static void test_multiple_readers_with_barrier_thread(void) { const int num_readers = 10; struct obj o; unsigned int run; ck_epoch_section_t section; pthread_t threads[num_readers + 1]; run = 1; memset(&o, 0, sizeof(struct obj)); memset(§ion, 0, sizeof(ck_epoch_section_t)); common_srand(time(NULL)); setup_test(); /* Create a thread to call barrier() while we create reader threads. * Each barrier will attempt to move the global epoch forward so * it will make the read section code coverage more interesting. */ if (pthread_create(&threads[num_readers], NULL, barrier_work, &run) != 0) { abort(); } ck_epoch_begin(&record, §ion); ck_epoch_call(&record, &o.entry, obj_destroy); for (int i = 0; i < num_readers; i++) { if (pthread_create(&threads[i], NULL, reader_work, &o) != 0) { abort(); } } ck_epoch_end(&record, §ion); ck_pr_store_uint(&run, 0); if (pthread_join(threads[num_readers], NULL) != 0) { abort(); } /* After the barrier, the object should be destroyed and readers * should return. */ for (int i = 0; i < num_readers; i++) { if (pthread_join(threads[i], NULL) != 0) { abort(); } } teardown_test(); return; } int main(void) { test_simple_read_section(); test_nested_read_section(); test_single_reader_with_barrier_thread(); test_multiple_readers_with_barrier_thread(); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_epoch/validate/ck_epoch_section_2.c ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" static unsigned int n_rd; static unsigned int n_wr; static unsigned int n_threads; static unsigned int barrier; static unsigned int leave; #ifndef PAIRS_S #define PAIRS_S 10000 #endif #ifndef CK_EPOCH_T_DEPTH #define CK_EPOCH_T_DEPTH 8 #endif static ck_epoch_t epoch; static struct affinity a; static void * read_thread(void *unused CK_CC_UNUSED) { ck_epoch_record_t *record; unsigned long long i = 0; record = malloc(sizeof *record); assert(record != NULL); ck_epoch_register(&epoch, record, NULL); if (aff_iterate(&a)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < n_threads); for (;;) { ck_epoch_section_t section[2]; ck_epoch_section_t junk[CK_EPOCH_T_DEPTH]; unsigned int j; ck_epoch_begin(record, §ion[0]); for (j = 0; j < CK_EPOCH_T_DEPTH; j++) ck_epoch_begin(record, &junk[j]); for (j = 0; j < CK_EPOCH_T_DEPTH; j++) ck_epoch_end(record, &junk[j]); if (i > 0) ck_epoch_end(record, §ion[1]); /* Wait for the next synchronize operation. */ while ((ck_pr_load_uint(&epoch.epoch) & 1) == section[0].bucket) { i++; if (!(i % 10000000)) { fprintf(stderr, "%u %u %u\n", ck_pr_load_uint(&epoch.epoch), section[0].bucket, record->epoch); } while ((ck_pr_load_uint(&epoch.epoch) & 1) == section[0].bucket) { if (ck_pr_load_uint(&leave) == 1) break; ck_pr_stall(); } } ck_epoch_begin(record, §ion[1]); assert(section[0].bucket != section[1].bucket); ck_epoch_end(record, §ion[0]); assert(ck_pr_load_uint(&record->active) > 0); if (ck_pr_load_uint(&leave) == 1) { ck_epoch_end(record, §ion[1]); break; } i++; } return NULL; } static void * write_thread(void *unused CK_CC_UNUSED) { ck_epoch_record_t record; unsigned long iterations = 0; ck_epoch_register(&epoch, &record, NULL); if (aff_iterate(&a)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < n_threads); for (;;) { if (!(iterations % 1048575)) fprintf(stderr, "."); ck_epoch_synchronize(&record); iterations++; if (ck_pr_load_uint(&leave) == 1) break; } fprintf(stderr, "%lu iterations\n", iterations); return NULL; } int main(int argc, char *argv[]) { unsigned int i; pthread_t *threads; if (argc != 4) { ck_error("Usage: stack <#readers> <#writers> \n"); } n_rd = atoi(argv[1]); n_wr = atoi(argv[2]); n_threads = n_wr + n_rd; a.delta = atoi(argv[3]); a.request = 0; threads = malloc(sizeof(pthread_t) * n_threads); ck_epoch_init(&epoch); for (i = 0; i < n_rd; i++) pthread_create(threads + i, NULL, read_thread, NULL); do { pthread_create(threads + i, NULL, write_thread, NULL); } while (++i < n_wr + n_rd); common_sleep(10); ck_pr_store_uint(&leave, 1); for (i = 0; i < n_threads; i++) pthread_join(threads[i], NULL); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_epoch/validate/ck_epoch_synchronize.c ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" static unsigned int n_rd; static unsigned int n_wr; static unsigned int n_threads; static unsigned int barrier; static unsigned int e_barrier; static unsigned int readers; static unsigned int writers; #ifndef PAIRS_S #define PAIRS_S 10000 #endif #ifndef ITERATE_S #define ITERATE_S 20 #endif struct node { unsigned int value; ck_stack_entry_t stack_entry; ck_epoch_entry_t epoch_entry; }; static ck_stack_t stack = CK_STACK_INITIALIZER; static ck_epoch_t stack_epoch; CK_STACK_CONTAINER(struct node, stack_entry, stack_container) CK_EPOCH_CONTAINER(struct node, epoch_entry, epoch_container) static struct affinity a; static const char animate[] = "-/|\\"; static void destructor(ck_epoch_entry_t *p) { struct node *e = epoch_container(p); free(e); return; } static void * read_thread(void *unused CK_CC_UNUSED) { unsigned int j; ck_epoch_record_t record CK_CC_CACHELINE; ck_stack_entry_t *cursor; ck_stack_entry_t *n; unsigned int i; ck_epoch_register(&stack_epoch, &record, NULL); if (aff_iterate(&a)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < n_threads); while (CK_STACK_ISEMPTY(&stack) == true) { if (ck_pr_load_uint(&readers) != 0) break; ck_pr_stall(); } j = 0; for (;;) { i = 0; ck_epoch_begin(&record, NULL); CK_STACK_FOREACH(&stack, cursor) { if (cursor == NULL) continue; n = CK_STACK_NEXT(cursor); j += ck_pr_load_ptr(&n) != NULL; if (i++ > 4098) break; } ck_epoch_end(&record, NULL); if (j != 0 && ck_pr_load_uint(&readers) == 0) ck_pr_store_uint(&readers, 1); if (CK_STACK_ISEMPTY(&stack) == true && ck_pr_load_uint(&e_barrier) != 0) break; } ck_pr_inc_uint(&e_barrier); while (ck_pr_load_uint(&e_barrier) < n_threads); fprintf(stderr, "[R] Observed entries: %u\n", j); return (NULL); } static void * write_thread(void *unused CK_CC_UNUSED) { struct node **entry, *e; unsigned int i, j, tid; ck_epoch_record_t record; ck_stack_entry_t *s; ck_epoch_register(&stack_epoch, &record, NULL); if (aff_iterate(&a)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } tid = ck_pr_faa_uint(&writers, 1); ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < n_threads); entry = malloc(sizeof(struct node *) * PAIRS_S); if (entry == NULL) { ck_error("Failed allocation.\n"); } for (j = 0; j < ITERATE_S; j++) { for (i = 0; i < PAIRS_S; i++) { entry[i] = malloc(sizeof(struct node)); if (entry == NULL) { ck_error("Failed individual allocation\n"); } } for (i = 0; i < PAIRS_S; i++) { ck_stack_push_upmc(&stack, &entry[i]->stack_entry); } while (ck_pr_load_uint(&readers) == 0) ck_pr_stall(); for (i = 0; i < PAIRS_S; i++) { ck_epoch_begin(&record, NULL); s = ck_stack_pop_upmc(&stack); e = stack_container(s); ck_epoch_end(&record, NULL); if (i & 1) { ck_epoch_synchronize(&record); ck_epoch_reclaim(&record); ck_epoch_call(&record, &e->epoch_entry, destructor); } else { ck_epoch_barrier(&record); destructor(&e->epoch_entry); } if (tid == 0 && (i % 16384) == 0) { fprintf(stderr, "[W] %2.2f: %c\n", (double)j / ITERATE_S, animate[i % strlen(animate)]); } } } ck_epoch_synchronize(&record); if (tid == 0) { fprintf(stderr, "[W] Peak: %u (%2.2f%%)\n Reclamations: %u\n\n", record.n_peak, (double)record.n_peak / ((double)PAIRS_S * ITERATE_S) * 100, record.n_dispatch); } ck_pr_inc_uint(&e_barrier); while (ck_pr_load_uint(&e_barrier) < n_threads); return (NULL); } int main(int argc, char *argv[]) { unsigned int i; pthread_t *threads; if (argc != 4) { ck_error("Usage: stack <#readers> <#writers> \n"); } n_rd = atoi(argv[1]); n_wr = atoi(argv[2]); n_threads = n_wr + n_rd; a.delta = atoi(argv[3]); a.request = 0; threads = malloc(sizeof(pthread_t) * n_threads); ck_epoch_init(&stack_epoch); for (i = 0; i < n_rd; i++) pthread_create(threads + i, NULL, read_thread, NULL); do { pthread_create(threads + i, NULL, write_thread, NULL); } while (++i < n_wr + n_rd); for (i = 0; i < n_threads; i++) pthread_join(threads[i], NULL); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_epoch/validate/ck_stack.c ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" static unsigned int n_threads; static unsigned int barrier; static unsigned int e_barrier; #ifndef PAIRS #define PAIRS 5000000 #endif struct node { unsigned int value; ck_epoch_entry_t epoch_entry; ck_stack_entry_t stack_entry; }; static ck_stack_t stack = {NULL, NULL}; static ck_epoch_t stack_epoch; CK_STACK_CONTAINER(struct node, stack_entry, stack_container) CK_EPOCH_CONTAINER(struct node, epoch_entry, epoch_container) static struct affinity a; static void destructor(ck_epoch_entry_t *p) { struct node *e = epoch_container(p); free(e); return; } static void * thread(void *unused CK_CC_UNUSED) { struct node **entry, *e; ck_epoch_record_t record; ck_stack_entry_t *s; unsigned long smr = 0; unsigned int i; ck_epoch_register(&stack_epoch, &record, NULL); if (aff_iterate(&a)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } entry = malloc(sizeof(struct node *) * PAIRS); if (entry == NULL) { ck_error("Failed allocation.\n"); } for (i = 0; i < PAIRS; i++) { entry[i] = malloc(sizeof(struct node)); if (entry == NULL) { ck_error("Failed individual allocation\n"); } } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < n_threads); for (i = 0; i < PAIRS; i++) { ck_epoch_begin(&record, NULL); ck_stack_push_upmc(&stack, &entry[i]->stack_entry); s = ck_stack_pop_upmc(&stack); ck_epoch_end(&record, NULL); e = stack_container(s); ck_epoch_call(&record, &e->epoch_entry, destructor); smr += ck_epoch_poll(&record) == false; } ck_pr_inc_uint(&e_barrier); while (ck_pr_load_uint(&e_barrier) < n_threads); fprintf(stderr, "Deferrals: %lu (%2.2f)\n", smr, (double)smr / PAIRS); fprintf(stderr, "Peak: %u (%2.2f%%), %u pending\nReclamations: %u\n\n", record.n_peak, (double)record.n_peak / PAIRS * 100, record.n_pending, record.n_dispatch); ck_epoch_barrier(&record); ck_pr_inc_uint(&e_barrier); while (ck_pr_load_uint(&e_barrier) < (n_threads << 1)); if (record.n_pending != 0) { ck_error("ERROR: %u pending, expecting none.\n", record.n_pending); } return (NULL); } int main(int argc, char *argv[]) { unsigned int i; pthread_t *threads; if (argc != 3) { ck_error("Usage: stack \n"); } n_threads = atoi(argv[1]); a.delta = atoi(argv[2]); a.request = 0; threads = malloc(sizeof(pthread_t) * n_threads); ck_epoch_init(&stack_epoch); for (i = 0; i < n_threads; i++) pthread_create(threads + i, NULL, thread, NULL); for (i = 0; i < n_threads; i++) pthread_join(threads[i], NULL); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_epoch/validate/torture.c ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" static unsigned int n_rd; static unsigned int n_wr; static unsigned int n_threads; static unsigned int barrier; static unsigned int leave; static unsigned int first; struct { unsigned int value; } valid CK_CC_CACHELINE = { 1 }; struct { unsigned int value; } invalid CK_CC_CACHELINE; #ifndef PAIRS_S #define PAIRS_S 10000 #endif #ifndef CK_EPOCH_T_DEPTH #define CK_EPOCH_T_DEPTH 8 #endif static ck_epoch_t epoch; static struct affinity a; static void test(struct ck_epoch_record *record) { unsigned int j[3]; unsigned int b, c; const unsigned int r = 100; size_t i; for (i = 0; i < 8; i++) { ck_epoch_begin(record, NULL); c = ck_pr_load_uint(&invalid.value); ck_pr_fence_load(); b = ck_pr_load_uint(&valid.value); ck_test(c > b, "Invalid value: %u > %u\n", c, b); ck_epoch_end(record, NULL); } ck_epoch_begin(record, NULL); /* This implies no early load of epoch occurs. */ j[0] = record->epoch; /* We should observe up to one epoch migration. */ do { ck_pr_fence_load(); j[1] = ck_pr_load_uint(&epoch.epoch); if (ck_pr_load_uint(&leave) == 1) { ck_epoch_end(record, NULL); return; } } while (j[1] == j[0]); /* No more epoch migrations should occur */ for (i = 0; i < r; i++) { ck_pr_fence_strict_load(); j[2] = ck_pr_load_uint(&epoch.epoch); ck_test(j[2] != j[1], "Inconsistency detected: %u %u %u\n", j[0], j[1], j[2]); } ck_epoch_end(record, NULL); return; } static void * read_thread(void *unused CK_CC_UNUSED) { ck_epoch_record_t *record; record = malloc(sizeof *record); assert(record != NULL); ck_epoch_register(&epoch, record, NULL); if (aff_iterate(&a)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < n_threads); do { test(record); test(record); test(record); test(record); } while (ck_pr_load_uint(&leave) == 0); ck_pr_dec_uint(&n_rd); return NULL; } static void * write_thread(void *unused CK_CC_UNUSED) { ck_epoch_record_t *record; unsigned long iterations = 0; bool c = ck_pr_faa_uint(&first, 1); uint64_t ac = 0; record = malloc(sizeof *record); assert(record != NULL); ck_epoch_register(&epoch, record, NULL); if (aff_iterate(&a)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < n_threads); #define CK_EPOCH_S do { \ uint64_t _s = rdtsc(); \ ck_epoch_synchronize(record); \ ac += rdtsc() - _s; \ } while (0) do { /* * A thread should never observe invalid.value > valid.value. * inside a protected section. Only * invalid.value <= valid.value is valid. */ if (!c) ck_pr_store_uint(&valid.value, 1); CK_EPOCH_S; if (!c) ck_pr_store_uint(&invalid.value, 1); ck_pr_fence_store(); if (!c) ck_pr_store_uint(&valid.value, 2); CK_EPOCH_S; if (!c) ck_pr_store_uint(&invalid.value, 2); ck_pr_fence_store(); if (!c) ck_pr_store_uint(&valid.value, 3); CK_EPOCH_S; if (!c) ck_pr_store_uint(&invalid.value, 3); ck_pr_fence_store(); if (!c) ck_pr_store_uint(&valid.value, 4); CK_EPOCH_S; if (!c) ck_pr_store_uint(&invalid.value, 4); CK_EPOCH_S; if (!c) ck_pr_store_uint(&invalid.value, 0); CK_EPOCH_S; iterations += 6; } while (ck_pr_load_uint(&leave) == 0 && ck_pr_load_uint(&n_rd) > 0); fprintf(stderr, "%lu iterations\n", iterations); fprintf(stderr, "%" PRIu64 " average latency\n", ac / iterations); return NULL; } int main(int argc, char *argv[]) { unsigned int i; pthread_t *threads; if (argc != 4) { ck_error("Usage: stack <#readers> <#writers> \n"); } n_rd = atoi(argv[1]); n_wr = atoi(argv[2]); n_threads = n_wr + n_rd; a.delta = atoi(argv[3]); a.request = 0; threads = malloc(sizeof(pthread_t) * n_threads); ck_epoch_init(&epoch); for (i = 0; i < n_rd; i++) pthread_create(threads + i, NULL, read_thread, NULL); do { pthread_create(threads + i, NULL, write_thread, NULL); } while (++i < n_wr + n_rd); common_sleep(30); ck_pr_store_uint(&leave, 1); for (i = 0; i < n_threads; i++) pthread_join(threads[i], NULL); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_fifo/benchmark/latency.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "../../common.h" #ifndef ENTRIES #define ENTRIES 4096 #endif #ifndef STEPS #define STEPS 40000 #endif int main(void) { ck_spinlock_fas_t mutex = CK_SPINLOCK_FAS_INITIALIZER; void *r; uint64_t s, e, a; unsigned int i; unsigned int j; #if defined(CK_F_FIFO_SPSC) ck_fifo_spsc_t spsc_fifo; ck_fifo_spsc_entry_t spsc_entry[ENTRIES]; ck_fifo_spsc_entry_t spsc_stub; #endif #if defined(CK_F_FIFO_MPMC) ck_fifo_mpmc_t mpmc_fifo; ck_fifo_mpmc_entry_t mpmc_entry[ENTRIES]; ck_fifo_mpmc_entry_t mpmc_stub; ck_fifo_mpmc_entry_t *garbage; #endif #ifdef CK_F_FIFO_SPSC a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_spsc_init(&spsc_fifo, &spsc_stub); s = rdtsc(); for (j = 0; j < ENTRIES; j++) { ck_spinlock_fas_lock(&mutex); ck_fifo_spsc_enqueue(&spsc_fifo, spsc_entry + j, NULL); ck_spinlock_fas_unlock(&mutex); } e = rdtsc(); a += e - s; } printf(" spinlock_enqueue: %16" PRIu64 "\n", a / STEPS / (sizeof(spsc_entry) / sizeof(*spsc_entry))); a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_spsc_init(&spsc_fifo, &spsc_stub); for (j = 0; j < ENTRIES; j++) ck_fifo_spsc_enqueue(&spsc_fifo, spsc_entry + j, NULL); s = rdtsc(); for (j = 0; j < ENTRIES; j++) { ck_spinlock_fas_lock(&mutex); ck_fifo_spsc_dequeue(&spsc_fifo, &r); ck_spinlock_fas_unlock(&mutex); } e = rdtsc(); a += e - s; } printf(" spinlock_dequeue: %16" PRIu64 "\n", a / STEPS / (sizeof(spsc_entry) / sizeof(*spsc_entry))); a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_spsc_init(&spsc_fifo, &spsc_stub); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_fifo_spsc_enqueue(&spsc_fifo, spsc_entry + j, NULL); e = rdtsc(); a += e - s; } printf("ck_fifo_spsc_enqueue: %16" PRIu64 "\n", a / STEPS / (sizeof(spsc_entry) / sizeof(*spsc_entry))); a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_spsc_init(&spsc_fifo, &spsc_stub); for (j = 0; j < ENTRIES; j++) ck_fifo_spsc_enqueue(&spsc_fifo, spsc_entry + j, NULL); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_fifo_spsc_dequeue(&spsc_fifo, &r); e = rdtsc(); a += e - s; } printf("ck_fifo_spsc_dequeue: %16" PRIu64 "\n", a / STEPS / (sizeof(spsc_entry) / sizeof(*spsc_entry))); #endif #ifdef CK_F_FIFO_MPMC a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_mpmc_init(&mpmc_fifo, &mpmc_stub); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_fifo_mpmc_enqueue(&mpmc_fifo, mpmc_entry + j, NULL); e = rdtsc(); a += e - s; } printf("ck_fifo_mpmc_enqueue: %16" PRIu64 "\n", a / STEPS / (sizeof(mpmc_entry) / sizeof(*mpmc_entry))); a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_mpmc_init(&mpmc_fifo, &mpmc_stub); for (j = 0; j < ENTRIES; j++) ck_fifo_mpmc_enqueue(&mpmc_fifo, mpmc_entry + j, NULL); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_fifo_mpmc_dequeue(&mpmc_fifo, &r, &garbage); e = rdtsc(); a += e - s; } printf("ck_fifo_mpmc_dequeue: %16" PRIu64 "\n", a / STEPS / (sizeof(mpmc_entry) / sizeof(*mpmc_entry))); #endif return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_fifo/validate/ck_fifo_mpmc.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "../../common.h" #ifdef CK_F_FIFO_MPMC #ifndef ITERATIONS #define ITERATIONS 128 #endif struct context { unsigned int tid; unsigned int previous; unsigned int next; }; struct entry { int tid; int value; }; static int nthr; #ifdef CK_F_FIFO_MPMC static ck_fifo_mpmc_t fifo CK_CC_CACHELINE; #endif static struct affinity a; static int size; static unsigned int barrier; static void * test(void *c) { #ifdef CK_F_FIFO_MPMC struct context *context = c; struct entry *entry; ck_fifo_mpmc_entry_t *fifo_entry, *garbage; int i, j; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < (unsigned int)nthr); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { fifo_entry = malloc(sizeof(ck_fifo_mpmc_entry_t)); entry = malloc(sizeof(struct entry)); entry->tid = context->tid; ck_fifo_mpmc_enqueue(&fifo, fifo_entry, entry); if (ck_fifo_mpmc_dequeue(&fifo, &entry, &garbage) == false) { ck_error("ERROR [%u] Queue should never be empty.\n", context->tid); } if (entry->tid < 0 || entry->tid >= nthr) { ck_error("ERROR [%u] Incorrect value in entry.\n", entry->tid); } } } for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { fifo_entry = malloc(sizeof(ck_fifo_mpmc_entry_t)); entry = malloc(sizeof(struct entry)); entry->tid = context->tid; while (ck_fifo_mpmc_tryenqueue(&fifo, fifo_entry, entry) == false) ck_pr_stall(); while (ck_fifo_mpmc_trydequeue(&fifo, &entry, &garbage) == false) ck_pr_stall(); if (entry->tid < 0 || entry->tid >= nthr) { ck_error("ERROR [%u] Incorrect value in entry when using try interface.\n", entry->tid); } } } #endif return (NULL); } int main(int argc, char *argv[]) { int i, r; struct context *context; ck_fifo_mpmc_entry_t *garbage; pthread_t *thread; if (argc != 4) { ck_error("Usage: validate \n"); } a.request = 0; a.delta = atoi(argv[2]); nthr = atoi(argv[1]); assert(nthr >= 1); size = atoi(argv[3]); assert(size > 0); context = malloc(sizeof(*context) * nthr); assert(context); thread = malloc(sizeof(pthread_t) * nthr); assert(thread); ck_fifo_mpmc_init(&fifo, malloc(sizeof(ck_fifo_mpmc_entry_t))); ck_fifo_mpmc_deinit(&fifo, &garbage); if (garbage == NULL) ck_error("ERROR: Expected non-NULL stub node on deinit.\n"); free(garbage); ck_fifo_mpmc_init(&fifo, malloc(sizeof(ck_fifo_mpmc_entry_t))); for (i = 0; i < nthr; i++) { context[i].tid = i; r = pthread_create(thread + i, NULL, test, context + i); assert(r == 0); } for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); return (0); } #else int main(void) { fprintf(stderr, "Unsupported.\n"); return 0; } #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_fifo/validate/ck_fifo_mpmc_iterator.c ================================================ /* * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #ifdef CK_F_FIFO_MPMC struct example { int x; }; static ck_fifo_mpmc_t mpmc_fifo; int main(void) { int i, length = 3; struct example *examples; ck_fifo_mpmc_entry_t *stub, *entries, *entry, *next; stub = malloc(sizeof(ck_fifo_mpmc_entry_t)); if (stub == NULL) exit(EXIT_FAILURE); ck_fifo_mpmc_init(&mpmc_fifo, stub); entries = malloc(sizeof(ck_fifo_mpmc_entry_t) * length); if (entries == NULL) exit(EXIT_FAILURE); examples = malloc(sizeof(struct example) * length); /* Need these for this unit test. */ if (examples == NULL) exit(EXIT_FAILURE); for (i = 0; i < length; ++i) { examples[i].x = i; ck_fifo_mpmc_enqueue(&mpmc_fifo, entries + i, examples + i); } puts("Testing CK_FIFO_MPMC_FOREACH."); CK_FIFO_MPMC_FOREACH(&mpmc_fifo, entry) { printf("Next value in fifo: %d\n", ((struct example *)entry->value)->x); } puts("Testing CK_FIFO_MPMC_FOREACH_SAFE."); CK_FIFO_MPMC_FOREACH_SAFE(&mpmc_fifo, entry, next) { if (entry->next.pointer != next) exit(EXIT_FAILURE); printf("Next value in fifo: %d\n", ((struct example *)entry->value)->x); } free(examples); free(entries); free(stub); return (0); } #else int main(void) { return (0); } #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_fifo/validate/ck_fifo_spsc.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "../../common.h" #ifndef ITERATIONS #define ITERATIONS 128 #endif struct context { unsigned int tid; unsigned int previous; unsigned int next; }; struct entry { int tid; int value; }; static int nthr; static ck_fifo_spsc_t *fifo; static struct affinity a; static int size; static unsigned int barrier; static void * test(void *c) { struct context *context = c; struct entry *entry; ck_fifo_spsc_entry_t *fifo_entry; int i, j; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } #ifdef DEBUG fprintf(stderr, "%p %u: %u -> %u\n", fifo+context->tid, context->tid, context->previous, context->tid); #endif if (context->tid == 0) { struct entry *entries; entries = malloc(sizeof(struct entry) * size); assert(entries != NULL); for (i = 0; i < size; i++) { entries[i].value = i; entries[i].tid = 0; fifo_entry = malloc(sizeof(ck_fifo_spsc_entry_t)); ck_fifo_spsc_enqueue(fifo + context->tid, fifo_entry, entries + i); } } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < (unsigned int)nthr); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { while (ck_fifo_spsc_dequeue(fifo + context->previous, &entry) == false); if (context->previous != (unsigned int)entry->tid) { ck_error("T [%u:%p] %u != %u\n", context->tid, (void *)entry, entry->tid, context->previous); } if (entry->value != j) { ck_error("V [%u:%p] %u != %u\n", context->tid, (void *)entry, entry->value, j); } entry->tid = context->tid; fifo_entry = ck_fifo_spsc_recycle(fifo + context->tid); if (fifo_entry == NULL) fifo_entry = malloc(sizeof(ck_fifo_spsc_entry_t)); ck_fifo_spsc_enqueue(fifo + context->tid, fifo_entry, entry); } } return (NULL); } int main(int argc, char *argv[]) { int i, r; struct context *context; pthread_t *thread; if (argc != 4) { ck_error("Usage: validate \n"); } a.request = 0; a.delta = atoi(argv[2]); nthr = atoi(argv[1]); assert(nthr >= 1); size = atoi(argv[3]); assert(size > 0); fifo = malloc(sizeof(ck_fifo_spsc_t) * nthr); assert(fifo); context = malloc(sizeof(*context) * nthr); assert(context); thread = malloc(sizeof(pthread_t) * nthr); assert(thread); for (i = 0; i < nthr; i++) { ck_fifo_spsc_entry_t *garbage; context[i].tid = i; if (i == 0) { context[i].previous = nthr - 1; context[i].next = i + 1; } else if (i == nthr - 1) { context[i].next = 0; context[i].previous = i - 1; } else { context[i].next = i + 1; context[i].previous = i - 1; } ck_fifo_spsc_init(fifo + i, malloc(sizeof(ck_fifo_spsc_entry_t))); ck_fifo_spsc_deinit(fifo + i, &garbage); if (garbage == NULL) ck_error("ERROR: Expected non-NULL stub node on deinit.\n"); free(garbage); ck_fifo_spsc_init(fifo + i, malloc(sizeof(ck_fifo_spsc_entry_t))); r = pthread_create(thread + i, NULL, test, context + i); assert(r == 0); } for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_fifo/validate/ck_fifo_spsc_iterator.c ================================================ /* * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include struct example { int x; }; static ck_fifo_spsc_t spsc_fifo; int main(void) { int i, length = 3; struct example *examples; ck_fifo_spsc_entry_t *stub, *entries, *entry, *next; stub = malloc(sizeof(ck_fifo_spsc_entry_t)); if (stub == NULL) exit(EXIT_FAILURE); ck_fifo_spsc_init(&spsc_fifo, stub); entries = malloc(sizeof(ck_fifo_spsc_entry_t) * length); if (entries == NULL) exit(EXIT_FAILURE); examples = malloc(sizeof(struct example) * length); /* Need these for this unit test. */ if (examples == NULL) exit(EXIT_FAILURE); for (i = 0; i < length; ++i) { examples[i].x = i; ck_fifo_spsc_enqueue(&spsc_fifo, entries + i, examples + i); } puts("Testing CK_FIFO_SPSC_FOREACH."); CK_FIFO_SPSC_FOREACH(&spsc_fifo, entry) { printf("Next value in fifo: %d\n", ((struct example *)entry->value)->x); } puts("Testing CK_FIFO_SPSC_FOREACH_SAFE."); CK_FIFO_SPSC_FOREACH_SAFE(&spsc_fifo, entry, next) { if (entry->next != next) exit(EXIT_FAILURE); printf("Next value in fifo: %d\n", ((struct example *)entry->value)->x); } free(examples); free(entries); free(stub); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_hp/benchmark/fifo_latency.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include "../../common.h" #ifndef ENTRIES #define ENTRIES 4096 #endif #ifndef STEPS #define STEPS 40000 #endif static ck_hp_fifo_t fifo; static ck_hp_t fifo_hp; int main(void) { void *r; uint64_t s, e, a; unsigned int i; unsigned int j; ck_hp_fifo_entry_t hp_entry[ENTRIES]; ck_hp_fifo_entry_t hp_stub; ck_hp_record_t record; ck_hp_init(&fifo_hp, CK_HP_FIFO_SLOTS_COUNT, 1000000, NULL); r = malloc(CK_HP_FIFO_SLOTS_SIZE); if (r == NULL) { ck_error("ERROR: Failed to allocate slots.\n"); } ck_hp_register(&fifo_hp, &record, r); a = 0; for (i = 0; i < STEPS; i++) { ck_hp_fifo_init(&fifo, &hp_stub); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_hp_fifo_enqueue_mpmc(&record, &fifo, hp_entry + j, NULL); e = rdtsc(); a += e - s; } printf("ck_hp_fifo_enqueue_mpmc: %16" PRIu64 "\n", a / STEPS / ENTRIES); a = 0; for (i = 0; i < STEPS; i++) { ck_hp_fifo_init(&fifo, &hp_stub); for (j = 0; j < ENTRIES; j++) ck_hp_fifo_enqueue_mpmc(&record, &fifo, hp_entry + j, NULL); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_hp_fifo_dequeue_mpmc(&record, &fifo, &r); e = rdtsc(); a += e - s; } printf("ck_hp_fifo_dequeue_mpmc: %16" PRIu64 "\n", a / STEPS / ENTRIES); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_hp/benchmark/stack_latency.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef ENTRIES #define ENTRIES 4096 #endif #ifndef STEPS #define STEPS 40000 #endif static ck_stack_t stack; static ck_hp_t stack_hp; int main(void) { ck_hp_record_t record; ck_stack_entry_t entry[ENTRIES]; uint64_t s, e, a; unsigned int i; unsigned int j; void *r; ck_hp_init(&stack_hp, CK_HP_STACK_SLOTS_COUNT, 1000000, NULL); r = malloc(CK_HP_STACK_SLOTS_SIZE); if (r == NULL) { ck_error("ERROR: Failed to allocate slots.\n"); } ck_hp_register(&stack_hp, &record, (void *)r); a = 0; for (i = 0; i < STEPS; i++) { ck_stack_init(&stack); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_hp_stack_push_mpmc(&stack, entry + j); e = rdtsc(); a += e - s; } printf("ck_hp_stack_push_mpmc: %16" PRIu64 "\n", a / STEPS / ENTRIES); a = 0; for (i = 0; i < STEPS; i++) { ck_stack_init(&stack); for (j = 0; j < ENTRIES; j++) ck_hp_stack_push_mpmc(&stack, entry + j); s = rdtsc(); for (j = 0; j < ENTRIES; j++) { r = ck_hp_stack_pop_mpmc(&record, &stack); } e = rdtsc(); a += e - s; } printf(" ck_hp_stack_pop_mpmc: %16" PRIu64 "\n", a / STEPS / ENTRIES); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_hp/validate/ck_hp_fifo.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "../../common.h" #ifndef ITERATIONS #define ITERATIONS 128 #endif struct context { unsigned int tid; unsigned int previous; unsigned int next; }; struct entry { int tid; int value; }; static ck_hp_fifo_t fifo; static ck_hp_t fifo_hp; static int nthr; static struct affinity a; static int size; static unsigned int barrier; static unsigned int e_barrier; static void * test(void *c) { struct context *context = c; struct entry *entry; ck_hp_fifo_entry_t *fifo_entry; ck_hp_record_t record; int i, j; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } ck_hp_register(&fifo_hp, &record, malloc(sizeof(void *) * 2)); ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < (unsigned int)nthr); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { fifo_entry = malloc(sizeof(ck_hp_fifo_entry_t)); entry = malloc(sizeof(struct entry)); entry->tid = context->tid; ck_hp_fifo_enqueue_mpmc(&record, &fifo, fifo_entry, entry); ck_pr_barrier(); fifo_entry = ck_hp_fifo_dequeue_mpmc(&record, &fifo, &entry); if (fifo_entry == NULL) { ck_error("ERROR [%u] Queue should never be empty.\n", context->tid); } ck_pr_barrier(); if (entry->tid < 0 || entry->tid >= nthr) { ck_error("ERROR [%u] Incorrect value in entry.\n", entry->tid); } ck_hp_free(&record, &fifo_entry->hazard, fifo_entry, fifo_entry); } } for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { fifo_entry = malloc(sizeof(ck_hp_fifo_entry_t)); entry = malloc(sizeof(struct entry)); entry->tid = context->tid; while (ck_hp_fifo_tryenqueue_mpmc(&record, &fifo, fifo_entry, entry) == false) ck_pr_stall(); while (fifo_entry = ck_hp_fifo_trydequeue_mpmc(&record, &fifo, &entry), fifo_entry == NULL) ck_pr_stall(); if (entry->tid < 0 || entry->tid >= nthr) { ck_error("ERROR [%u] Incorrect value in entry.\n", entry->tid); } ck_hp_free(&record, &fifo_entry->hazard, fifo_entry, fifo_entry); } } ck_pr_inc_uint(&e_barrier); while (ck_pr_load_uint(&e_barrier) < (unsigned int)nthr); return (NULL); } static void destructor(void *p) { free(p); return; } int main(int argc, char *argv[]) { int i, r; struct context *context; pthread_t *thread; int threshold; if (argc != 5) { ck_error("Usage: validate \n"); } a.delta = atoi(argv[2]); nthr = atoi(argv[1]); assert(nthr >= 1); size = atoi(argv[3]); assert(size > 0); threshold = atoi(argv[4]); assert(threshold > 0); context = malloc(sizeof(*context) * nthr); assert(context); thread = malloc(sizeof(pthread_t) * nthr); assert(thread); ck_hp_init(&fifo_hp, 2, threshold, destructor); ck_hp_fifo_init(&fifo, malloc(sizeof(ck_hp_fifo_entry_t))); ck_hp_fifo_entry_t *entry; ck_hp_fifo_deinit(&fifo, &entry); if (entry == NULL) ck_error("ERROR: Expected non-NULL stub node.\n"); free(entry); ck_hp_fifo_init(&fifo, malloc(sizeof(ck_hp_fifo_entry_t))); for (i = 0; i < nthr; i++) { context[i].tid = i; r = pthread_create(thread + i, NULL, test, context + i); assert(r == 0); } for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_hp/validate/ck_hp_fifo_donner.c ================================================ /* * Copyright 2012 Hendrik Donner * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "../../common.h" /* FIFO queue */ static ck_hp_fifo_t fifo; /* Hazard pointer global */ static ck_hp_t fifo_hp; /* thread local element count */ static unsigned long *count; static unsigned long thread_count; static unsigned int start_barrier; static unsigned int end_barrier; /* destructor for FIFO queue */ static void destructor(void *p) { free(p); return; } /* entry struct for FIFO queue entries */ struct entry { unsigned long value; }; /* function for thread */ static void * queue_50_50(void *elements) { struct entry *entry; ck_hp_fifo_entry_t *fifo_entry; ck_hp_record_t *record; void *slots; unsigned long j, element_count = *(unsigned long *)elements; unsigned int seed; record = malloc(sizeof(ck_hp_record_t)); assert(record); slots = malloc(CK_HP_FIFO_SLOTS_SIZE); assert(slots); /* different seed for each thread */ seed = 1337; /*(unsigned int) pthread_self(); */ /* * This subscribes the thread to the fifo_hp state using the thread-owned * record. * FIFO queue needs 2 hazard pointers. */ ck_hp_register(&fifo_hp, record, slots); /* start barrier */ ck_pr_inc_uint(&start_barrier); while (ck_pr_load_uint(&start_barrier) < thread_count + 1) ck_pr_stall(); /* 50/50 enqueue-dequeue */ for(j = 0; j < element_count; j++) { /* rand_r with thread local state should be thread safe */ if( 50 < (1+(int) (100.0*common_rand_r(&seed)/(RAND_MAX+1.0)))) { /* This is the container for the enqueued data. */ fifo_entry = malloc(sizeof(ck_hp_fifo_entry_t)); if (fifo_entry == NULL) { exit(EXIT_FAILURE); } /* This is the data. */ entry = malloc(sizeof(struct entry)); if (entry != NULL) { entry->value = j; } /* * Enqueue the value of the pointer entry into FIFO queue using the * container fifo_entry. */ ck_hp_fifo_enqueue_mpmc(record, &fifo, fifo_entry, entry); } else { /* * ck_hp_fifo_dequeue_mpmc will return a pointer to the first unused node and store * the value of the first pointer in the FIFO queue in entry. */ fifo_entry = ck_hp_fifo_dequeue_mpmc(record, &fifo, &entry); if (fifo_entry != NULL) { /* * Safely reclaim memory associated with fifo_entry. * This inserts garbage into a local list. Once the list (plist) reaches * a length of 100, ck_hp_free will attempt to reclaim all references * to objects on the list. */ ck_hp_free(record, &fifo_entry->hazard, fifo_entry, fifo_entry); } } } /* end barrier */ ck_pr_inc_uint(&end_barrier); while (ck_pr_load_uint(&end_barrier) < thread_count + 1) ck_pr_stall(); return NULL; } int main(int argc, char** argv) { ck_hp_fifo_entry_t *stub; unsigned long element_count, i; pthread_t *thr; if (argc != 3) { ck_error("Usage: cktest \n"); } /* Get element count from argument */ element_count = atoi(argv[2]); /* Get element count from argument */ thread_count = atoi(argv[1]); /* pthread handles */ thr = malloc(sizeof(pthread_t) * thread_count); /* array for local operation count */ count = malloc(sizeof(unsigned long *) * thread_count); /* * Initialize global hazard pointer safe memory reclamation to execute free() * when a fifo_entry is safe to be deleted. * Hazard pointer scan routine will be called when the thread local intern plist's * size exceed 100 entries. */ /* FIFO queue needs 2 hazard pointers */ ck_hp_init(&fifo_hp, CK_HP_FIFO_SLOTS_COUNT, 100, destructor); /* The FIFO requires one stub entry on initialization. */ stub = malloc(sizeof(ck_hp_fifo_entry_t)); /* Behavior is undefined if stub is NULL. */ if (stub == NULL) { exit(EXIT_FAILURE); } /* This is called once to initialize the fifo. */ ck_hp_fifo_init(&fifo, stub); /* Create threads */ for (i = 0; i < thread_count; i++) { count[i] = (element_count + i) / thread_count; if (pthread_create(&thr[i], NULL, queue_50_50, (void *) &count[i]) != 0) { exit(EXIT_FAILURE); } } /* start barrier */ ck_pr_inc_uint(&start_barrier); while (ck_pr_load_uint(&start_barrier) < thread_count + 1); /* end barrier */ ck_pr_inc_uint(&end_barrier); while (ck_pr_load_uint(&end_barrier) < thread_count + 1); /* Join threads */ for (i = 0; i < thread_count; i++) pthread_join(thr[i], NULL); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_hp/validate/ck_hp_stack.c ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" static unsigned int threshold; static unsigned int n_threads; static unsigned int barrier; static unsigned int e_barrier; #ifndef PAIRS #define PAIRS 5000000 #endif struct node { unsigned int value; ck_hp_hazard_t hazard; ck_stack_entry_t stack_entry; }; static ck_stack_t stack = {NULL, NULL}; static ck_hp_t stack_hp; CK_STACK_CONTAINER(struct node, stack_entry, stack_container) static struct affinity a; static void * thread(void *unused CK_CC_UNUSED) { struct node **entry, *e; unsigned int i; ck_hp_record_t record; void **pointers; ck_stack_entry_t *s; unused = NULL; pointers = malloc(sizeof(void *)); ck_hp_register(&stack_hp, &record, pointers); if (aff_iterate(&a)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } entry = malloc(sizeof(struct node *) * PAIRS); if (entry == NULL) { ck_error("Failed allocation.\n"); } for (i = 0; i < PAIRS; i++) { entry[i] = malloc(sizeof(struct node)); if (entry == NULL) { ck_error("Failed individual allocation\n"); } } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < n_threads) ck_pr_stall(); for (i = 0; i < PAIRS; i++) { ck_hp_stack_push_mpmc(&stack, &entry[i]->stack_entry); s = ck_hp_stack_pop_mpmc(&record, &stack); e = stack_container(s); ck_hp_free(&record, &e->hazard, e, s); } ck_pr_inc_uint(&e_barrier); while (ck_pr_load_uint(&e_barrier) < n_threads) ck_pr_stall(); fprintf(stderr, "Peak: %u (%2.2f%%)\nReclamations: %" PRIu64 "\n\n", record.n_peak, (double)record.n_peak / PAIRS * 100, record.n_reclamations); ck_hp_clear(&record); ck_hp_purge(&record); ck_pr_inc_uint(&e_barrier); while (ck_pr_load_uint(&e_barrier) < (n_threads << 1)); if (record.n_pending != 0) { ck_error("ERROR: %u pending, expecting none.\n", record.n_pending); } return (NULL); } static void destructor(void *p) { free(p); return; } int main(int argc, char *argv[]) { unsigned int i; pthread_t *threads; if (argc != 4) { ck_error("Usage: stack \n"); } n_threads = atoi(argv[1]); threshold = atoi(argv[2]); a.delta = atoi(argv[3]); a.request = 0; threads = malloc(sizeof(pthread_t) * n_threads); ck_hp_init(&stack_hp, 1, threshold, destructor); for (i = 0; i < n_threads; i++) pthread_create(threads + i, NULL, thread, NULL); for (i = 0; i < n_threads; i++) pthread_join(threads[i], NULL); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_hp/validate/nbds_haz_test.c ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * This is a unit test similar to the implementation in John Dybnis's nbds * test. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #define STACK_CONTAINER(T, M, N) CK_CC_CONTAINER(stack_entry_t, T, M, N) struct stack_entry { struct stack_entry *next; } CK_CC_ALIGN(8); typedef struct stack_entry stack_entry_t; struct stack { struct stack_entry *head; char *generation; } CK_CC_PACKED CK_CC_ALIGN(16); typedef struct stack hp_stack_t; static unsigned int threshold; static unsigned int n_threads; static unsigned int barrier; static unsigned int e_barrier; static unsigned int global_tid; static unsigned int pops; static unsigned int pushs; #ifndef PAIRS #define PAIRS 1000000 #endif struct node { unsigned int value; ck_hp_hazard_t hazard; stack_entry_t stack_entry; }; hp_stack_t stack = {NULL, NULL}; ck_hp_t stack_hp; STACK_CONTAINER(struct node, stack_entry, stack_container) static struct affinity a; /* * Stack producer operation safe for multiple unique producers and multiple consumers. */ CK_CC_INLINE static void stack_push_mpmc(struct stack *target, struct stack_entry *entry) { struct stack_entry *lstack; ck_backoff_t backoff = CK_BACKOFF_INITIALIZER; lstack = ck_pr_load_ptr(&target->head); ck_pr_store_ptr(&entry->next, lstack); ck_pr_fence_store(); while (ck_pr_cas_ptr_value(&target->head, lstack, entry, &lstack) == false) { ck_pr_store_ptr(&entry->next, lstack); ck_pr_fence_store(); ck_backoff_eb(&backoff); } return; } /* * Stack consumer operation safe for multiple unique producers and multiple consumers. */ CK_CC_INLINE static struct stack_entry * stack_pop_mpmc(ck_hp_record_t *record, struct stack *target) { struct stack_entry *entry; ck_backoff_t backoff = CK_BACKOFF_INITIALIZER; do { entry = ck_pr_load_ptr(&target->head); if (entry == NULL) return (NULL); ck_hp_set_fence(record, 0, entry); } while (entry != ck_pr_load_ptr(&target->head)); while (ck_pr_cas_ptr_value(&target->head, entry, entry->next, &entry) == false) { if (ck_pr_load_ptr(&entry) == NULL) break; ck_hp_set_fence(record, 0, entry); if (entry != ck_pr_load_ptr(&target->head)) continue; ck_backoff_eb(&backoff); } return (entry); } static void * thread(void *unused CK_CC_UNUSED) { struct node *entry, *e; unsigned int i; ck_hp_record_t record; void **pointers; stack_entry_t *s; unsigned int tid = ck_pr_faa_uint(&global_tid, 1) + 1; unsigned int r = (unsigned int)(tid + 1) * 0x5bd1e995; unused = NULL; pointers = malloc(sizeof(void *)); ck_hp_register(&stack_hp, &record, pointers); if (aff_iterate(&a)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < n_threads) ck_pr_stall(); for (i = 0; i < PAIRS; i++) { r ^= r << 6; r ^= r >> 21; r ^= r << 7; if (r & 0x1000) { entry = malloc(sizeof(struct node)); assert(entry); stack_push_mpmc(&stack, &entry->stack_entry); ck_pr_inc_uint(&pushs); } else { s = stack_pop_mpmc(&record, &stack); if (s == NULL) continue; e = stack_container(s); ck_hp_free(&record, &e->hazard, e, s); ck_pr_inc_uint(&pops); } } ck_pr_inc_uint(&e_barrier); while (ck_pr_load_uint(&e_barrier) < n_threads); return (NULL); } static void destructor(void *p) { free(p); return; } int main(int argc, char *argv[]) { unsigned int i; pthread_t *threads; if (argc != 4) { ck_error("Usage: stack \n"); } n_threads = atoi(argv[1]); threshold = atoi(argv[2]); a.delta = atoi(argv[3]); a.request = 0; threads = malloc(sizeof(pthread_t) * n_threads); ck_hp_init(&stack_hp, 1, threshold, destructor); for (i = 0; i < n_threads; i++) pthread_create(threads + i, NULL, thread, NULL); for (i = 0; i < n_threads; i++) pthread_join(threads[i], NULL); fprintf(stderr, "Push: %u\nPop: %u\n", pushs, pops); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_hp/validate/serial.c ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" struct entry { unsigned int value; ck_hp_hazard_t hazard; }; static void destructor(void *pointer) { fprintf(stderr, "Free %p\n", pointer); free(pointer); return; } int main(int argc, char *argv[]) { ck_hp_t state; ck_hp_record_t record[2]; void **pointers; struct entry *entry, *other; (void)argc; (void)argv; ck_hp_init(&state, 1, 1, destructor); pointers = malloc(sizeof(void *)); if (pointers == NULL) { ck_error("ERROR: Failed to allocate slot.\n"); } ck_hp_register(&state, &record[0], pointers); ck_hp_reclaim(&record[0]); entry = malloc(sizeof *entry); ck_hp_set(&record[0], 0, entry); ck_hp_reclaim(&record[0]); ck_hp_free(&record[0], &entry->hazard, entry, entry); ck_hp_reclaim(&record[0]); ck_hp_set(&record[0], 0, NULL); ck_hp_reclaim(&record[0]); entry = malloc(sizeof *entry); ck_hp_set(&record[0], 0, entry); ck_hp_reclaim(&record[0]); ck_hp_free(&record[0], &entry->hazard, entry, entry); ck_hp_reclaim(&record[0]); ck_hp_set(&record[0], 0, NULL); ck_hp_reclaim(&record[0]); pointers = malloc(sizeof(void *)); if (pointers == NULL) { ck_error("ERROR: Failed to allocate slot.\n"); } ck_hp_register(&state, &record[1], pointers); ck_hp_reclaim(&record[1]); entry = malloc(sizeof *entry); ck_hp_set(&record[1], 0, entry); ck_hp_reclaim(&record[1]); ck_hp_free(&record[1], &entry->hazard, entry, entry); ck_hp_reclaim(&record[1]); ck_hp_set(&record[1], 0, NULL); ck_hp_reclaim(&record[1]); printf("Allocating entry and freeing in other HP record...\n"); entry = malloc(sizeof *entry); entry->value = 42; ck_hp_set(&record[0], 0, entry); ck_hp_free(&record[1], &entry->hazard, entry, entry); ck_pr_store_uint(&entry->value, 1); other = malloc(sizeof *other); other->value = 24; ck_hp_set(&record[1], 0, other); ck_hp_free(&record[0], &other->hazard, other, other); ck_pr_store_uint(&other->value, 32); ck_hp_set(&record[0], 0, NULL); ck_hp_reclaim(&record[1]); ck_hp_set(&record[1], 0, NULL); ck_hp_reclaim(&record[0]); ck_hp_reclaim(&record[1]); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_hs/benchmark/apply.c ================================================ /* * Copyright 2014 Samy Al Bahra. * Copyright 2014 Backtrace I/O, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyrights * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyrights * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "../../common.h" #include "../../../src/ck_ht_hash.h" static ck_hs_t hs; static char **keys; static size_t keys_length = 0; static size_t keys_capacity = 128; static unsigned long global_seed; static void * hs_malloc(size_t r) { return malloc(r); } static void hs_free(void *p, size_t b, bool r) { (void)b; (void)r; free(p); return; } static struct ck_malloc my_allocator = { .malloc = hs_malloc, .free = hs_free }; static unsigned long hs_hash(const void *object, unsigned long seed) { const char *c = object; unsigned long h; h = (unsigned long)MurmurHash64A(c, strlen(c), seed); return h; } static bool hs_compare(const void *previous, const void *compare) { return strcmp(previous, compare) == 0; } static void set_destroy(void) { ck_hs_destroy(&hs); return; } static void set_init(unsigned int size, unsigned int mode) { if (ck_hs_init(&hs, CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC | mode, hs_hash, hs_compare, &my_allocator, size, global_seed) == false) { perror("ck_hs_init"); exit(EXIT_FAILURE); } return; } static size_t set_count(void) { return ck_hs_count(&hs); } static bool set_reset(void) { return ck_hs_reset(&hs); } static void * test_apply(void *key, void *closure) { (void)key; return closure; } static void run_test(const char *file, size_t r, unsigned int size, unsigned int mode) { FILE *fp; char buffer[512]; size_t i, j; unsigned int d = 0; uint64_t s, e, a, gp, agp; struct ck_hs_stat st; char **t; keys = malloc(sizeof(char *) * keys_capacity); assert(keys != NULL); fp = fopen(file, "r"); assert(fp != NULL); while (fgets(buffer, sizeof(buffer), fp) != NULL) { buffer[strlen(buffer) - 1] = '\0'; keys[keys_length++] = strdup(buffer); assert(keys[keys_length - 1] != NULL); if (keys_length == keys_capacity) { t = realloc(keys, sizeof(char *) * (keys_capacity *= 2)); assert(t != NULL); keys = t; } } t = realloc(keys, sizeof(char *) * keys_length); assert(t != NULL); keys = t; set_init(size, mode); for (i = 0; i < keys_length; i++) { unsigned long h = CK_HS_HASH(&hs, hs_hash, keys[i]); if (ck_hs_get(&hs, h, keys[i]) == false) { if (ck_hs_put(&hs, h, keys[i]) == false) ck_error("ERROR: Failed get to put workload.\n"); } else { d++; } } ck_hs_stat(&hs, &st); fprintf(stderr, "# %zu entries stored, %u duplicates, %u probe.\n", set_count(), d, st.probe_maximum); a = 0; for (j = 0; j < r; j++) { if (set_reset() == false) ck_error("ERROR: Failed to reset hash table.\n"); s = rdtsc(); for (i = 0; i < keys_length; i++) { unsigned long h = CK_HS_HASH(&hs, hs_hash, keys[i]); if (ck_hs_get(&hs, h, keys[i]) == false && ck_hs_put(&hs, h, keys[i]) == false) { ck_error("ERROR: Failed get to put workload.\n"); } } e = rdtsc(); a += e - s; } gp = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { if (set_reset() == false) ck_error("ERROR: Failed to reset hash table.\n"); s = rdtsc(); for (i = 0; i < keys_length; i++) { unsigned long h = CK_HS_HASH(&hs, hs_hash, keys[i]); if (ck_hs_apply(&hs, h, keys[i], test_apply, (void *)keys[i]) == false) ck_error("ERROR: Failed in apply workload.\n"); } e = rdtsc(); a += e - s; } agp = a / (r * keys_length); fclose(fp); for (i = 0; i < keys_length; i++) { free(keys[i]); } printf("Get to put: %" PRIu64 " ticks\n", gp); printf(" Apply: %" PRIu64 " ticks\n", agp); free(keys); keys_length = 0; set_destroy(); return; } int main(int argc, char *argv[]) { unsigned int r, size; common_srand48((long int)time(NULL)); if (argc < 2) { ck_error("Usage: ck_hs [ ]\n"); } r = 16; if (argc >= 3) r = atoi(argv[2]); size = 8; if (argc >= 4) size = atoi(argv[3]); global_seed = common_lrand48(); run_test(argv[1], r, size, 0); printf("\n==============================================\n" "Delete mode\n" "==============================================\n"); run_test(argv[1], r, size, CK_HS_MODE_DELETE); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_hs/benchmark/parallel_bytestring.c ================================================ /* * Copyright 2012 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyrights * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyrights * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "../../common.h" #include #include "../../../src/ck_ht_hash.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include static ck_hs_t hs CK_CC_CACHELINE; static char **keys; static size_t keys_length = 0; static size_t keys_capacity = 128; static ck_epoch_t epoch_hs; static ck_epoch_record_t epoch_wr; static int n_threads; static bool next_stage; enum state { HS_STATE_STOP = 0, HS_STATE_GET, HS_STATE_STRICT_REPLACEMENT, HS_STATE_DELETION, HS_STATE_REPLACEMENT, HS_STATE_COUNT }; static ck_spinlock_t mtx = CK_SPINLOCK_INITIALIZER; static struct affinity affinerator = AFFINITY_INITIALIZER; static uint64_t accumulator[HS_STATE_COUNT]; static int barrier[HS_STATE_COUNT]; static int state; struct hs_epoch { ck_epoch_entry_t epoch_entry; }; COMMON_ALARM_DECLARE_GLOBAL(hs_alarm, alarm_event, next_stage) static void alarm_handler(int s) { (void)s; next_stage = true; return; } static unsigned long hs_hash(const void *object, unsigned long seed) { const char *c = object; unsigned long h; h = (unsigned long)MurmurHash64A(c, strlen(c), seed); return h; } static bool hs_compare(const void *previous, const void *compare) { return strcmp(previous, compare) == 0; } static void hs_destroy(ck_epoch_entry_t *e) { free(e); return; } static void * hs_malloc(size_t r) { ck_epoch_entry_t *b; b = malloc(sizeof(*b) + r); return b + 1; } static void hs_free(void *p, size_t b, bool r) { struct hs_epoch *e = p; (void)b; if (r == true) { /* Destruction requires safe memory reclamation. */ ck_epoch_call(&epoch_wr, &(--e)->epoch_entry, hs_destroy); } else { free(--e); } return; } static struct ck_malloc my_allocator = { .malloc = hs_malloc, .free = hs_free }; static void set_init(void) { unsigned int mode = CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC; #ifdef HS_DELETE mode |= CK_HS_MODE_DELETE; #endif ck_epoch_init(&epoch_hs); ck_epoch_register(&epoch_hs, &epoch_wr, NULL); common_srand48((long int)time(NULL)); if (ck_hs_init(&hs, mode, hs_hash, hs_compare, &my_allocator, 65536, common_lrand48()) == false) { perror("ck_hs_init"); exit(EXIT_FAILURE); } return; } static bool set_remove(const char *value) { unsigned long h; h = CK_HS_HASH(&hs, hs_hash, value); return (bool)ck_hs_remove(&hs, h, value); } static bool set_replace(const char *value) { unsigned long h; void *previous; h = CK_HS_HASH(&hs, hs_hash, value); return ck_hs_set(&hs, h, value, &previous); } static bool set_swap(const char *value) { unsigned long h; void *previous; h = CK_HS_HASH(&hs, hs_hash, value); return ck_hs_fas(&hs, h, value, &previous); } static void * set_get(const char *value) { unsigned long h; void *v; h = CK_HS_HASH(&hs, hs_hash, value); v = ck_hs_get(&hs, h, value); return v; } static bool set_insert(const char *value) { unsigned long h; h = CK_HS_HASH(&hs, hs_hash, value); return ck_hs_put(&hs, h, value); } static size_t set_count(void) { return ck_hs_count(&hs); } static bool set_reset(void) { return ck_hs_reset(&hs); } static void * reader(void *unused) { size_t i; ck_epoch_record_t epoch_record; int state_previous = HS_STATE_STOP; int n_state = 0; uint64_t s, j, a; (void)unused; if (aff_iterate(&affinerator) != 0) perror("WARNING: Failed to affine thread"); s = j = a = 0; ck_epoch_register(&epoch_hs, &epoch_record, NULL); for (;;) { j++; ck_epoch_begin(&epoch_record, NULL); s = rdtsc(); for (i = 0; i < keys_length; i++) { char *r; r = set_get(keys[i]); if (r == NULL) { if (n_state == HS_STATE_STRICT_REPLACEMENT) { ck_error("ERROR: Did not find during replacement: %s\n", keys[i]); } continue; } if (strcmp(r, keys[i]) == 0) continue; ck_error("ERROR: Found invalid value: [%s] but expected [%s]\n", (char *)r, keys[i]); } a += rdtsc() - s; ck_epoch_end(&epoch_record, NULL); n_state = ck_pr_load_int(&state); if (n_state != state_previous) { ck_spinlock_lock(&mtx); accumulator[state_previous] += a / (j * keys_length); ck_spinlock_unlock(&mtx); ck_pr_inc_int(&barrier[state_previous]); while (ck_pr_load_int(&barrier[state_previous]) != n_threads + 1) ck_pr_stall(); state_previous = n_state; s = j = a = 0; } } return NULL; } static uint64_t acc(size_t i) { uint64_t r; ck_spinlock_lock(&mtx); r = accumulator[i]; ck_spinlock_unlock(&mtx); return r; } int main(int argc, char *argv[]) { FILE *fp; char buffer[512]; size_t i, j, r; unsigned int d = 0; uint64_t s, e, a, repeated; char **t; pthread_t *readers; double p_r, p_d; COMMON_ALARM_DECLARE_LOCAL(hs_alarm, alarm_event) r = 20; s = 8; p_d = 0.5; p_r = 0.5; n_threads = CORES - 1; if (argc < 2) { ck_error("Usage: parallel [ \n" " ]\n"); } if (argc >= 3) r = atoi(argv[2]); if (argc >= 4) s = (uint64_t)atoi(argv[3]); if (argc >= 5) { n_threads = atoi(argv[4]); if (n_threads < 1) { ck_error("ERROR: Number of readers must be >= 1.\n"); } } if (argc >= 6) { p_r = atof(argv[5]) / 100.00; if (p_r < 0) { ck_error("ERROR: Probability of replacement must be >= 0 and <= 100.\n"); } } if (argc >= 7) { p_d = atof(argv[6]) / 100.00; if (p_d < 0) { ck_error("ERROR: Probability of deletion must be >= 0 and <= 100.\n"); } } COMMON_ALARM_INIT(hs_alarm, alarm_event, r) affinerator.delta = 1; readers = malloc(sizeof(pthread_t) * n_threads); assert(readers != NULL); keys = malloc(sizeof(char *) * keys_capacity); assert(keys != NULL); fp = fopen(argv[1], "r"); assert(fp != NULL); while (fgets(buffer, sizeof(buffer), fp) != NULL) { buffer[strlen(buffer) - 1] = '\0'; keys[keys_length++] = strdup(buffer); assert(keys[keys_length - 1] != NULL); if (keys_length == keys_capacity) { t = realloc(keys, sizeof(char *) * (keys_capacity *= 2)); assert(t != NULL); keys = t; } } t = realloc(keys, sizeof(char *) * keys_length); assert(t != NULL); keys = t; set_init(); for (i = 0; i < (size_t)n_threads; i++) { if (pthread_create(&readers[i], NULL, reader, NULL) != 0) { ck_error("ERROR: Failed to create thread %zu.\n", i); } } for (i = 0; i < keys_length; i++) d += set_insert(keys[i]) == false; fprintf(stderr, " [S] %d readers, 1 writer.\n", n_threads); fprintf(stderr, " [S] %zu entries stored and %u duplicates.\n\n", set_count(), d); fprintf(stderr, " ,- BASIC TEST\n"); fprintf(stderr, " | Executing SMR test..."); a = 0; for (j = 0; j < r; j++) { if (set_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = 0; i < keys_length; i++) d += set_insert(keys[i]) == false; e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing replacement test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_replace(keys[i]); e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing get test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { if (set_get(keys[i]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); a = 0; fprintf(stderr, " | Executing removal test..."); for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_remove(keys[i]); e = rdtsc(); a += e - s; for (i = 0; i < keys_length; i++) set_insert(keys[i]); } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing negative look-up test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { set_get("\x50\x03\x04\x05\x06\x10"); } e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); ck_epoch_record_t epoch_temporary = epoch_wr; ck_epoch_synchronize(&epoch_wr); fprintf(stderr, " '- Summary: %u pending, %u peak, %u reclamations -> " "%u pending, %u peak, %u reclamations\n\n", epoch_temporary.n_pending, epoch_temporary.n_peak, epoch_temporary.n_dispatch, epoch_wr.n_pending, epoch_wr.n_peak, epoch_wr.n_dispatch); fprintf(stderr, " ,- READER CONCURRENCY\n"); fprintf(stderr, " | Executing reader test..."); ck_pr_store_int(&state, HS_STATE_GET); while (ck_pr_load_int(&barrier[HS_STATE_STOP]) != n_threads) ck_pr_stall(); ck_pr_inc_int(&barrier[HS_STATE_STOP]); common_sleep(r); ck_pr_store_int(&state, HS_STATE_STRICT_REPLACEMENT); while (ck_pr_load_int(&barrier[HS_STATE_GET]) != n_threads) ck_pr_stall(); fprintf(stderr, "done (reader = %" PRIu64 " ticks)\n", acc(HS_STATE_GET) / n_threads); fprintf(stderr, " | Executing strict replacement test..."); a = repeated = 0; common_alarm(alarm_handler, &alarm_event, r); ck_pr_inc_int(&barrier[HS_STATE_GET]); for (;;) { repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) { if (i & 1) { set_replace(keys[i]); } else { set_swap(keys[i]); } } e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HS_STATE_DELETION); while (ck_pr_load_int(&barrier[HS_STATE_STRICT_REPLACEMENT]) != n_threads) ck_pr_stall(); set_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), acc(HS_STATE_STRICT_REPLACEMENT) / n_threads); common_alarm(alarm_handler, &alarm_event, r); fprintf(stderr, " | Executing deletion test (%.2f)...", p_d * 100); a = repeated = 0; ck_pr_inc_int(&barrier[HS_STATE_STRICT_REPLACEMENT]); for (;;) { double delete; repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) { set_insert(keys[i]); if (p_d != 0.0) { delete = common_drand48(); if (delete <= p_d) set_remove(keys[i]); } } e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HS_STATE_REPLACEMENT); while (ck_pr_load_int(&barrier[HS_STATE_DELETION]) != n_threads) ck_pr_stall(); set_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), acc(HS_STATE_DELETION) / n_threads); common_alarm(alarm_handler, &alarm_event, r); fprintf(stderr, " | Executing replacement test (%.2f)...", p_r * 100); a = repeated = 0; ck_pr_inc_int(&barrier[HS_STATE_DELETION]); for (;;) { double delete, replace; repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) { set_insert(keys[i]); if (p_d != 0.0) { delete = common_drand48(); if (delete <= p_d) set_remove(keys[i]); } else { delete = 0.0; } if (p_r != 0.0) { replace = common_drand48(); if (replace <= p_r) { if ((i & 1) || (delete <= p_d)) { set_replace(keys[i]); } else { set_swap(keys[i]); } } } } e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HS_STATE_STOP); while (ck_pr_load_int(&barrier[HS_STATE_REPLACEMENT]) != n_threads) ck_pr_stall(); set_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), acc(HS_STATE_REPLACEMENT) / n_threads); ck_pr_inc_int(&barrier[HS_STATE_REPLACEMENT]); epoch_temporary = epoch_wr; ck_epoch_synchronize(&epoch_wr); fprintf(stderr, " '- Summary: %u pending, %u peak, %u reclamations -> " "%u pending, %u peak, %u reclamations\n\n", epoch_temporary.n_pending, epoch_temporary.n_peak, epoch_temporary.n_dispatch, epoch_wr.n_pending, epoch_wr.n_peak, epoch_wr.n_dispatch); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_hs/benchmark/serial.c ================================================ /* * Copyright 2012 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyrights * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyrights * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "../../common.h" #include "../../../src/ck_ht_hash.h" static ck_hs_t hs; static char **keys; static size_t keys_length = 0; static size_t keys_capacity = 128; static unsigned long global_seed; static void * hs_malloc(size_t r) { return malloc(r); } static void hs_free(void *p, size_t b, bool r) { (void)b; (void)r; free(p); return; } static struct ck_malloc my_allocator = { .malloc = hs_malloc, .free = hs_free }; static unsigned long hs_hash(const void *object, unsigned long seed) { const char *c = object; unsigned long h; h = (unsigned long)MurmurHash64A(c, strlen(c), seed); return h; } static bool hs_compare(const void *previous, const void *compare) { return strcmp(previous, compare) == 0; } static void set_destroy(void) { ck_hs_destroy(&hs); return; } static void set_init(unsigned int size, unsigned int mode) { if (ck_hs_init(&hs, CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC | mode, hs_hash, hs_compare, &my_allocator, size, global_seed) == false) { perror("ck_hs_init"); exit(EXIT_FAILURE); } return; } static bool set_remove(const char *value) { unsigned long h; h = CK_HS_HASH(&hs, hs_hash, value); return ck_hs_remove(&hs, h, value) != NULL; } static bool set_swap(const char *value) { unsigned long h; void *previous; h = CK_HS_HASH(&hs, hs_hash, value); return ck_hs_fas(&hs, h, value, &previous); } static bool set_replace(const char *value) { unsigned long h; void *previous; h = CK_HS_HASH(&hs, hs_hash, value); ck_hs_set(&hs, h, value, &previous); return previous == value; } static void * set_get(const char *value) { unsigned long h; void *v; h = CK_HS_HASH(&hs, hs_hash, value); v = ck_hs_get(&hs, h, value); return v; } static bool set_insert(const char *value) { unsigned long h; h = CK_HS_HASH(&hs, hs_hash, value); return ck_hs_put(&hs, h, value); } static bool set_insert_unique(const char *value) { unsigned long h; h = CK_HS_HASH(&hs, hs_hash, value); return ck_hs_put_unique(&hs, h, value); } static size_t set_count(void) { return ck_hs_count(&hs); } static bool set_reset(void) { return ck_hs_reset(&hs); } static void set_gc(void) { ck_hs_gc(&hs, 0, 0); return; } static void set_rebuild(void) { ck_hs_rebuild(&hs); return; } static void keys_shuffle(char **k) { size_t i, j; char *t; for (i = keys_length; i > 1; i--) { j = rand() % (i - 1); if (j != i - 1) { t = k[i - 1]; k[i - 1] = k[j]; k[j] = t; } } return; } static void run_test(const char *file, size_t r, unsigned int size, unsigned int mode) { FILE *fp; char buffer[512]; size_t i, j; unsigned int d = 0; uint64_t s, e, a, ri, si, ai, sr, rg, sg, ag, sd, ng, ss, sts, su, sgc, sb; struct ck_hs_stat st; char **t; keys = malloc(sizeof(char *) * keys_capacity); assert(keys != NULL); fp = fopen(file, "r"); assert(fp != NULL); while (fgets(buffer, sizeof(buffer), fp) != NULL) { buffer[strlen(buffer) - 1] = '\0'; keys[keys_length++] = strdup(buffer); assert(keys[keys_length - 1] != NULL); if (keys_length == keys_capacity) { t = realloc(keys, sizeof(char *) * (keys_capacity *= 2)); assert(t != NULL); keys = t; } } t = realloc(keys, sizeof(char *) * keys_length); assert(t != NULL); keys = t; set_init(size, mode); for (i = 0; i < keys_length; i++) d += set_insert(keys[i]) == false; ck_hs_stat(&hs, &st); fprintf(stderr, "# %zu entries stored, %u duplicates, %u probe.\n", set_count(), d, st.probe_maximum); a = 0; for (j = 0; j < r; j++) { if (set_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = keys_length; i > 0; i--) d += set_insert(keys[i - 1]) == false; e = rdtsc(); a += e - s; } ri = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { if (set_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = 0; i < keys_length; i++) d += set_insert(keys[i]) == false; e = rdtsc(); a += e - s; } si = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { keys_shuffle(keys); if (set_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = 0; i < keys_length; i++) d += set_insert(keys[i]) == false; e = rdtsc(); a += e - s; } ai = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_swap(keys[i]); e = rdtsc(); a += e - s; } ss = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_replace(keys[i]); e = rdtsc(); a += e - s; } sr = a / (r * keys_length); set_reset(); for (i = 0; i < keys_length; i++) set_insert(keys[i]); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = keys_length; i > 0; i--) { if (set_get(keys[i - 1]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } rg = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { if (set_get(keys[i]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } sg = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { keys_shuffle(keys); s = rdtsc(); for (i = 0; i < keys_length; i++) { if (set_get(keys[i]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } ag = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_remove(keys[i]); e = rdtsc(); a += e - s; for (i = 0; i < keys_length; i++) set_insert(keys[i]); } sd = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { set_get("\x50\x03\x04\x05\x06\x10"); } e = rdtsc(); a += e - s; } ng = a / (r * keys_length); set_reset(); for (i = 0; i < keys_length; i++) set_insert(keys[i]); for (i = 0; i < keys_length; i++) set_remove(keys[i]); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_insert(keys[i]); e = rdtsc(); a += e - s; for (i = 0; i < keys_length; i++) set_remove(keys[i]); } sts = a / (r * keys_length); set_reset(); /* Prune duplicates. */ for (i = 0; i < keys_length; i++) { if (set_insert(keys[i]) == true) continue; free(keys[i]); keys[i] = keys[--keys_length]; } for (i = 0; i < keys_length; i++) set_remove(keys[i]); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_insert_unique(keys[i]); e = rdtsc(); a += e - s; for (i = 0; i < keys_length; i++) set_remove(keys[i]); } su = a / (r * keys_length); for (i = 0; i < keys_length; i++) set_insert_unique(keys[i]); for (i = 0; i < keys_length / 2; i++) set_remove(keys[i]); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); set_gc(); e = rdtsc(); a += e - s; } sgc = a / r; a = 0; for (j = 0; j < r; j++) { s = rdtsc(); set_rebuild(); e = rdtsc(); a += e - s; } sb = a / r; printf("%zu " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 "\n", keys_length, ri, si, ai, ss, sr, rg, sg, ag, sd, ng, sts, su, sgc, sb); fclose(fp); for (i = 0; i < keys_length; i++) { free(keys[i]); } free(keys); keys_length = 0; set_destroy(); return; } int main(int argc, char *argv[]) { unsigned int r, size; common_srand48((long int)time(NULL)); if (argc < 2) { ck_error("Usage: ck_hs [ ]\n"); } r = 16; if (argc >= 3) r = atoi(argv[2]); size = 8; if (argc >= 4) size = atoi(argv[3]); global_seed = common_lrand48(); run_test(argv[1], r, size, 0); run_test(argv[1], r, size, CK_HS_MODE_DELETE); fprintf(stderr, "# reverse_insertion serial_insertion random_insertion serial_swap " "serial_replace reverse_get serial_get random_get serial_remove negative_get tombstone " "set_unique gc rebuild\n\n"); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_hs/validate/serial.c ================================================ /* * Copyright 2012 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyrights * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyrights * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" static void * hs_malloc(size_t r) { return malloc(r); } static void hs_free(void *p, size_t b, bool r) { (void)b; (void)r; free(p); return; } static struct ck_malloc my_allocator = { .malloc = hs_malloc, .free = hs_free }; const char *test[] = { "Samy", "Al", "Bahra", "dances", "in", "the", "wind.", "Once", "upon", "a", "time", "his", "gypsy", "ate", "one", "itsy", "bitsy", "spider.", "What", "goes", "up", "must", "come", "down.", "What", "is", "down", "stays", "down.", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q" }; const char *negative = "negative"; /* Purposefully crappy hash function. */ static unsigned long hs_hash(const void *object, unsigned long seed) { const char *c = object; unsigned long h; (void)seed; h = c[0]; return h; } static bool hs_compare(const void *previous, const void *compare) { return strcmp(previous, compare) == 0; } static void * test_ip(void *key, void *closure) { const char *a = key; const char *b = closure; if (strcmp(a, b) != 0) ck_error("Mismatch: %s != %s\n", a, b); return closure; } static void * test_negative(void *key, void *closure) { (void)closure; if (key != NULL) ck_error("ERROR: Apply callback expects NULL argument instead of [%s]\n", key); return NULL; } static void * test_unique(void *key, void *closure) { if (key != NULL) ck_error("ERROR: Apply callback expects NULL argument instead of [%s]\n", key); return closure; } static void * test_remove(void *key, void *closure) { (void)key; (void)closure; return NULL; } static void run_test(unsigned int is, unsigned int ad) { ck_hs_t hs[16]; const size_t size = sizeof(hs) / sizeof(*hs); size_t i, j; const char *blob = "#blobs"; unsigned long h; ck_hs_iterator_t it; if (ck_hs_init(&hs[0], CK_HS_MODE_SPMC | CK_HS_MODE_OBJECT | ad, hs_hash, hs_compare, &my_allocator, is, 6602834) == false) ck_error("ck_hs_init\n"); for (j = 0; j < size; j++) { for (i = 0; i < sizeof(test) / sizeof(*test); i++) { h = test[i][0]; if (ck_hs_get(&hs[j], h, test[i]) != NULL) { continue; } if (i & 1) { if (ck_hs_put_unique(&hs[j], h, test[i]) == false) ck_error("ERROR [%zu]: Failed to insert unique (%s)\n", j, test[i]); } else if (ck_hs_apply(&hs[j], h, test[i], test_unique, (void *)(uintptr_t)test[i]) == false) { ck_error("ERROR: Failed to apply for insertion.\n"); } if (i & 1) { if (ck_hs_remove(&hs[j], h, test[i]) == false) ck_error("ERROR [%zu]: Failed to remove unique (%s)\n", j, test[i]); } else if (ck_hs_apply(&hs[j], h, test[i], test_remove, NULL) == false) { ck_error("ERROR: Failed to remove apply.\n"); } if (ck_hs_apply(&hs[j], h, test[i], test_negative, (char *)(uintptr_t)test[i]) == false) ck_error("ERROR: Failed to apply.\n"); break; } if (ck_hs_gc(&hs[j], 0, 0) == false) ck_error("ERROR: Failed to GC empty set.\n"); for (i = 0; i < sizeof(test) / sizeof(*test); i++) { h = test[i][0]; ck_hs_put(&hs[j], h, test[i]); if (ck_hs_put(&hs[j], h, test[i]) == true) { ck_error("ERROR [%u] [1]: put must fail on collision (%s).\n", is, test[i]); } if (ck_hs_get(&hs[j], h, test[i]) == NULL) { ck_error("ERROR [%u]: get must not fail after put\n", is); } } /* Test iteration */ if (j == 0) { // avoid the blob stuff as it's not in the test array ck_hs_iterator_init(&it); void *k = NULL; int matches = 0; int entries = 0; while(ck_hs_next(&hs[j], &it, &k)) { entries++; for (i = 0; i < sizeof(test) / sizeof(*test); i++) { int x = strcmp(test[i], (char *)k); if (x == 0) { matches++; break; } } } if (entries != matches) { ck_error("Iteration must match all elements, has: %d, matched: %d [%d]", entries, matches, is); } /* Now test iteration in the face of grows (spmc)*/ ck_hs_iterator_init(&it); k = NULL; matches = 0; entries = 0; while(ck_hs_next_spmc(&hs[j], &it, &k)) { entries++; for (i = 0; i < sizeof(test) / sizeof(*test); i++) { int x = strcmp(test[i], (char *)k); if (x == 0) { matches++; break; } } if (entries == 20) { ck_hs_grow(&hs[j], 128); } } if (entries != matches) { ck_error("After growth, iteration must match all elements, has: %d, matched: %d [%d]", entries, matches, is); } } /* Test grow semantics. */ ck_hs_grow(&hs[j], 128); for (i = 0; i < sizeof(test) / sizeof(*test); i++) { h = test[i][0]; if (ck_hs_put(&hs[j], h, test[i]) == true) { ck_error("ERROR [%u] [2]: put must fail on collision.\n", is); } if (ck_hs_get(&hs[j], h, test[i]) == NULL) { ck_error("ERROR [%u]: get must not fail\n", is); } } h = blob[0]; if (ck_hs_get(&hs[j], h, blob) == NULL) { if (j > 0) ck_error("ERROR [%u]: Blob must always exist after first.\n", is); if (ck_hs_put(&hs[j], h, blob) == false) { ck_error("ERROR [%u]: A unique blob put failed.\n", is); } } else { if (ck_hs_put(&hs[j], h, blob) == true) { ck_error("ERROR [%u]: Duplicate blob put succeeded.\n", is); } } /* Grow set and check get semantics. */ ck_hs_grow(&hs[j], 512); for (i = 0; i < sizeof(test) / sizeof(*test); i++) { h = test[i][0]; if (ck_hs_get(&hs[j], h, test[i]) == NULL) { ck_error("ERROR [%u]: get must not fail\n", is); } } /* Delete and check negative membership. */ for (i = 0; i < sizeof(test) / sizeof(*test); i++) { void *r; h = test[i][0]; if (ck_hs_get(&hs[j], h, test[i]) == NULL) continue; if (r = ck_hs_remove(&hs[j], h, test[i]), r == NULL) { ck_error("ERROR [%u]: remove must not fail\n", is); } if (strcmp(r, test[i]) != 0) { ck_error("ERROR [%u]: Removed incorrect node (%s != %s)\n", (char *)r, test[i], is); } } /* Test replacement semantics. */ for (i = 0; i < sizeof(test) / sizeof(*test); i++) { void *r; bool d; h = test[i][0]; d = ck_hs_get(&hs[j], h, test[i]) != NULL; if (ck_hs_set(&hs[j], h, test[i], &r) == false) { ck_error("ERROR [%u]: Failed to set\n", is); } /* Expected replacement. */ if (d == true && (r == NULL || strcmp(r, test[i]) != 0)) { ck_error("ERROR [%u]: Incorrect previous value: %s != %s\n", is, test[i], (char *)r); } /* Replacement should succeed. */ if (ck_hs_fas(&hs[j], h, test[i], &r) == false) ck_error("ERROR [%u]: ck_hs_fas must succeed.\n", is); if (strcmp(r, test[i]) != 0) { ck_error("ERROR [%u]: Incorrect replaced value: %s != %s\n", is, test[i], (char *)r); } if (ck_hs_fas(&hs[j], h, negative, &r) == true) ck_error("ERROR [%u]: Replacement of negative should fail.\n", is); if (ck_hs_set(&hs[j], h, test[i], &r) == false) { ck_error("ERROR [%u]: Failed to set [1]\n", is); } if (strcmp(r, test[i]) != 0) { ck_error("ERROR [%u]: Invalid &hs[j]: %s != %s\n", is, test[i], (char *)r); } /* Attempt in-place mutation. */ if (ck_hs_apply(&hs[j], h, test[i], test_ip, (void *)(uintptr_t)test[i]) == false) ck_error("ERROR [%u]: Failed to apply: %s != %s\n", is, (char *)r, test[i]); d = ck_hs_get(&hs[j], h, test[i]) != NULL; if (d == false) ck_error("ERROR [%u]: Expected [%s] to exist.\n", is, test[i]); } if (j == size - 1) break; if (ck_hs_move(&hs[j + 1], &hs[j], hs_hash, hs_compare, &my_allocator) == false) ck_error("Failed to move hash table"); if (j & 1) { ck_hs_gc(&hs[j + 1], 0, 0); } else { ck_hs_gc(&hs[j + 1], 26, 26); } if (ck_hs_rebuild(&hs[j + 1]) == false) ck_error("Failed to rebuild"); } return; } int main(void) { unsigned int k; for (k = 16; k <= 64; k <<= 1) { run_test(k, 0); run_test(k, CK_HS_MODE_DELETE); break; } return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_ht/benchmark/parallel_bytestring.c ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" static ck_ht_t ht CK_CC_CACHELINE; static char **keys; static size_t keys_length = 0; static size_t keys_capacity = 128; static ck_epoch_t epoch_ht; static ck_epoch_record_t epoch_wr; static int n_threads; static bool next_stage; enum state { HT_STATE_STOP = 0, HT_STATE_GET, HT_STATE_STRICT_REPLACEMENT, HT_STATE_DELETION, HT_STATE_REPLACEMENT, HT_STATE_COUNT }; static struct affinity affinerator = AFFINITY_INITIALIZER; static uint64_t accumulator[HT_STATE_COUNT]; static ck_spinlock_t accumulator_mutex = CK_SPINLOCK_INITIALIZER; static int barrier[HT_STATE_COUNT]; static int state; struct ht_epoch { ck_epoch_entry_t epoch_entry; }; COMMON_ALARM_DECLARE_GLOBAL(ht_alarm, alarm_event, next_stage) static void alarm_handler(int s) { (void)s; next_stage = true; return; } static void ht_destroy(ck_epoch_entry_t *e) { free(e); return; } static void * ht_malloc(size_t r) { ck_epoch_entry_t *b; b = malloc(sizeof(*b) + r); return b + 1; } static void ht_free(void *p, size_t b, bool r) { struct ht_epoch *e = p; (void)b; if (r == true) { /* Destruction requires safe memory reclamation. */ ck_epoch_call(&epoch_wr, &(--e)->epoch_entry, ht_destroy); } else { free(--e); } return; } static struct ck_malloc my_allocator = { .malloc = ht_malloc, .free = ht_free }; static void table_init(void) { unsigned int mode = CK_HT_MODE_BYTESTRING; #ifdef HT_DELETE mode |= CK_HT_WORKLOAD_DELETE; #endif ck_epoch_init(&epoch_ht); ck_epoch_register(&epoch_ht, &epoch_wr, NULL); common_srand48((long int)time(NULL)); if (ck_ht_init(&ht, mode, NULL, &my_allocator, 8, common_lrand48()) == false) { perror("ck_ht_init"); exit(EXIT_FAILURE); } return; } static bool table_remove(const char *value) { ck_ht_entry_t entry; ck_ht_hash_t h; size_t l = strlen(value); ck_ht_hash(&h, &ht, value, l); ck_ht_entry_key_set(&entry, value, l); return ck_ht_remove_spmc(&ht, h, &entry); } static bool table_replace(const char *value) { ck_ht_entry_t entry; ck_ht_hash_t h; size_t l = strlen(value); ck_ht_hash(&h, &ht, value, l); ck_ht_entry_set(&entry, h, value, l, "REPLACED"); return ck_ht_set_spmc(&ht, h, &entry); } static void * table_get(const char *value) { ck_ht_entry_t entry; ck_ht_hash_t h; size_t l = strlen(value); ck_ht_hash(&h, &ht, value, l); ck_ht_entry_key_set(&entry, value, l); if (ck_ht_get_spmc(&ht, h, &entry) == true) return ck_ht_entry_value(&entry); return NULL; } static bool table_insert(const char *value) { ck_ht_entry_t entry; ck_ht_hash_t h; size_t l = strlen(value); ck_ht_hash(&h, &ht, value, l); ck_ht_entry_set(&entry, h, value, l, value); return ck_ht_put_spmc(&ht, h, &entry); } static size_t table_count(void) { return ck_ht_count(&ht); } static bool table_reset(void) { return ck_ht_reset_spmc(&ht); } static void * reader(void *unused) { size_t i; ck_epoch_record_t epoch_record; int state_previous = HT_STATE_STOP; int n_state; uint64_t s, j, a; (void)unused; if (aff_iterate(&affinerator) != 0) perror("WARNING: Failed to affine thread"); s = j = a = 0; ck_epoch_register(&epoch_ht, &epoch_record, NULL); for (;;) { j++; ck_epoch_begin(&epoch_record, NULL); s = rdtsc(); for (i = 0; i < keys_length; i++) { char *r; r = table_get(keys[i]); if (r == NULL) continue; if (strcmp(r, "REPLACED") == 0) continue; if (strcmp(r, keys[i]) == 0) continue; ck_error("ERROR: Found invalid value: [%s] but expected [%s]\n", r, keys[i]); } a += rdtsc() - s; ck_epoch_end(&epoch_record, NULL); n_state = ck_pr_load_int(&state); if (n_state != state_previous) { ck_spinlock_lock(&accumulator_mutex); accumulator[state_previous] += a / (j * keys_length); ck_spinlock_unlock(&accumulator_mutex); ck_pr_inc_int(&barrier[state_previous]); while (ck_pr_load_int(&barrier[state_previous]) != n_threads + 1) ck_pr_stall(); state_previous = n_state; s = j = a = 0; } } return NULL; } int main(int argc, char *argv[]) { FILE *fp; char buffer[512]; size_t i, j, r; unsigned int d = 0; uint64_t s, e, a, repeated; char **t; pthread_t *readers; double p_r, p_d; COMMON_ALARM_DECLARE_LOCAL(ht_alarm, alarm_event) r = 20; s = 8; p_d = 0.5; p_r = 0.5; n_threads = CORES - 1; if (argc < 2) { ck_error("Usage: parallel [ \n" " ]\n"); } if (argc >= 3) r = atoi(argv[2]); if (argc >= 4) s = (uint64_t)atoi(argv[3]); if (argc >= 5) { n_threads = atoi(argv[4]); if (n_threads < 1) { ck_error("ERROR: Number of readers must be >= 1.\n"); } } if (argc >= 6) { p_r = atof(argv[5]) / 100.00; if (p_r < 0) { ck_error("ERROR: Probability of replacement must be >= 0 and <= 100.\n"); } } if (argc >= 7) { p_d = atof(argv[6]) / 100.00; if (p_d < 0) { ck_error("ERROR: Probability of deletion must be >= 0 and <= 100.\n"); } } COMMON_ALARM_INIT(ht_alarm, alarm_event, r) affinerator.delta = 1; readers = malloc(sizeof(pthread_t) * n_threads); assert(readers != NULL); keys = malloc(sizeof(char *) * keys_capacity); assert(keys != NULL); fp = fopen(argv[1], "r"); assert(fp != NULL); while (fgets(buffer, sizeof(buffer), fp) != NULL) { buffer[strlen(buffer) - 1] = '\0'; keys[keys_length++] = strdup(buffer); assert(keys[keys_length - 1] != NULL); if (keys_length == keys_capacity) { t = realloc(keys, sizeof(char *) * (keys_capacity *= 2)); assert(t != NULL); keys = t; } } t = realloc(keys, sizeof(char *) * keys_length); assert(t != NULL); keys = t; table_init(); for (i = 0; i < (size_t)n_threads; i++) { if (pthread_create(&readers[i], NULL, reader, NULL) != 0) { ck_error("ERROR: Failed to create thread %zu.\n", i); } } for (i = 0; i < keys_length; i++) d += table_insert(keys[i]) == false; fprintf(stderr, " [S] %d readers, 1 writer.\n", n_threads); fprintf(stderr, " [S] %zu entries stored and %u duplicates.\n\n", table_count(), d); fprintf(stderr, " ,- BASIC TEST\n"); fprintf(stderr, " | Executing SMR test..."); a = 0; for (j = 0; j < r; j++) { if (table_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = 0; i < keys_length; i++) d += table_insert(keys[i]) == false; e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing replacement test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) table_replace(keys[i]); e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing get test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { if (table_get(keys[i]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); a = 0; fprintf(stderr, " | Executing removal test..."); for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) table_remove(keys[i]); e = rdtsc(); a += e - s; for (i = 0; i < keys_length; i++) table_insert(keys[i]); } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing negative look-up test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { table_get("\x50\x03\x04\x05\x06\x10"); } e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); ck_epoch_record_t epoch_temporary = epoch_wr; ck_epoch_synchronize(&epoch_wr); fprintf(stderr, " '- Summary: %u pending, %u peak, %u reclamations -> " "%u pending, %u peak, %u reclamations\n\n", epoch_temporary.n_pending, epoch_temporary.n_peak, epoch_temporary.n_dispatch, epoch_wr.n_pending, epoch_wr.n_peak, epoch_wr.n_dispatch); fprintf(stderr, " ,- READER CONCURRENCY\n"); fprintf(stderr, " | Executing reader test..."); ck_pr_store_int(&state, HT_STATE_GET); while (ck_pr_load_int(&barrier[HT_STATE_STOP]) != n_threads) ck_pr_stall(); ck_pr_inc_int(&barrier[HT_STATE_STOP]); common_sleep(r); ck_pr_store_int(&state, HT_STATE_STRICT_REPLACEMENT); while (ck_pr_load_int(&barrier[HT_STATE_GET]) != n_threads) ck_pr_stall(); fprintf(stderr, "done (reader = %" PRIu64 " ticks)\n", accumulator[HT_STATE_GET] / n_threads); fprintf(stderr, " | Executing strict replacement test..."); a = repeated = 0; common_alarm(alarm_handler, &alarm_event, r); ck_pr_inc_int(&barrier[HT_STATE_GET]); for (;;) { repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) table_replace(keys[i]); e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HT_STATE_DELETION); while (ck_pr_load_int(&barrier[HT_STATE_STRICT_REPLACEMENT]) != n_threads) ck_pr_stall(); table_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), accumulator[HT_STATE_STRICT_REPLACEMENT] / n_threads); common_alarm(alarm_handler, &alarm_event, r); fprintf(stderr, " | Executing deletion test (%.2f)...", p_d * 100); a = repeated = 0; ck_pr_inc_int(&barrier[HT_STATE_STRICT_REPLACEMENT]); for (;;) { double delete; repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) { table_insert(keys[i]); if (p_d != 0.0) { delete = common_drand48(); if (delete <= p_d) table_remove(keys[i]); } } e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HT_STATE_REPLACEMENT); while (ck_pr_load_int(&barrier[HT_STATE_DELETION]) != n_threads) ck_pr_stall(); table_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), accumulator[HT_STATE_DELETION] / n_threads); common_alarm(alarm_handler, &alarm_event, r); fprintf(stderr, " | Executing replacement test (%.2f)...", p_r * 100); a = repeated = 0; ck_pr_inc_int(&barrier[HT_STATE_DELETION]); for (;;) { double replace, delete; repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) { table_insert(keys[i]); if (p_d != 0.0) { delete = common_drand48(); if (delete <= p_d) table_remove(keys[i]); } if (p_r != 0.0) { replace = common_drand48(); if (replace <= p_r) table_replace(keys[i]); } } e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HT_STATE_STOP); while (ck_pr_load_int(&barrier[HT_STATE_REPLACEMENT]) != n_threads) ck_pr_stall(); table_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), accumulator[HT_STATE_REPLACEMENT] / n_threads); ck_pr_inc_int(&barrier[HT_STATE_REPLACEMENT]); epoch_temporary = epoch_wr; ck_epoch_synchronize(&epoch_wr); fprintf(stderr, " '- Summary: %u pending, %u peak, %u reclamations -> " "%u pending, %u peak, %u reclamations\n\n", epoch_temporary.n_pending, epoch_temporary.n_peak, epoch_temporary.n_dispatch, epoch_wr.n_pending, epoch_wr.n_peak, epoch_wr.n_dispatch); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_ht/benchmark/parallel_direct.c ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" static ck_ht_t ht CK_CC_CACHELINE; static uintptr_t *keys; static size_t keys_length = 0; static ck_epoch_t epoch_ht; static ck_epoch_record_t epoch_wr; static int n_threads; static bool next_stage; enum state { HT_STATE_STOP = 0, HT_STATE_GET, HT_STATE_STRICT_REPLACEMENT, HT_STATE_DELETION, HT_STATE_REPLACEMENT, HT_STATE_COUNT }; static struct affinity affinerator = AFFINITY_INITIALIZER; static uint64_t accumulator[HT_STATE_COUNT]; static ck_spinlock_t accumulator_mutex = CK_SPINLOCK_INITIALIZER; static int barrier[HT_STATE_COUNT]; static int state; struct ht_epoch { ck_epoch_entry_t epoch_entry; }; COMMON_ALARM_DECLARE_GLOBAL(ht_alarm, alarm_event, next_stage) static void alarm_handler(int s) { (void)s; next_stage = true; return; } static void ht_destroy(ck_epoch_entry_t *e) { free(e); return; } static void * ht_malloc(size_t r) { ck_epoch_entry_t *b; b = malloc(sizeof(*b) + r); return b + 1; } static void ht_free(void *p, size_t b, bool r) { struct ht_epoch *e = p; (void)b; if (r == true) { /* Destruction requires safe memory reclamation. */ ck_epoch_call(&epoch_wr, &(--e)->epoch_entry, ht_destroy); } else { free(--e); } return; } static struct ck_malloc my_allocator = { .malloc = ht_malloc, .free = ht_free }; static void hash_function(ck_ht_hash_t *h, const void *key, size_t key_length, uint64_t seed) { const uintptr_t *value = key; (void)key_length; (void)seed; h->value = *value; return; } static void table_init(void) { ck_epoch_init(&epoch_ht); ck_epoch_register(&epoch_ht, &epoch_wr, NULL); common_srand48((long int)time(NULL)); if (ck_ht_init(&ht, CK_HT_MODE_DIRECT, hash_function, &my_allocator, 8, common_lrand48()) == false) { perror("ck_ht_init"); exit(EXIT_FAILURE); } return; } static bool table_remove(uintptr_t value) { ck_ht_entry_t entry; ck_ht_hash_t h; ck_ht_hash_direct(&h, &ht, value); ck_ht_entry_key_set_direct(&entry, value); return ck_ht_remove_spmc(&ht, h, &entry); } static bool table_replace(uintptr_t value) { ck_ht_entry_t entry; ck_ht_hash_t h; ck_ht_hash_direct(&h, &ht, value); ck_ht_entry_set_direct(&entry, h, value, 6605241); return ck_ht_set_spmc(&ht, h, &entry); } static uintptr_t table_get(uintptr_t value) { ck_ht_entry_t entry; ck_ht_hash_t h; ck_ht_hash_direct(&h, &ht, value); ck_ht_entry_key_set_direct(&entry, value); if (ck_ht_get_spmc(&ht, h, &entry) == true) return ck_ht_entry_value_direct(&entry); return 0; } static bool table_insert(uintptr_t value) { ck_ht_entry_t entry; ck_ht_hash_t h; ck_ht_hash_direct(&h, &ht, value); ck_ht_entry_set_direct(&entry, h, value, value); return ck_ht_put_spmc(&ht, h, &entry); } static size_t table_count(void) { return ck_ht_count(&ht); } static bool table_reset(void) { return ck_ht_reset_spmc(&ht); } static void * ht_reader(void *unused) { size_t i; ck_epoch_record_t epoch_record; int state_previous = HT_STATE_STOP; int n_state; uint64_t s, j, a; (void)unused; if (aff_iterate(&affinerator) != 0) perror("WARNING: Failed to affine thread"); s = j = a = 0; ck_epoch_register(&epoch_ht, &epoch_record, NULL); for (;;) { j++; ck_epoch_begin(&epoch_record, NULL); s = rdtsc(); for (i = 0; i < keys_length; i++) { uintptr_t r; r = table_get(keys[i]); if (r == 0) continue; if (r == 6605241) continue; if (r == keys[i]) continue; ck_error("ERROR: Found invalid value: [%ju]\n", (uintmax_t)r); } a += rdtsc() - s; ck_epoch_end(&epoch_record, NULL); n_state = ck_pr_load_int(&state); if (n_state != state_previous) { ck_spinlock_lock(&accumulator_mutex); accumulator[state_previous] += a / (j * keys_length); ck_spinlock_unlock(&accumulator_mutex); ck_pr_inc_int(&barrier[state_previous]); while (ck_pr_load_int(&barrier[state_previous]) != n_threads + 1) ck_pr_stall(); state_previous = n_state; s = j = a = 0; } } return NULL; } int main(int argc, char *argv[]) { size_t i, j, r; unsigned int d = 0; uint64_t s, e, a, repeated; pthread_t *readers; double p_r, p_d; COMMON_ALARM_DECLARE_LOCAL(ht_alarm, alarm_event) r = 20; s = 8; p_d = 0.5; p_r = 0.5; n_threads = CORES - 1; if (argc < 2) { fprintf(stderr, "Usage: parallel <#entries> [ \n" " ]\n"); exit(EXIT_FAILURE); } if (argc >= 3) r = atoi(argv[2]); if (argc >= 4) s = (uint64_t)atoi(argv[3]); if (argc >= 5) { n_threads = atoi(argv[4]); if (n_threads < 1) { ck_error("ERROR: Number of readers must be >= 1.\n"); } } if (argc >= 6) { p_r = atof(argv[5]) / 100.00; if (p_r < 0) { ck_error("ERROR: Probability of replacement must be >= 0 and <= 100.\n"); } } if (argc >= 7) { p_d = atof(argv[6]) / 100.00; if (p_d < 0) { ck_error("ERROR: Probability of deletion must be >= 0 and <= 100.\n"); } } COMMON_ALARM_INIT(ht_alarm, alarm_event, r) affinerator.delta = 1; readers = malloc(sizeof(pthread_t) * n_threads); assert(readers != NULL); keys_length = (size_t)atoi(argv[1]); keys = malloc(sizeof(uintptr_t) * keys_length); assert(keys != NULL); table_init(); for (i = 0; i < keys_length; i++) { keys[i] = (uintptr_t)common_lrand48(); while (keys[i] == 2) keys[i] = (uintptr_t)common_lrand48(); } for (i = 0; i < (size_t)n_threads; i++) { if (pthread_create(&readers[i], NULL, ht_reader, NULL) != 0) { ck_error("ERROR: Failed to create thread %zu.\n", i); } } for (i = 0; i < keys_length; i++) d += table_insert(keys[i]) == false; fprintf(stderr, " [S] %zu entries stored and %u duplicates.\n\n", table_count(), d); fprintf(stderr, " ,- BASIC TEST\n"); fprintf(stderr, " | Executing SMR test..."); a = 0; for (j = 0; j < r; j++) { if (table_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = 0; i < keys_length; i++) d += table_insert(keys[i]) == false; e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing replacement test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) table_replace(keys[i]); e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing get test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { if (table_get(keys[i]) == 0) { ck_error("ERROR: Unexpected 0 value.\n"); } } e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); a = 0; fprintf(stderr, " | Executing removal test..."); for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) table_remove(keys[i]); e = rdtsc(); a += e - s; for (i = 0; i < keys_length; i++) table_insert(keys[i]); } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing negative look-up test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { table_get(2); } e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); ck_epoch_record_t epoch_temporary = epoch_wr; ck_epoch_synchronize(&epoch_wr); fprintf(stderr, " '- Summary: %u pending, %u peak, %u reclamations -> " "%u pending, %u peak, %u reclamations\n\n", epoch_temporary.n_pending, epoch_temporary.n_peak, epoch_temporary.n_dispatch, epoch_wr.n_pending, epoch_wr.n_peak, epoch_wr.n_dispatch); fprintf(stderr, " ,- READER CONCURRENCY\n"); fprintf(stderr, " | Executing reader test..."); ck_pr_store_int(&state, HT_STATE_GET); while (ck_pr_load_int(&barrier[HT_STATE_STOP]) != n_threads) ck_pr_stall(); ck_pr_inc_int(&barrier[HT_STATE_STOP]); common_sleep(r); ck_pr_store_int(&state, HT_STATE_STRICT_REPLACEMENT); while (ck_pr_load_int(&barrier[HT_STATE_GET]) != n_threads) ck_pr_stall(); fprintf(stderr, "done (reader = %" PRIu64 " ticks)\n", accumulator[HT_STATE_GET] / n_threads); fprintf(stderr, " | Executing strict replacement test..."); a = repeated = 0; common_alarm(alarm_handler, &alarm_event, r); ck_pr_inc_int(&barrier[HT_STATE_GET]); for (;;) { repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) table_replace(keys[i]); e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HT_STATE_DELETION); while (ck_pr_load_int(&barrier[HT_STATE_STRICT_REPLACEMENT]) != n_threads) ck_pr_stall(); table_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), accumulator[HT_STATE_STRICT_REPLACEMENT] / n_threads); common_alarm(alarm_handler, &alarm_event, r); fprintf(stderr, " | Executing deletion test (%.2f)...", p_d * 100); a = repeated = 0; ck_pr_inc_int(&barrier[HT_STATE_STRICT_REPLACEMENT]); for (;;) { double delete; repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) { table_insert(keys[i]); if (p_d != 0.0) { delete = common_drand48(); if (delete <= p_d) table_remove(keys[i]); } } e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HT_STATE_REPLACEMENT); while (ck_pr_load_int(&barrier[HT_STATE_DELETION]) != n_threads) ck_pr_stall(); table_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), accumulator[HT_STATE_DELETION] / n_threads); common_alarm(alarm_handler, &alarm_event, r); fprintf(stderr, " | Executing replacement test (%.2f)...", p_r * 100); a = repeated = 0; ck_pr_inc_int(&barrier[HT_STATE_DELETION]); for (;;) { double replace, delete; repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) { table_insert(keys[i]); if (p_d != 0.0) { delete = common_drand48(); if (delete <= p_d) table_remove(keys[i]); } if (p_r != 0.0) { replace = common_drand48(); if (replace <= p_r) table_replace(keys[i]); } } e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HT_STATE_STOP); while (ck_pr_load_int(&barrier[HT_STATE_REPLACEMENT]) != n_threads) ck_pr_stall(); table_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), accumulator[HT_STATE_REPLACEMENT] / n_threads); ck_pr_inc_int(&barrier[HT_STATE_REPLACEMENT]); epoch_temporary = epoch_wr; ck_epoch_synchronize(&epoch_wr); fprintf(stderr, " '- Summary: %u pending, %u peak, %u reclamations -> " "%u pending, %u peak, %u reclamations\n\n", epoch_temporary.n_pending, epoch_temporary.n_peak, epoch_temporary.n_dispatch, epoch_wr.n_pending, epoch_wr.n_peak, epoch_wr.n_dispatch); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_ht/benchmark/serial.c ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "../../common.h" static ck_ht_t ht; static char **keys; static size_t keys_length = 0; static size_t keys_capacity = 128; static void * ht_malloc(size_t r) { return malloc(r); } static void ht_free(void *p, size_t b, bool r) { (void)b; (void)r; free(p); return; } static struct ck_malloc my_allocator = { .malloc = ht_malloc, .free = ht_free }; static void table_init(void) { unsigned int mode = CK_HT_MODE_BYTESTRING; #ifdef HT_DELETE mode |= CK_HT_WORKLOAD_DELETE; #endif common_srand48((long int)time(NULL)); if (ck_ht_init(&ht, mode, NULL, &my_allocator, 8, common_lrand48()) == false) { perror("ck_ht_init"); exit(EXIT_FAILURE); } return; } static bool table_remove(const char *value) { ck_ht_entry_t entry; ck_ht_hash_t h; size_t l = strlen(value); ck_ht_hash(&h, &ht, value, l); ck_ht_entry_key_set(&entry, value, l); return ck_ht_remove_spmc(&ht, h, &entry); } static bool table_replace(const char *value) { ck_ht_entry_t entry; ck_ht_hash_t h; size_t l = strlen(value); ck_ht_hash(&h, &ht, value, l); ck_ht_entry_set(&entry, h, value, l, "REPLACED"); return ck_ht_set_spmc(&ht, h, &entry); } static void * table_get(const char *value) { ck_ht_entry_t entry; ck_ht_hash_t h; size_t l = strlen(value); void *v = NULL; ck_ht_hash(&h, &ht, value, l); ck_ht_entry_key_set(&entry, value, l); if (ck_ht_get_spmc(&ht, h, &entry) == true) { v = ck_ht_entry_value(&entry); } return v; } static bool table_insert(const char *value) { ck_ht_entry_t entry; ck_ht_hash_t h; size_t l = strlen(value); ck_ht_hash(&h, &ht, value, l); ck_ht_entry_set(&entry, h, value, l, "VALUE"); return ck_ht_put_spmc(&ht, h, &entry); } static size_t table_count(void) { return ck_ht_count(&ht); } static bool table_gc(void) { return ck_ht_gc(&ht, 0, common_lrand48()); } static bool table_reset(void) { return ck_ht_reset_spmc(&ht); } static void keys_shuffle(char **k) { size_t i, j; char *t; for (i = keys_length; i > 1; i--) { j = rand() % (i - 1); if (j != i - 1) { t = k[i - 1]; k[i - 1] = k[j]; k[j] = t; } } return; } int main(int argc, char *argv[]) { FILE *fp; char buffer[512]; size_t i, j, r; unsigned int d = 0; uint64_t s, e, a, ri, si, ai, sr, rg, sg, ag, sd, ng, gg; char **t; struct ck_ht_stat st; r = 20; s = 8; srand(time(NULL)); if (argc < 2) { ck_error("Usage: ck_ht [ ]\n"); } if (argc >= 3) r = atoi(argv[2]); if (argc >= 4) s = (uint64_t)atoi(argv[3]); keys = malloc(sizeof(char *) * keys_capacity); assert(keys != NULL); fp = fopen(argv[1], "r"); assert(fp != NULL); while (fgets(buffer, sizeof(buffer), fp) != NULL) { buffer[strlen(buffer) - 1] = '\0'; keys[keys_length++] = strdup(buffer); assert(keys[keys_length - 1] != NULL); if (keys_length == keys_capacity) { t = realloc(keys, sizeof(char *) * (keys_capacity *= 2)); assert(t != NULL); keys = t; } } t = realloc(keys, sizeof(char *) * keys_length); assert(t != NULL); keys = t; table_init(); for (i = 0; i < keys_length; i++) d += table_insert(keys[i]) == false; ck_ht_stat(&ht, &st); fprintf(stderr, "# %zu entries stored, %u duplicates, %" PRIu64 " probe.\n", table_count(), d, st.probe_maximum); fprintf(stderr, "# reverse_insertion serial_insertion random_insertion serial_replace reverse_get serial_get random_get serial_remove negative_get garbage_collect\n\n"); a = 0; for (j = 0; j < r; j++) { if (table_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = keys_length; i > 0; i--) d += table_insert(keys[i - 1]) == false; e = rdtsc(); a += e - s; } ri = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { if (table_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = 0; i < keys_length; i++) d += table_insert(keys[i]) == false; e = rdtsc(); a += e - s; } si = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { keys_shuffle(keys); if (table_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = 0; i < keys_length; i++) d += table_insert(keys[i]) == false; e = rdtsc(); a += e - s; } ai = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) table_replace(keys[i]); e = rdtsc(); a += e - s; } sr = a / (r * keys_length); table_reset(); for (i = 0; i < keys_length; i++) table_insert(keys[i]); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = keys_length; i > 0; i--) { if (table_get(keys[i - 1]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } rg = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { if (table_get(keys[i]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } sg = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { keys_shuffle(keys); s = rdtsc(); for (i = 0; i < keys_length; i++) { if (table_get(keys[i]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } ag = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) table_remove(keys[i]); e = rdtsc(); a += e - s; for (i = 0; i < keys_length; i++) table_insert(keys[i]); } sd = a / (r * keys_length); for (i = 0; i < keys_length / 2; i++) table_remove(keys[i]); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); table_gc(); e = rdtsc(); a += e - s; } gg = a / r; a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { table_get("\x50\x03\x04\x05\x06\x10"); } e = rdtsc(); a += e - s; } ng = a / (r * keys_length); printf("%zu " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 "\n", keys_length, ri, si, ai, sr, rg, sg, ag, sd, ng, gg); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_ht/validate/serial.c ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #include "../../../src/ck_ht_hash.h" static size_t hash_times_called = 0; static void * ht_malloc(size_t r) { return malloc(r); } static void ht_free(void *p, size_t b, bool r) { (void)b; (void)r; free(p); return; } static void ht_hash_wrapper(struct ck_ht_hash *h, const void *key, size_t length, uint64_t seed) { hash_times_called++; h->value = (unsigned long)MurmurHash64A(key, length, seed); return; } static struct ck_malloc my_allocator = { .malloc = ht_malloc, .free = ht_free }; const char *test[] = {"Samy", "Al", "Bahra", "dances", "in", "the", "wind.", "Once", "upon", "a", "time", "his", "gypsy", "ate", "one", "itsy", "bitsy", "spider.", "What", "goes", "up", "must", "come", "down.", "What", "is", "down", "stays", "down.", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"}; static uintptr_t direct[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 1, 2, 3, 4, 5, 9 }; const char *negative = "negative"; int main(void) { size_t i, l; ck_ht_t ht; ck_ht_entry_t entry; ck_ht_hash_t h; ck_ht_iterator_t iterator = CK_HT_ITERATOR_INITIALIZER; ck_ht_entry_t *cursor; unsigned int mode = CK_HT_MODE_BYTESTRING; #ifdef HT_DELETE mode |= CK_HT_WORKLOAD_DELETE; #endif if (ck_ht_init(&ht, mode, ht_hash_wrapper, &my_allocator, 2, 6602834) == false) { perror("ck_ht_init"); exit(EXIT_FAILURE); } for (i = 0; i < sizeof(test) / sizeof(*test); i++) { l = strlen(test[i]); ck_ht_hash(&h, &ht, test[i], l); ck_ht_entry_set(&entry, h, test[i], l, test[i]); ck_ht_put_spmc(&ht, h, &entry); } l = strlen(test[0]); ck_ht_hash(&h, &ht, test[0], l); ck_ht_entry_set(&entry, h, test[0], l, test[0]); ck_ht_put_spmc(&ht, h, &entry); for (i = 0; i < sizeof(test) / sizeof(*test); i++) { l = strlen(test[i]); ck_ht_hash(&h, &ht, test[i], l); ck_ht_entry_key_set(&entry, test[i], l); if (ck_ht_get_spmc(&ht, h, &entry) == false) { ck_error("ERROR (put): Failed to find [%s]\n", test[i]); } else { void *k, *v; k = ck_ht_entry_key(&entry); v = ck_ht_entry_value(&entry); if (strcmp(k, test[i]) || strcmp(v, test[i])) { ck_error("ERROR: Mismatch: (%s, %s) != (%s, %s)\n", (char *)k, (char *)v, test[i], test[i]); } } } ck_ht_hash(&h, &ht, negative, strlen(negative)); ck_ht_entry_key_set(&entry, negative, strlen(negative)); if (ck_ht_get_spmc(&ht, h, &entry) == true) { ck_error("ERROR: Found non-existing entry.\n"); } for (i = 0; i < sizeof(test) / sizeof(*test); i++) { l = strlen(test[i]); ck_ht_hash(&h, &ht, test[i], l); ck_ht_entry_key_set(&entry, test[i], l); if (ck_ht_get_spmc(&ht, h, &entry) == false) continue; if (ck_ht_remove_spmc(&ht, h, &entry) == false) { ck_error("ERROR: Failed to delete existing entry\n"); } if (ck_ht_get_spmc(&ht, h, &entry) == true) ck_error("ERROR: Able to find [%s] after delete\n", test[i]); ck_ht_entry_set(&entry, h, test[i], l, test[i]); if (ck_ht_put_spmc(&ht, h, &entry) == false) ck_error("ERROR: Failed to insert [%s]\n", test[i]); if (ck_ht_remove_spmc(&ht, h, &entry) == false) { ck_error("ERROR: Failed to delete existing entry\n"); } } ck_ht_reset_spmc(&ht); if (ck_ht_count(&ht) != 0) { ck_error("ERROR: Map was not reset.\n"); } for (i = 0; i < sizeof(test) / sizeof(*test); i++) { l = strlen(test[i]); ck_ht_hash(&h, &ht, test[i], l); ck_ht_entry_set(&entry, h, test[i], l, test[i]); ck_ht_put_spmc(&ht, h, &entry); } for (i = 0; ck_ht_next(&ht, &iterator, &cursor) == true; i++); if (i != 42) { ck_error("ERROR: Incorrect number of entries in table.\n"); } for (i = 0; i < sizeof(test) / sizeof(*test); i++) { l = strlen(test[i]); ck_ht_hash(&h, &ht, test[i], l); ck_ht_entry_set(&entry, h, test[i], l, test[i]); ck_ht_set_spmc(&ht, h, &entry); } for (i = 0; i < sizeof(test) / sizeof(*test); i++) { l = strlen(test[i]); ck_ht_hash(&h, &ht, test[i], l); ck_ht_entry_key_set(&entry, test[i], l); if (ck_ht_get_spmc(&ht, h, &entry) == false) { ck_error("ERROR (set): Failed to find [%s]\n", test[i]); } else { void *k, *v; k = ck_ht_entry_key(&entry); v = ck_ht_entry_value(&entry); if (strcmp(k, test[i]) || strcmp(v, test[i])) { ck_error("ERROR: Mismatch: (%s, %s) != (%s, %s)\n", (char *)k, (char *)v, test[i], test[i]); } } } if (ck_ht_gc(&ht, 0, 27) == false) { ck_error("ck_ht_gc\n"); } for (i = 0; i < sizeof(test) / sizeof(*test); i++) { l = strlen(test[i]); ck_ht_hash(&h, &ht, test[i], l); ck_ht_entry_set(&entry, h, test[i], l, "REPLACED"); ck_ht_set_spmc(&ht, h, &entry); if (strcmp(test[i], "What") == 0) continue; if (strcmp(test[i], "down.") == 0) continue; if (strcmp(ck_ht_entry_value(&entry), test[i]) != 0) { ck_error("Mismatch detected: %s, expected %s\n", (char *)ck_ht_entry_value(&entry), test[i]); } } ck_ht_iterator_init(&iterator); while (ck_ht_next(&ht, &iterator, &cursor) == true) { if (strcmp(ck_ht_entry_value(cursor), "REPLACED") != 0) { ck_error("Mismatch detected: %s, expected REPLACED\n", (char *)ck_ht_entry_value(cursor)); } } for (i = 0; i < sizeof(test) / sizeof(*test); i++) { l = strlen(test[i]); ck_ht_hash(&h, &ht, test[i], l); ck_ht_entry_key_set(&entry, test[i], l); if (ck_ht_get_spmc(&ht, h, &entry) == false) continue; if (ck_ht_remove_spmc(&ht, h, &entry) == false) { ck_error("ERROR: Failed to delete existing entry\n"); } if (ck_ht_get_spmc(&ht, h, &entry) == true) ck_error("ERROR: Able to find [%s] after delete\n", test[i]); ck_ht_entry_set(&entry, h, test[i], l, test[i]); if (ck_ht_put_spmc(&ht, h, &entry) == false) ck_error("ERROR: Failed to insert [%s]\n", test[i]); if (ck_ht_remove_spmc(&ht, h, &entry) == false) { ck_error("ERROR: Failed to delete existing entry\n"); } } ck_ht_destroy(&ht); if (hash_times_called == 0) { ck_error("ERROR: Our hash function was not called!\n"); } hash_times_called = 0; if (ck_ht_init(&ht, CK_HT_MODE_DIRECT, ht_hash_wrapper, &my_allocator, 8, 6602834) == false) { perror("ck_ht_init"); exit(EXIT_FAILURE); } l = 0; for (i = 0; i < sizeof(direct) / sizeof(*direct); i++) { ck_ht_hash_direct(&h, &ht, direct[i]); ck_ht_entry_set_direct(&entry, h, direct[i], (uintptr_t)test[i]); l += ck_ht_put_spmc(&ht, h, &entry) == false; } if (l != 7) { ck_error("ERROR: Got %zu failures rather than 7\n", l); } for (i = 0; i < sizeof(direct) / sizeof(*direct); i++) { ck_ht_hash_direct(&h, &ht, direct[i]); ck_ht_entry_set_direct(&entry, h, direct[i], (uintptr_t)"REPLACED"); l += ck_ht_set_spmc(&ht, h, &entry) == false; } ck_ht_iterator_init(&iterator); while (ck_ht_next(&ht, &iterator, &cursor) == true) { if (strcmp(ck_ht_entry_value(cursor), "REPLACED") != 0) { ck_error("Mismatch detected: %s, expected REPLACED\n", (char *)ck_ht_entry_value(cursor)); } } ck_ht_destroy(&ht); if (hash_times_called == 0) { ck_error("ERROR: Our hash function was not called!\n"); } return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pflock/benchmark/latency.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2013 John Wittrock. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHEPFISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS 1000000 #endif int main(void) { uint64_t s_b, e_b, i; ck_pflock_t pflock = CK_PFLOCK_INITIALIZER; for (i = 0; i < STEPS; i++) { ck_pflock_write_lock(&pflock); ck_pflock_write_unlock(&pflock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_pflock_write_lock(&pflock); ck_pflock_write_unlock(&pflock); } e_b = rdtsc(); printf("WRITE: pflock %15" PRIu64 "\n", (e_b - s_b) / STEPS); for (i = 0; i < STEPS; i++) { ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); } e_b = rdtsc(); printf("READ: pflock %15" PRIu64 "\n", (e_b - s_b) / STEPS); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pflock/benchmark/throughput.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2013 John Wittrock. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHEPFISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS 1000000 #endif static int barrier; static int threads; static unsigned int flag CK_CC_CACHELINE; static ck_pflock_t pflock = CK_PFLOCK_INITIALIZER; static struct affinity affinity; static void * thread_pflock(void *pun) { uint64_t s_b, e_b, a, i; uint64_t *value = pun; if (aff_iterate(&affinity) != 0) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads) ck_pr_stall(); for (i = 1, a = 0;; i++) { s_b = rdtsc(); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); ck_pflock_read_lock(&pflock); ck_pflock_read_unlock(&pflock); e_b = rdtsc(); a += (e_b - s_b) >> 4; if (ck_pr_load_uint(&flag) == 1) break; } ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads * 2) ck_pr_stall(); *value = (a / i); return NULL; } int main(int argc, char *argv[]) { int t; pthread_t *p; uint64_t *latency; if (argc != 3) { ck_error("Usage: throughput \n"); } threads = atoi(argv[2]); if (threads <= 0) { ck_error("ERROR: Threads must be a value > 0.\n"); } p = malloc(sizeof(pthread_t) * threads); if (p == NULL) { ck_error("ERROR: Failed to initialize thread.\n"); } latency = malloc(sizeof(uint64_t) * threads); if (latency == NULL) { ck_error("ERROR: Failed to create latency buffer.\n"); } affinity.delta = atoi(argv[1]); affinity.request = 0; fprintf(stderr, "Creating threads (pflock)..."); for (t = 0; t < threads; t++) { if (pthread_create(&p[t], NULL, thread_pflock, latency + t) != 0) { ck_error("ERROR: Could not create thread %d\n", t); } } fprintf(stderr, "done\n"); common_sleep(10); ck_pr_store_uint(&flag, 1); fprintf(stderr, "Waiting for threads to finish acquisition regression..."); for (t = 0; t < threads; t++) pthread_join(p[t], NULL); fprintf(stderr, "done\n\n"); for (t = 1; t <= threads; t++) printf("%10u %20" PRIu64 "\n", t, latency[t - 1]); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pflock/validate/validate.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra, John Wittrock. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 1000000 #endif static struct affinity a; static unsigned int locked; static int nthr; static ck_pflock_t lock = CK_PFLOCK_INITIALIZER; static void * thread(void *null CK_CC_UNUSED) { int i = ITERATE; unsigned int l; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { ck_pflock_write_lock(&lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } ck_pflock_write_unlock(&lock); ck_pflock_read_lock(&lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } ck_pflock_read_unlock(&lock); } return NULL; } int main(int argc, char *argv[]) { pthread_t *threads; int i; if (argc != 3) { ck_error("Usage: validate \n"); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } a.delta = atoi(argv[2]); fprintf(stderr, "Creating threads (mutual exclusion)..."); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, thread, NULL)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); fprintf(stderr, "Waiting for threads to finish correctness regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/benchmark/benchmark.h ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" /* 8! = 40320, evenly divide 1 .. 8 processor workload. */ #define WORKLOAD (40320 * 2056) struct block { unsigned int tid; }; static struct affinity a; static unsigned int ready; static uint64_t *count; static uint64_t nthr; static uint64_t object[2] CK_CC_CACHELINE; static void * fairness(void *null) { struct block *context = null; unsigned int i = context->tid; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (ck_pr_load_uint(&ready) == 0); while (ck_pr_load_uint(&ready)) { ATOMIC; ATOMIC; ATOMIC; ATOMIC; ck_pr_store_64(count + i, count[i] + 1); } return (NULL); } int main(int argc, char *argv[]) { uint64_t v, d; unsigned int i; pthread_t *threads; struct block *context; if (argc != 3) { ck_error("Usage: " ATOMIC_STRING " \n"); exit(EXIT_FAILURE); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); exit(EXIT_FAILURE); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); exit(EXIT_FAILURE); } context = malloc(sizeof(struct block) * nthr); if (context == NULL) { ck_error("ERROR: Could not allocate thread contexts\n"); exit(EXIT_FAILURE); } a.delta = atoi(argv[2]); a.request = 0; count = malloc(sizeof(uint64_t) * nthr); if (count == NULL) { ck_error("ERROR: Could not create acquisition buffer\n"); exit(EXIT_FAILURE); } memset(count, 0, sizeof(uint64_t) * nthr); fprintf(stderr, "Creating threads (fairness)..."); for (i = 0; i < nthr; i++) { context[i].tid = i; if (pthread_create(&threads[i], NULL, fairness, context + i)) { ck_error("ERROR: Could not create thread %d\n", i); exit(EXIT_FAILURE); } } fprintf(stderr, "done\n"); ck_pr_store_uint(&ready, 1); common_sleep(10); ck_pr_store_uint(&ready, 0); fprintf(stderr, "Waiting for threads to finish acquisition regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done\n\n"); for (i = 0, v = 0; i < nthr; i++) { printf("%d %15" PRIu64 "\n", i, count[i]); v += count[i]; } printf("\n# total : %15" PRIu64 "\n", v); printf("# throughput : %15" PRIu64 " a/s\n", (v /= nthr) / 10); for (i = 0, d = 0; i < nthr; i++) d += (count[i] - v) * (count[i] - v); printf("# average : %15" PRIu64 "\n", v); printf("# deviation : %.2f (%.2f%%)\n\n", sqrt(d / nthr), (sqrt(d / nthr) / v) * 100.00); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/benchmark/ck_pr_add_64.c ================================================ #include #ifdef CK_F_PR_ADD_64 #define ATOMIC ck_pr_add_64(object, 1) #define ATOMIC_STRING "ck_pr_add_64" #include "benchmark.h" #else #warning Did not find ADD_64 implementation. #include int main(void) { exit(EXIT_FAILURE); } #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/benchmark/ck_pr_cas_64.c ================================================ #include #ifdef CK_F_PR_CAS_64 #define ATOMIC ck_pr_cas_64(object, 1, 1) #define ATOMIC_STRING "ck_pr_cas_64" #include "benchmark.h" #else #warning Did not find CAS_64 implementation. #include int main(void) { exit(EXIT_FAILURE); } #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/benchmark/ck_pr_cas_64_2.c ================================================ #include #ifdef CK_F_PR_CAS_64_2 #define ATOMIC { uint64_t z[2] = {1, 2}; ck_pr_cas_64_2(object, z, z); } #define ATOMIC_STRING "ck_pr_cas_64_2" #include "benchmark.h" #else #include #include int main(void) { fprintf(stderr, "Unsupported.\n"); return 0; } #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/benchmark/ck_pr_faa_64.c ================================================ #include #ifdef CK_F_PR_FAA_64 #define ATOMIC ck_pr_faa_64(object, 1) #define ATOMIC_STRING "ck_pr_faa_64" #include "benchmark.h" #else #warning Did not find FAA_64 implementation. #include int main(void) { exit(EXIT_FAILURE); } #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/benchmark/ck_pr_fas_64.c ================================================ #include #ifdef CK_F_PR_FAS_64 #define ATOMIC ck_pr_fas_64(object, 1) #define ATOMIC_STRING "ck_pr_fas_64" #include "benchmark.h" #else #warning Did not find FAS_64 implementation. #include int main(void) { return 0; } #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/benchmark/ck_pr_neg_64.c ================================================ #include #ifdef CK_F_PR_NEG_64 #define ATOMIC ck_pr_neg_64(object) #define ATOMIC_STRING "ck_pr_neg_64" #include "benchmark.h" #else #warning Did not find NEG_64 implementation. #include int main(void) { exit(EXIT_FAILURE); } #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/benchmark/fp.c ================================================ #include #include #include #include "../../common.h" #ifndef IR #define IR 3000000 #endif /* IR */ static int a CK_CC_CACHELINE; static int b CK_CC_CACHELINE; int main(void) { uint64_t s, e; unsigned int i; s = rdtsc(); for (i = 0; i < IR; i++) { ck_pr_load_int(&a); ck_pr_fence_strict_load(); ck_pr_load_int(&b); } e = rdtsc(); printf("[A] fence_load: %" PRIu64 "\n", (e - s) / IR); s = rdtsc(); for (i = 0; i < IR; i++) { if (ck_pr_load_int(&a) == 0) ck_pr_barrier(); ck_pr_fence_strict_lock(); ck_pr_load_int(&b); } e = rdtsc(); printf("[A] fence_lock: %" PRIu64 "\n", (e - s) / IR); s = rdtsc(); for (i = 0; i < IR; i++) { ck_pr_store_int(&a, 0); ck_pr_fence_strict_store(); ck_pr_store_int(&b, 0); } e = rdtsc(); printf("[B] fence_store: %" PRIu64 "\n", (e - s) / IR); s = rdtsc(); for (i = 0; i < IR; i++) { ck_pr_store_int(&a, 0); ck_pr_fence_strict_memory(); ck_pr_load_int(&b); } e = rdtsc(); printf("[C] fence_memory: %" PRIu64 "\n", (e - s) / IR); s = rdtsc(); for (i = 0; i < IR; i++) { ck_pr_store_int(&a, 0); ck_pr_faa_int(&a, 0); ck_pr_load_int(&b); } e = rdtsc(); printf("[C] atomic: %" PRIu64 "\n", (e - s) / IR); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_add.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define CK_PR_ADD_T(w, v, d) \ { \ uint##w##_t t = v; \ ck_pr_add_##w(&t, d); \ if (t != (uint##w##_t)(v + d)) { \ printf("FAIL ["); \ printf("%" PRIu##w " (%" PRIu##w ") -> %" PRIu##w "]\n",\ (uint##w##_t)v, d, t); \ exit(EXIT_FAILURE); \ } \ } #define CK_PR_ADD_B(w) \ { \ unsigned int __ck_i = 0; \ printf("ck_pr_add_" #w ": "); \ if (w < 10) \ printf(" "); \ for (__ck_i = 0; __ck_i < R_REPEAT; __ck_i++) { \ uint##w##_t a = common_rand() % ((uint##w##_t)-1 / 2); \ uint##w##_t b = common_rand() % ((uint##w##_t)-1 / 2); \ CK_PR_ADD_T(w, a, b); \ } \ rg_width(w); \ printf(" SUCCESS\n"); \ } #define CK_PR_ADD_W(m, w) \ { \ uint##m##_t t = -1, r = -1 & ~(uint##m##_t)(uint##w##_t)-1; \ ck_pr_add_##w((uint##w##_t *)(void *)&t, 1); \ if (t != r) { \ printf("FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, r);\ exit(EXIT_FAILURE); \ } \ t = 0, r = (uint##m##_t)(uint##w##_t)-1; \ ck_pr_add_##w((uint##w##_t *)(void *)&t, -1); \ if (t != r) { \ printf("FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, r);\ exit(EXIT_FAILURE); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_ADD_64 if (m == 64) { #if defined(CK_F_PR_ADD_32) CK_PR_ADD_W(64, 32); #endif #if defined(CK_PR_ADD_16) CK_PR_ADD_W(64, 16); #endif #if defined(CK_PR_ADD_8) CK_PR_ADD_W(64, 8); #endif } #endif /* CK_PR_ADD_64 */ #ifdef CK_F_PR_ADD_32 if (m == 32) { #if defined(CK_F_PR_ADD_16) CK_PR_ADD_W(32, 16); #endif #if defined(CK_PR_ADD_8) CK_PR_ADD_W(32, 8); #endif } #endif /* CK_PR_ADD_32 */ #if defined(CK_F_PR_ADD_16) && defined(CK_PR_ADD_8) if (m == 16) { CK_PR_ADD_W(16, 8); } #endif /* CK_PR_ADD_16 && CK_PR_ADD_8 */ return; } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_ADD_64 CK_PR_ADD_B(64); #endif #ifdef CK_F_PR_ADD_32 CK_PR_ADD_B(32); #endif #ifdef CK_F_PR_ADD_16 CK_PR_ADD_B(16); #endif #ifdef CK_F_PR_ADD_8 CK_PR_ADD_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_and.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define BM(m, w) ((uint##m##_t)-1 << (w)) #define CK_PR_AND_T(w, v, d) \ { \ uint##w##_t t = v; \ ck_pr_and_##w(&t, d); \ if (t != (uint##w##_t)(v & d)) { \ printf("FAIL ["); \ printf("%" PRIu##w " (%" PRIu##w ") -> %" PRIu##w "]\n",\ (uint##w##_t)v, d, t); \ exit(EXIT_FAILURE); \ } \ } #define CK_PR_AND_B(w) \ { \ unsigned int __ck_i = 0; \ printf("ck_pr_and_" #w ": "); \ if (w < 10) \ printf(" "); \ for (__ck_i = 0; __ck_i < R_REPEAT; __ck_i++) { \ uint##w##_t a = (uint##w##_t)common_rand(); \ uint##w##_t b = (uint##w##_t)common_rand(); \ CK_PR_AND_T(w, a, b); \ } \ rg_width(w); \ printf(" SUCCESS\n"); \ } #define CK_PR_AND_W(m, w) \ { \ uint##m##_t t = -1; \ ck_pr_and_##w((uint##w##_t *)(void *)&t, 0); \ if (t != BM(m, w)) { \ printf(" FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, BM(m, w)); \ exit(EXIT_FAILURE); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_AND_64 if (m == 64) { #if defined(CK_F_PR_AND_32) CK_PR_AND_W(64, 32); #endif #if defined(CK_PR_AND_16) CK_PR_AND_W(64, 16); #endif #if defined(CK_PR_AND_8) CK_PR_AND_W(64, 8); #endif } #endif /* CK_PR_AND_64 */ #ifdef CK_F_PR_AND_32 if (m == 32) { #if defined(CK_F_PR_AND_16) CK_PR_AND_W(32, 16); #endif #if defined(CK_PR_AND_8) CK_PR_AND_W(32, 8); #endif } #endif /* CK_PR_AND_32 */ #if defined(CK_F_PR_AND_16) && defined(CK_PR_AND_8) if (m == 16) { CK_PR_AND_W(16, 8); } #endif /* CK_PR_AND_16 && CK_PR_AND_8 */ return; } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_AND_64 CK_PR_AND_B(64); #endif #ifdef CK_F_PR_AND_32 CK_PR_AND_B(32); #endif #ifdef CK_F_PR_AND_16 CK_PR_AND_B(16); #endif #ifdef CK_F_PR_AND_8 CK_PR_AND_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_bin.c ================================================ /* * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "../../common.h" #define REPEAT 2000000 #define TEST_BINARY(K, S, T, P, D) \ static void \ run_test_##K##_##S(void) \ { \ int i, r; \ T serial_result = 65535; \ T ck_result = 65535; \ \ puts("***TESTING ck_pr_" #K "_" #S "***"); \ common_srand((unsigned int)getpid()); \ for (i = 0; i < REPEAT; ++i) { \ r = common_rand(); \ serial_result = serial_result P r; \ ck_pr_##K##_##S(&ck_result, r); \ } \ \ printf("Value of operation " #K " on 2000000 " \ "random numbers\n\tusing " #P ": %" #D ",\n" \ "\tusing ck_pr_"#K"_"#S": %" #D "\n", \ serial_result, ck_result); \ (serial_result == ck_result) ? puts("SUCCESS.") \ : puts("FAILURE."); \ \ return; \ } \ #define GENERATE_TEST(K, P) \ TEST_BINARY(K, int, int, P, d) \ TEST_BINARY(K, uint, unsigned int, P, u) \ static void \ run_test_##K(void) \ { \ run_test_##K##_int(); \ run_test_##K##_uint(); \ \ return; \ } GENERATE_TEST(add, +) GENERATE_TEST(sub, -) GENERATE_TEST(and, &) GENERATE_TEST(or, |) GENERATE_TEST(xor, ^) #undef GENERATE_TEST #undef TEST_BINARY int main(void) { run_test_add(); run_test_sub(); run_test_and(); run_test_or(); run_test_xor(); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_btc.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif /* * Bit selector. */ #define BM(v, b) (((v) >> (b)) & 1) #define CK_PR_BTC_T(w, v) \ { \ unsigned int j; \ uint##w##_t r = v; \ bool t; \ for (j = 0; j < (w); j++) { \ t = ck_pr_btc_##w(&r, j); \ if ((t && !BM(v, j)) || ((BM(v, j) + BM(r, j)) != 1)) { \ printf("FAIL [%" PRIx##w ":%u]\n", r, j); \ exit(EXIT_FAILURE); \ } \ } \ } #define CK_PR_BTC_B(w) \ { \ uint##w##_t o; \ unsigned int i; \ printf("ck_pr_btc_" #w ": "); \ for (i = 0; i < R_REPEAT; i++) { \ o = (uint##w##_t)common_rand(); \ CK_PR_BTC_T(w, o); \ } \ printf(" SUCCESS\n"); \ } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_BTC_64 CK_PR_BTC_B(64); #endif #ifdef CK_F_PR_BTC_32 CK_PR_BTC_B(32); #endif #ifdef CK_F_PR_BTC_16 CK_PR_BTC_B(16); #endif #ifdef CK_F_PR_BTC_8 CK_PR_BTC_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_btr.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif /* * Bit selector. */ #define BM(v, b) (((v) >> (b)) & 1) #define CK_PR_BTR_T(w, v) \ { \ unsigned int j; \ uint##w##_t r = v, c = v; \ bool t; \ for (j = 0; j < (w); j++) { \ c &= (uint##w##_t)-1 ^ (1 << j); \ t = ck_pr_btr_##w(&r, j); \ if ((t && !BM(v, j)) || (r != c)) { \ printf("FAIL [%" PRIx##w ":%u != %" PRIx##w ":%u]\n", r, j, c, j); \ exit(EXIT_FAILURE); \ } \ } \ } #define CK_PR_BTR_B(w) \ { \ uint##w##_t o; \ unsigned int i; \ printf("ck_pr_btr_" #w ": "); \ for (i = 0; i < R_REPEAT; i++) { \ o = (uint##w##_t)common_rand(); \ CK_PR_BTR_T(w, o); \ } \ printf(" SUCCESS\n"); \ } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_BTR_64 CK_PR_BTR_B(64); #endif #ifdef CK_F_PR_BTR_32 CK_PR_BTR_B(32); #endif #ifdef CK_F_PR_BTR_16 CK_PR_BTR_B(16); #endif #ifdef CK_F_PR_BTR_8 CK_PR_BTR_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_bts.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif /* * Bit selector. */ #define BM(v, b) (((v) >> (b)) & 1) #define CK_PR_BTS_T(w, v) \ { \ unsigned int j; \ uint##w##_t r = v, c = v; \ bool t; \ for (j = 0; j < (w); j++) { \ c |= (uint##w##_t)1 << j; \ t = ck_pr_bts_##w(&r, j); \ if ((t && !BM(v, j)) || (r != c)) { \ printf("FAIL [%" PRIx##w ":%u != %" PRIx##w ":%u]\n", r, j, c, j); \ exit(EXIT_FAILURE); \ } \ } \ } #define CK_PR_BTS_B(w) \ { \ uint##w##_t o; \ unsigned int i; \ printf("ck_pr_bts_" #w ": "); \ for (i = 0; i < R_REPEAT; i++) { \ o = (uint##w##_t)common_rand(); \ CK_PR_BTS_T(w, o); \ } \ printf(" SUCCESS\n"); \ } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_BTS_64 CK_PR_BTS_B(64); #endif #ifdef CK_F_PR_BTS_32 CK_PR_BTS_B(32); #endif #ifdef CK_F_PR_BTS_16 CK_PR_BTS_B(16); #endif #ifdef CK_F_PR_BTS_8 CK_PR_BTS_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_btx.c ================================================ /* * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "../../common.h" #define REPEAT 2000000 #define TEST_BTX(K, S, M, T, L, P, D, R) \ static bool \ test_##K##_##S(M *target, int offset) \ { \ T previous; \ const L change = R (0x01 << offset); \ \ previous = (T)*target; \ *target = previous P change; \ return ((previous >> offset) & 0x01); \ } \ static void \ run_test_##K##_##S(void) \ { \ int i, offset, m; \ bool serial_t, ck_pr_t; \ T x = 65535, y = 65535; \ \ common_srand((unsigned int)getpid()); \ m = sizeof(T) * 8; \ \ puts("***TESTING ck_pr_"#K"_"#S"***"); \ for (i = 0; i < REPEAT; ++i) { \ offset = common_rand() % m; \ serial_t = test_##K##_##S(&x, offset); \ ck_pr_t = ck_pr_##K##_##S(&y, offset); \ \ if (serial_t != ck_pr_t || x != y ) { \ printf("Serial(%"#D") and ck_pr(%"#D")" \ #K"_"#S " do not match.\n" \ "FAILURE.\n", \ serial_t, ck_pr_t); \ \ return; \ } \ } \ printf("\tserial_"#K"_"#S": %"#D"\n" \ "\tck_pr_"#K"_"#S": %"#D"\n" \ "SUCCESS.\n", \ x, y); \ \ return; \ } #define TEST_BTX_S(K, S, T, P, D, R) TEST_BTX(K, S, T, T, T, P, D, R) #define GENERATE_TEST(K, P, R) \ TEST_BTX_S(K, int, int, P, d, R) \ TEST_BTX_S(K, uint, unsigned int, P, u, R) \ static void \ run_test_##K(void) \ { \ run_test_##K##_int(); \ run_test_##K##_uint(); \ \ return; \ } GENERATE_TEST(btc, ^, 0+) GENERATE_TEST(btr, &, ~) GENERATE_TEST(bts, |, 0+) #undef GENERATE_TEST #undef TEST_BTX_S #undef TEST_BTX int main(void) { run_test_btc(); run_test_btr(); run_test_bts(); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_cas.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define W(w, x) (uint##w##_t)((x) & (uint##w##_t)~0) #define CK_PR_CAS_T(w, v, c, s) \ { \ uint##w##_t t = v; \ bool r; \ r = ck_pr_cas_##w(&t, c, s); \ if (((c == v) && (r == false)) || ((c != v) && (r == true)) || \ ((r == true) && (W(w, s) != t))) { \ printf("FAIL ["); \ printf("%" PRIu##w " (%" PRIu##w " -> %" PRIu##w ")" \ " -> %" PRIu##w "]\n", \ (uint##w##_t)(v), (uint##w##_t)(c), W(w, s), (uint##w##_t)(t)); \ } \ } #define CK_PR_CAS_B(w) \ { \ unsigned int __ck_i; \ printf("ck_pr_cas_" #w ": "); \ if (w < 10) \ printf(" "); \ for (__ck_i = 0; __ck_i < R_REPEAT; __ck_i++) { \ uint##w##_t a = common_rand() % (uint##w##_t)-1; \ CK_PR_CAS_T(w, a, a + 1, (a - 1)); \ CK_PR_CAS_T(w, a, a, (a - 1)); \ CK_PR_CAS_T(w, a, a + 1, a); \ } \ rg_width(w); \ printf(" SUCCESS\n"); \ } #define CK_PR_CAS_W(m, w) \ { \ uint##m##_t t = -1, r = -1 & ~(uint##m##_t)(uint##w##_t)-1; \ ck_pr_cas_##w((uint##w##_t *)(void *)&t, (uint##w##_t)t, 0); \ if (t != r) { \ printf("FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", \ (uint##m##_t)t, (uint##m##_t)r); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_CAS_64 if (m == 64) { #if defined(CK_F_PR_CAS_32) CK_PR_CAS_W(64, 32); #endif #if defined(CK_PR_CAS_16) CK_PR_CAS_W(64, 16); #endif #if defined(CK_PR_CAS_8) CK_PR_CAS_W(64, 8); #endif } #endif /* CK_PR_CAS_64 */ #ifdef CK_F_PR_CAS_32 if (m == 32) { #if defined(CK_F_PR_CAS_16) CK_PR_CAS_W(32, 16); #endif #if defined(CK_PR_CAS_8) CK_PR_CAS_W(32, 8); #endif } #endif /* CK_PR_CAS_32 */ #if defined(CK_F_PR_CAS_16) && defined(CK_PR_CAS_8) if (m == 16) { CK_PR_CAS_W(16, 8); } #endif /* CK_PR_CAS_16 && CK_PR_CAS_8 */ return; } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_CAS_64 CK_PR_CAS_B(64); #endif #ifdef CK_F_PR_CAS_32 CK_PR_CAS_B(32); #endif #ifdef CK_F_PR_CAS_16 CK_PR_CAS_B(16); #endif #ifdef CK_F_PR_CAS_8 CK_PR_CAS_B(8); #endif #ifdef CK_F_PR_CAS_64_VALUE uint64_t a = 0xffffffffaaaaaaaa, b = 0x8888888800000000; printf("%" PRIx64 " (%" PRIx64 ") -> ", b, a); ck_pr_cas_64_value(&a, a, b, &b); printf("%" PRIx64 " (%" PRIx64 ")\n", b, a); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_dec.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define CK_PR_DEC_T(w, v) \ { \ uint##w##_t t = v; \ ck_pr_dec_##w(&t); \ if ((t != (uint##w##_t)(v - 1))) { \ printf("FAIL ["); \ printf("%" PRIu##w " -> %" PRIu##w "]\n", (uint##w##_t)v, t); \ exit(EXIT_FAILURE); \ } \ } #define CK_PR_DEC_B(w) \ { \ unsigned int __ck_i = 0; \ printf("ck_pr_dec_" #w ": "); \ if (w < 10) \ printf(" "); \ for (__ck_i = 0; __ck_i < R_REPEAT; __ck_i++) { \ uint##w##_t a = common_rand() % ((uint##w##_t)-1); \ CK_PR_DEC_T(w, a); \ } \ rg_width(w); \ printf(" SUCCESS\n"); \ } #define CK_PR_DEC_W(m, w) \ { \ uint##m##_t t = 0, r = (uint##w##_t)-1; \ ck_pr_dec_##w((uint##w##_t *)(void *)&t); \ if (t != r) { \ printf("FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, r);\ exit(EXIT_FAILURE); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_DEC_64 if (m == 64) { #if defined(CK_F_PR_DEC_32) CK_PR_DEC_W(64, 32); #endif #if defined(CK_PR_DEC_16) CK_PR_DEC_W(64, 16); #endif #if defined(CK_PR_DEC_8) CK_PR_DEC_W(64, 8); #endif } #endif /* CK_PR_DEC_64 */ #ifdef CK_F_PR_DEC_32 if (m == 32) { #if defined(CK_F_PR_DEC_16) CK_PR_DEC_W(32, 16); #endif #if defined(CK_PR_DEC_8) CK_PR_DEC_W(32, 8); #endif } #endif /* CK_PR_DEC_32 */ #if defined(CK_F_PR_DEC_16) && defined(CK_PR_DEC_8) if (m == 16) { CK_PR_DEC_W(16, 8); } #endif /* CK_PR_DEC_16 && CK_PR_DEC_8 */ return; } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_DEC_64 CK_PR_DEC_B(64); #endif #ifdef CK_F_PR_DEC_32 CK_PR_DEC_B(32); #endif #ifdef CK_F_PR_DEC_16 CK_PR_DEC_B(16); #endif #ifdef CK_F_PR_DEC_8 CK_PR_DEC_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_faa.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define CK_PR_FAA_T(w, v, d) \ { \ uint##w##_t r, t = v; \ r = ck_pr_faa_##w(&t, d); \ if ((t != (uint##w##_t)(v + d)) || (r != v)) { \ printf("FAIL ["); \ printf("%" PRIu##w " (%" PRIu##w ") -> %" PRIu##w \ " (%" PRIu##w ")]\n", \ (uint##w##_t)v, d, t, r); \ exit(EXIT_FAILURE); \ } \ } #define CK_PR_FAA_B(w) \ { \ unsigned int __ck_i = 0; \ printf("ck_pr_faa_" #w ": "); \ if (w < 10) \ printf(" "); \ for (__ck_i = 0; __ck_i < R_REPEAT; __ck_i++) { \ uint##w##_t a = common_rand() % ((uint##w##_t)-1 / 2); \ uint##w##_t b = common_rand() % ((uint##w##_t)-1 / 2); \ CK_PR_FAA_T(w, a, b); \ } \ rg_width(w); \ printf(" SUCCESS\n"); \ } #define CK_PR_FAA_W(m, w) \ { \ uint##m##_t t = -1, r = -1 & ~(uint##m##_t)(uint##w##_t)-1; \ ck_pr_faa_##w((uint##w##_t *)(void *)&t, 1); \ if (t != r) { \ printf("FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, r);\ exit(EXIT_FAILURE); \ } \ t = 0, r = (uint##m##_t)(uint##w##_t)-1; \ ck_pr_faa_##w((uint##w##_t *)(void *)&t, -1); \ if (t != r) { \ printf("FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, r);\ exit(EXIT_FAILURE); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_FAA_64 if (m == 64) { #if defined(CK_F_PR_FAA_32) CK_PR_FAA_W(64, 32); #endif #if defined(CK_PR_FAA_16) CK_PR_FAA_W(64, 16); #endif #if defined(CK_PR_FAA_8) CK_PR_FAA_W(64, 8); #endif } #endif /* CK_PR_FAA_64 */ #ifdef CK_F_PR_FAA_32 if (m == 32) { #if defined(CK_F_PR_FAA_16) CK_PR_FAA_W(32, 16); #endif #if defined(CK_PR_FAA_8) CK_PR_FAA_W(32, 8); #endif } #endif /* CK_PR_FAA_32 */ #if defined(CK_F_PR_FAA_16) && defined(CK_PR_FAA_8) if (m == 16) { CK_PR_FAA_W(16, 8); } #endif /* CK_PR_FAA_16 && CK_PR_FAA_8 */ return; } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_FAA_64 CK_PR_FAA_B(64); #endif #ifdef CK_F_PR_FAA_32 CK_PR_FAA_B(32); #endif #ifdef CK_F_PR_FAA_16 CK_PR_FAA_B(16); #endif #ifdef CK_F_PR_FAA_8 CK_PR_FAA_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_fas.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define BM(m, w) ((uint##m##_t)(uint##w##_t)(-1)) #define CK_PR_FAS_T(w, v, d) \ { \ uint##w##_t r, t = v; \ r = ck_pr_fas_##w(&t, d); \ if ((t != d) || (r != v)) { \ printf("FAIL ["); \ printf("%" PRIu##w " (%" PRIu##w ") -> %" PRIu##w \ " (%" PRIu##w ")]\n", \ (uint##w##_t)v, d, t, r); \ exit(EXIT_FAILURE); \ } \ } #define CK_PR_FAS_B(w) \ { \ unsigned int __ck_i = 0; \ printf("ck_pr_fas_" #w ": "); \ if (w < 10) \ printf(" "); \ for (__ck_i = 0; __ck_i < R_REPEAT; __ck_i++) { \ uint##w##_t a = common_rand(); \ uint##w##_t b = common_rand(); \ CK_PR_FAS_T(w, a, b); \ } \ rg_width(w); \ printf(" SUCCESS\n"); \ } #define CK_PR_FAS_W(m, w) \ { \ uint##m##_t t = 0; \ ck_pr_fas_##w((uint##w##_t *)(void *)&t, -1); \ if (t != BM(m, w)) { \ printf("FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, BM(m, w)); \ exit(EXIT_FAILURE); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_FAS_64 if (m == 64) { #if defined(CK_F_PR_FAS_32) CK_PR_FAS_W(64, 32); #endif #if defined(CK_PR_FAS_16) CK_PR_FAS_W(64, 16); #endif #if defined(CK_PR_FAS_8) CK_PR_FAS_W(64, 8); #endif } #endif /* CK_PR_FAS_64 */ #ifdef CK_F_PR_FAS_32 if (m == 32) { #if defined(CK_F_PR_FAS_16) CK_PR_FAS_W(32, 16); #endif #if defined(CK_PR_FAS_8) CK_PR_FAS_W(32, 8); #endif } #endif /* CK_PR_FAS_32 */ #if defined(CK_F_PR_FAS_16) && defined(CK_PR_FAS_8) if (m == 16) { CK_PR_FAS_W(16, 8); } #endif /* CK_PR_FAS_16 && CK_PR_FAS_8 */ return; } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_FAS_64 CK_PR_FAS_B(64); #endif #ifdef CK_F_PR_FAS_32 CK_PR_FAS_B(32); #endif #ifdef CK_F_PR_FAS_16 CK_PR_FAS_B(16); #endif #ifdef CK_F_PR_FAS_8 CK_PR_FAS_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_fax.c ================================================ /* * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "../../common.h" #define REPEAT 2000000 #define TEST_FAX_FN(S, T, M) \ static T \ test_faa_##S(M *target, T delta) \ { \ T previous = (T)*target; \ *target = (T)*target + delta; \ \ return (previous); \ } \ static T \ test_fas_##S(M *target, T update) \ { \ T previous = *target; \ *target = update; \ \ return (previous); \ } #define TEST_FAX_FN_S(S, T) TEST_FAX_FN(S, T, T) TEST_FAX_FN_S(int, int) TEST_FAX_FN_S(uint, unsigned int) #undef TEST_FAX_FN_S #undef TEST_FAX_FN #define TEST_FAX(K, S, T, D) \ static void \ run_test_##K##_##S(void) \ { \ int i, r; \ T x = 0, y = 0, x_b, y_b; \ \ puts("***TESTING ck_pr_"#K"_"#S"***"); \ common_srand((unsigned int)getpid()); \ for (i = 0; i < REPEAT; ++i) { \ r = common_rand(); \ x_b = test_##K##_##S(&x, r); \ y_b = ck_pr_##K##_##S(&y, r); \ \ if (x_b != y_b) { \ printf("Serial fetch does not match ck_pr fetch.\n" \ "\tSerial: %"#D"\n" \ "\tck_pr: %"#D"\n", \ x_b, y_b); \ \ return; \ } \ } \ \ printf("Final result:\n" \ "\tSerial: %"#D"\n" \ "\tck_pr: %"#D"\n", \ x, y); \ (x == y) ? puts("SUCCESS.") \ : puts("FAILURE."); \ \ return; \ } \ #define GENERATE_TEST(K) \ TEST_FAX(K, int, int, d) \ TEST_FAX(K, uint, unsigned int, u) \ static void \ run_test_##K(void) \ { \ run_test_##K##_int(); \ run_test_##K##_uint(); \ } GENERATE_TEST(faa) GENERATE_TEST(fas) #undef GENERATE_TEST #undef TEST_FAX int main(void) { run_test_faa(); run_test_fas(); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_inc.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define CK_PR_INC_T(w, v) \ { \ uint##w##_t t = v; \ ck_pr_inc_##w(&t); \ if ((t != (uint##w##_t)(v + 1))) { \ printf("FAIL [%" PRIu##w " -> %" PRIu##w "]\n", \ (uint##w##_t)v, t); \ exit(EXIT_FAILURE); \ } \ } #define CK_PR_INC_B(w) \ { \ unsigned int __ck_i = 0; \ printf("ck_pr_inc_" #w ": "); \ if (w < 10) \ printf(" "); \ for (__ck_i = 0; __ck_i < R_REPEAT; __ck_i++) { \ uint##w##_t a = common_rand() % ((uint##w##_t)-1); \ CK_PR_INC_T(w, a); \ } \ rg_width(w); \ printf(" SUCCESS\n"); \ } #define CK_PR_INC_W(m, w) \ { \ uint##m##_t t = -1, r = -1 & ~(uint##m##_t)(uint##w##_t)-1; \ ck_pr_inc_##w((uint##w##_t *)(void *)&t); \ if (t != r) { \ printf("FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, r);\ exit(EXIT_FAILURE); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_INC_64 if (m == 64) { #if defined(CK_F_PR_INC_32) CK_PR_INC_W(64, 32); #endif #if defined(CK_PR_INC_16) CK_PR_INC_W(64, 16); #endif #if defined(CK_PR_INC_8) CK_PR_INC_W(64, 8); #endif } #endif /* CK_PR_INC_64 */ #ifdef CK_F_PR_INC_32 if (m == 32) { #if defined(CK_F_PR_INC_16) CK_PR_INC_W(32, 16); #endif #if defined(CK_PR_INC_8) CK_PR_INC_W(32, 8); #endif } #endif /* CK_PR_INC_32 */ #if defined(CK_F_PR_INC_16) && defined(CK_PR_INC_8) if (m == 16) { CK_PR_INC_W(16, 8); } #endif /* CK_PR_INC_16 && CK_PR_INC_8 */ return; } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_INC_64 CK_PR_INC_B(64); #endif #ifdef CK_F_PR_INC_32 CK_PR_INC_B(32); #endif #ifdef CK_F_PR_INC_16 CK_PR_INC_B(16); #endif #ifdef CK_F_PR_INC_8 CK_PR_INC_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_load.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define CK_PR_LOAD_B(w) \ { \ uint##w##_t t = (uint##w##_t)-1, a = 0; \ unsigned int i; \ printf("ck_pr_load_" #w ": "); \ if (w < 10) \ printf(" "); \ a = ck_pr_load_##w(&t); \ if (a != t) { \ printf("FAIL [%#" PRIx##w " != %#" PRIx##w "]\n", a, t); \ exit(EXIT_FAILURE); \ } \ for (i = 0; i < R_REPEAT; i++) { \ t = (uint##w##_t)common_rand(); \ a = ck_pr_load_##w(&t); \ if (a != t) { \ printf("FAIL [%#" PRIx##w " != %#" PRIx##w "]\n", a, t);\ exit(EXIT_FAILURE); \ } \ } \ rg_width(w); \ printf(" SUCCESS\n"); \ } #define CK_PR_LOAD_W(m, w) \ { \ uint##m##_t f = 0; \ uint##w##_t j = (uint##w##_t)-1; \ f = ck_pr_load_##w(&j); \ if (f != j) { \ printf("FAIL [%#" PRIx##m " != %#" PRIx##w "]\n", f, j);\ exit(EXIT_FAILURE); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_LOAD_64 if (m == 64) { #if defined(CK_F_PR_LOAD_32) CK_PR_LOAD_W(64, 32); #endif #if defined(CK_PR_LOAD_16) CK_PR_LOAD_W(64, 16); #endif #if defined(CK_PR_LOAD_8) CK_PR_LOAD_W(64, 8); #endif } #endif /* CK_PR_LOAD_64 */ #ifdef CK_F_PR_LOAD_32 if (m == 32) { #if defined(CK_F_PR_LOAD_16) CK_PR_LOAD_W(32, 16); #endif #if defined(CK_PR_LOAD_8) CK_PR_LOAD_W(32, 8); #endif } #endif /* CK_PR_LOAD_32 */ #if defined(CK_F_PR_LOAD_16) && defined(CK_PR_LOAD_8) if (m == 16) CK_PR_LOAD_W(16, 8); #endif /* CK_PR_LOAD_16 && CK_PR_LOAD_8 */ return; } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_LOAD_64 CK_PR_LOAD_B(64); #endif #ifdef CK_F_PR_LOAD_32 CK_PR_LOAD_B(32); #endif #ifdef CK_F_PR_LOAD_16 CK_PR_LOAD_B(16); #endif #ifdef CK_F_PR_LOAD_8 CK_PR_LOAD_B(8); #endif #if 0 uint64_t a[2] = {0, 0}, b[2] = {0x1111111144444444, 0x2222222266666666}; printf("%" PRIx64 ":%" PRIx64 " -> ", a[0], a[1]); ck_pr_load_64_2(&b, &a); printf("%" PRIx64 ":%" PRIx64 "\n", a[0], a[1]); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_n.c ================================================ /* * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "../../common.h" #define REPEAT 2000000 #define TEST_N(K, S, T, P, D) \ static void \ run_test_##K##_##S(void) \ { \ int i, r; \ T x = 0, y = 0; \ \ puts("***TESTING ck_pr_"#K"_"#S"***"); \ common_srand((unsigned int)getpid()); \ for (i = 0; i < REPEAT; ++i) { \ r = common_rand(); \ x += r; \ x = P x; \ y += r; \ ck_pr_##K##_##S(&y); \ } \ \ printf("Value of operation "#K" on 2000000 " \ "random numbers\n" \ "\tusing "#P": %"#D",\n" \ "\tusing ck_pr_"#K"_"#S": %"#D",\n", \ x, y); \ (x == y) ? puts("SUCCESS.") \ : puts("FAILURE."); \ \ return; \ } #define GENERATE_TEST(K, P) \ TEST_N(K, int, int, P, d) \ TEST_N(K, uint, unsigned int, P, u) \ static void \ run_test_##K(void) \ { \ run_test_##K##_int(); \ run_test_##K##_uint(); \ \ return; \ } GENERATE_TEST(not, ~) GENERATE_TEST(neg, -) #undef GENERATE_TEST #undef TEST_N int main(void) { run_test_not(); run_test_neg(); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_or.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define BM(m, w) (uint##m##_t)(uint##w##_t)-1 #define CK_PR_OR_T(w, v, d) \ { \ uint##w##_t t; \ ck_pr_or_##w(&t, 1ULL << (w - 1)); \ t = v; \ ck_pr_or_##w(&t, d); \ if (t != (uint##w##_t)(v | d)) { \ printf("FAIL ["); \ printf("%" PRIu##w " (%" PRIu##w ") -> %" PRIu##w "]\n",\ (uint##w##_t)v, d, t); \ exit(EXIT_FAILURE); \ } \ } #define CK_PR_OR_B(w) \ { \ unsigned int __ck_i = 0; \ printf("ck_pr_or_" #w ": "); \ if (w < 10) \ printf(" "); \ for (__ck_i = 0; __ck_i < R_REPEAT; __ck_i++) { \ uint##w##_t a = (uint##w##_t)common_rand(); \ uint##w##_t b = (uint##w##_t)common_rand(); \ CK_PR_OR_T(w, a, b); \ } \ rg_width(w); \ printf(" SUCCESS\n"); \ } #define CK_PR_OR_W(m, w) \ { \ uint##m##_t t = 0; \ ck_pr_or_##w((uint##w##_t *)(void *)&t, -1); \ if (t != BM(m, w)) { \ printf(" FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, BM(m, w)); \ exit(EXIT_FAILURE); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_OR_64 if (m == 64) { #if defined(CK_F_PR_OR_32) CK_PR_OR_W(64, 32); #endif #if defined(CK_PR_OR_16) CK_PR_OR_W(64, 16); #endif #if defined(CK_PR_OR_8) CK_PR_OR_W(64, 8); #endif } #endif /* CK_PR_OR_64 */ #ifdef CK_F_PR_OR_32 if (m == 32) { #if defined(CK_F_PR_OR_16) CK_PR_OR_W(32, 16); #endif #if defined(CK_PR_OR_8) CK_PR_OR_W(32, 8); #endif } #endif /* CK_PR_OR_32 */ #if defined(CK_F_PR_OR_16) && defined(CK_PR_OR_8) if (m == 16) { CK_PR_OR_W(16, 8); } #endif /* CK_PR_OR_16 && CK_PR_OR_8 */ return; } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_OR_64 CK_PR_OR_B(64); #endif #ifdef CK_F_PR_OR_32 CK_PR_OR_B(32); #endif #ifdef CK_F_PR_OR_16 CK_PR_OR_B(16); #endif #ifdef CK_F_PR_OR_8 CK_PR_OR_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_store.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "../../common.h" #include #include #include #include #include #include #include #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define CK_PR_STORE_B(w) \ { \ uint##w##_t t = (uint##w##_t)-1, a = 0, b; \ ck_pr_store_##w(&b, 1ULL << (w - 1)); \ unsigned int i; \ printf("ck_pr_store_" #w ": "); \ if (w < 10) \ printf(" "); \ ck_pr_store_##w(&a, t); \ if (a != t) { \ printf("FAIL [%#" PRIx##w " != %#" PRIx##w "]\n", a, t); \ exit(EXIT_FAILURE); \ } \ for (i = 0; i < R_REPEAT; i++) { \ t = (uint##w##_t)common_rand(); \ ck_pr_store_##w(&a, t); \ if (a != t) { \ printf("FAIL [%#" PRIx##w " != %#" PRIx##w "]\n", a, t);\ exit(EXIT_FAILURE); \ } \ } \ rg_width(w); \ printf("SUCCESS\n"); \ } #define CK_PR_STORE_W(m, w) \ { \ uint##m##_t f = 0; \ uint##w##_t j = (uint##w##_t)-1; \ ck_pr_store_##w((uint##w##_t *)(void *)&f, j); \ if (f != j) { \ printf("FAIL [%#" PRIx##m " != %#" PRIx##w "]\n", f, j);\ exit(EXIT_FAILURE); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_STORE_64 if (m == 64) { #if defined(CK_F_PR_STORE_32) CK_PR_STORE_W(64, 32); #endif #if defined(CK_PR_STORE_16) CK_PR_STORE_W(64, 16); #endif #if defined(CK_PR_STORE_8) CK_PR_STORE_W(64, 8); #endif } #endif /* CK_PR_STORE_64 */ #ifdef CK_F_PR_STORE_32 if (m == 32) { #if defined(CK_F_PR_STORE_16) CK_PR_STORE_W(32, 16); #endif #if defined(CK_PR_STORE_8) CK_PR_STORE_W(32, 8); #endif } #endif /* CK_PR_STORE_32 */ #if defined(CK_F_PR_STORE_16) && defined(CK_PR_STORE_8) if (m == 16) CK_PR_STORE_W(16, 8); #endif /* CK_PR_STORE_16 && CK_PR_STORE_8 */ return; } int main(void) { #if defined(CK_F_PR_STORE_DOUBLE) && defined(CK_F_PR_LOAD_DOUBLE) double d; ck_pr_store_double(&d, 0.0); if (ck_pr_load_double(&d) != 0.0) { ck_error("Stored 0 in double, did not find 0.\n"); } #endif common_srand((unsigned int)getpid()); #ifdef CK_F_PR_STORE_64 CK_PR_STORE_B(64); #endif #ifdef CK_F_PR_STORE_32 CK_PR_STORE_B(32); #endif #ifdef CK_F_PR_STORE_16 CK_PR_STORE_B(16); #endif #ifdef CK_F_PR_STORE_8 CK_PR_STORE_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_sub.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define CK_PR_SUB_T(w, v, d) \ { \ uint##w##_t t = v; \ ck_pr_sub_##w(&t, d); \ if (t != (uint##w##_t)(v - d)) { \ printf("FAIL ["); \ printf("%" PRIu##w " (%" PRIu##w ") -> %" PRIu##w "]\n", \ (uint##w##_t)v, d, t); \ exit(EXIT_FAILURE); \ } \ } #define CK_PR_SUB_B(w) \ { \ unsigned int __ck_i = 0; \ printf("ck_pr_sub_" #w ": "); \ if (w < 10) \ printf(" "); \ for (__ck_i = 0; __ck_i < R_REPEAT; __ck_i++) { \ uint##w##_t a = common_rand() % ((uint##w##_t)-1 / 2); \ uint##w##_t b = common_rand() % ((uint##w##_t)-1 / 2); \ CK_PR_SUB_T(w, a, b); \ } \ rg_width(w); \ printf(" SUCCESS\n"); \ } #define CK_PR_SUB_W(m, w) \ { \ uint##m##_t t = 0, r = (uint##m##_t)(uint##w##_t)-1; \ ck_pr_sub_##w((uint##w##_t *)(void *)&t, 1); \ if (t != r) { \ printf(" FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, r); \ exit(EXIT_FAILURE); \ } \ t = 0; \ ck_pr_sub_##w((uint##w##_t *)(void *)&t, -1); \ if (t != 1) { \ printf(" FAIL [%#" PRIx##m " != 1]\n", t); \ exit(EXIT_FAILURE); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_SUB_64 if (m == 64) { #if defined(CK_F_PR_SUB_32) CK_PR_SUB_W(64, 32); #endif #if defined(CK_PR_SUB_16) CK_PR_SUB_W(64, 16); #endif #if defined(CK_PR_SUB_8) CK_PR_SUB_W(64, 8); #endif } #endif /* CK_PR_SUB_64 */ #ifdef CK_F_PR_SUB_32 if (m == 32) { #if defined(CK_F_PR_SUB_16) CK_PR_SUB_W(32, 16); #endif #if defined(CK_PR_SUB_8) CK_PR_SUB_W(32, 8); #endif } #endif /* CK_PR_SUB_32 */ #if defined(CK_F_PR_SUB_16) && defined(CK_PR_SUB_8) if (m == 16) { CK_PR_SUB_W(16, 8); } #endif /* CK_PR_SUB_16 && CK_PR_SUB_8 */ return; } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_SUB_64 CK_PR_SUB_B(64); #endif #ifdef CK_F_PR_SUB_32 CK_PR_SUB_B(32); #endif #ifdef CK_F_PR_SUB_16 CK_PR_SUB_B(16); #endif #ifdef CK_F_PR_SUB_8 CK_PR_SUB_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_unary.c ================================================ /* * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #define REPEAT 2000000 #define TEST_UNARY(K, S, M, T, P, D, H) \ static void \ test_##K##_##S(M *target) \ { \ *target = *target P 1; \ \ return; \ } \ static void \ test_##K##_##S##_zero(M *target, bool *zero) \ { \ *zero = *target == H; \ *target = *target P 1; \ \ return; \ } \ static void \ run_test_##K##_##S(bool use_zero) \ { \ int i; \ T x = 1, y = 1; \ bool zero_x = false, zero_y = false; \ \ use_zero ? puts("***TESTING ck_pr_"#K"_"#S"_zero***") \ : puts("***TESTING ck_pr_"#K"_"#S"***"); \ for (i = 0; i < REPEAT; ++i) { \ if (use_zero) { \ test_##K##_##S##_zero(&x, &zero_x); \ ck_pr_##K##_##S##_zero(&y, &zero_y); \ } \ else { \ test_##K##_##S(&x); \ ck_pr_##K##_##S(&y); \ } \ \ if (x != y || zero_x != zero_y) { \ printf("Serial(%"#D") and ck_pr(%"#D")" \ #K"_"#S" do not match.\n" \ "FAILURE.\n", \ x, y); \ \ return; \ } \ \ if (zero_x) \ printf("Variables are zero at iteration %d\n", i); \ } \ \ \ printf("\tserial_"#K"_"#S": %"#D"\n" \ "\tck_pr_"#K"_"#S": %"#D"\n" \ "SUCCESS.\n", \ x, y); \ \ return; \ } #define GENERATE_TEST(K, P, Y, Z) \ TEST_UNARY(K, int, int, int, P, d, Y) \ TEST_UNARY(K, uint, unsigned int, unsigned int, P, u, Z) \ static void \ run_test_##K(void) \ { \ run_test_##K##_int(false); \ run_test_##K##_int(true); \ run_test_##K##_uint(false); \ run_test_##K##_uint(true); \ } GENERATE_TEST(inc, +, -1, UINT_MAX) GENERATE_TEST(dec, -, 1, 1) #undef GENERATE_TEST #undef TEST_UNARY int main(void) { run_test_inc(); run_test_dec(); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_pr/validate/ck_pr_xor.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef R_REPEAT #define R_REPEAT 200000 #endif #define BM(m, w) ((uint##m##_t)-1 << (w)) #define CK_PR_XOR_T(w, v, d) \ { \ uint##w##_t t = v; \ ck_pr_xor_##w(&t, d); \ if (t != (uint##w##_t)(v ^ d)) { \ printf("FAIL ["); \ printf("%" PRIu##w " (%" PRIu##w ") -> %" PRIu##w "]\n",\ (uint##w##_t)v, d, t); \ exit(EXIT_FAILURE); \ } \ } #define CK_PR_XOR_B(w) \ { \ unsigned int __ck_i = 0; \ printf("ck_pr_xor_" #w ": "); \ if (w < 10) \ printf(" "); \ for (__ck_i = 0; __ck_i < R_REPEAT; __ck_i++) { \ uint##w##_t a = (uint##w##_t)common_rand(); \ uint##w##_t b = (uint##w##_t)common_rand(); \ CK_PR_XOR_T(w, a, b); \ } \ rg_width(w); \ printf(" SUCCESS\n"); \ } #define CK_PR_XOR_W(m, w) \ { \ uint##m##_t t = -1; \ ck_pr_xor_##w((uint##w##_t *)(void *)&t, -1); \ if (t != BM(m, w)) { \ printf(" FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, BM(m, w)); \ exit(EXIT_FAILURE); \ } \ } static void rg_width(int m) { /* Other architectures are bi-endian. */ #if !defined(__x86__) && !defined(__x86_64__) return; #endif #ifdef CK_F_PR_XOR_64 if (m == 64) { #if defined(CK_F_PR_XOR_32) CK_PR_XOR_W(64, 32); #endif #if defined(CK_PR_XOR_16) CK_PR_XOR_W(64, 16); #endif #if defined(CK_PR_XOR_8) CK_PR_XOR_W(64, 8); #endif } #endif /* CK_PR_XOR_64 */ #ifdef CK_F_PR_XOR_32 if (m == 32) { #if defined(CK_F_PR_XOR_16) CK_PR_XOR_W(32, 16); #endif #if defined(CK_PR_XOR_8) CK_PR_XOR_W(32, 8); #endif } #endif /* CK_PR_XOR_32 */ #if defined(CK_F_PR_XOR_16) && defined(CK_PR_XOR_8) if (m == 16) { CK_PR_XOR_W(16, 8); } #endif /* CK_PR_XOR_16 && CK_PR_XOR_8 */ return; } int main(void) { common_srand((unsigned int)getpid()); #ifdef CK_F_PR_XOR_64 CK_PR_XOR_B(64); #endif #ifdef CK_F_PR_XOR_32 CK_PR_XOR_B(32); #endif #ifdef CK_F_PR_XOR_16 CK_PR_XOR_B(16); #endif #ifdef CK_F_PR_XOR_8 CK_PR_XOR_B(8); #endif return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_queue/validate/ck_list.c ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "../../common.h" struct test { int value; CK_LIST_ENTRY(test) list_entry; }; static CK_LIST_HEAD(test_list, test) head = CK_LIST_HEAD_INITIALIZER(head); static int goal; static void test_foreach(void) { struct test *n, *next, *safe; int i, s = 0, j = 0, k = 0; for (i = goal; i != 0; i = goal) { s = 0; CK_LIST_FOREACH(n, &head, list_entry) { j++; if (s == 0) s = n->value; else s = s - 1; if (n->value != s) { ck_error("\nExpected %d, but got %d.\n", s, n->value); } next = CK_LIST_NEXT(n, list_entry); if (next != NULL && next->value != s - 1) { ck_error("\nExpected %d, but got %d.\n", s, next->value); } i--; } if (i == 0) break; s = 0; CK_LIST_FOREACH_SAFE(n, &head, list_entry, safe) { k++; if (s == 0) s = n->value; else s = s - 1; if (n->value != s) { ck_error("\nExpected %d, but got %d.\n", s, n->value); } next = CK_LIST_NEXT(n, list_entry); if (next != NULL && next->value != s - 1) { ck_error("\nExpected %d, but got %d.\n", s, next->value); } i--; } if (i == 0 || CK_LIST_EMPTY(&head) == true) break; } fprintf(stderr, "(%d, %d) ", j, k); return; } static void * execute(void *c) { (void)c; test_foreach(); return NULL; } int main(int argc, char *argv[]) { pthread_t *thread; struct test *n, a, b; struct test_list target; int n_threads, i; if (argc != 3) { ck_error("Usage: %s \n", argv[0]); } n_threads = atoi(argv[1]); if (n_threads < 1) { ck_error("ERROR: Number of threads must be >= 1.\n"); } thread = malloc(sizeof(pthread_t) * n_threads); assert(thread != NULL); goal = atoi(argv[2]); if (goal < 4) { ck_error("ERROR: Number of entries must be >= 4.\n"); } fprintf(stderr, "Beginning serial test..."); CK_LIST_INIT(&head); for (i = 1; i <= goal; i++) { n = malloc(sizeof *n); assert(n != NULL); n->value = i; CK_LIST_INSERT_HEAD(&head, n, list_entry); } test_foreach(); for (i = 1; i <= goal; i++) { n = CK_LIST_FIRST(&head); CK_LIST_REMOVE(n, list_entry); free(n); } CK_LIST_INSERT_HEAD(&head, &a, list_entry); CK_LIST_INSERT_HEAD(&head, &b, list_entry); CK_LIST_REMOVE(&a, list_entry); if (CK_LIST_FIRST(&head) != &b) ck_error("List is in invalid state.\n"); CK_LIST_REMOVE(&b, list_entry); if (CK_LIST_EMPTY(&head) == false) { ck_error("List is not empty after bulk removal.\n"); } CK_LIST_INSERT_HEAD(&head, &a, list_entry); CK_LIST_INSERT_AFTER(&a, &b, list_entry); if (CK_LIST_NEXT(&b, list_entry) != NULL) ck_error("Inserted item after last, it should not have no next.\n"); CK_LIST_INIT(&head); CK_LIST_INSERT_HEAD(&head, &a, list_entry); CK_LIST_INSERT_BEFORE(&a, &b, list_entry); if (CK_LIST_NEXT(&b, list_entry) != &a) ck_error("Inserted item before last, it should point to last.\n"); CK_LIST_INIT(&head); fprintf(stderr, "done (success)\n"); fprintf(stderr, "Beginning parallel traversal..."); n = malloc(sizeof *n); assert(n != NULL); n->value = 1; CK_LIST_INSERT_HEAD(&head, n, list_entry); for (i = 0; i < n_threads; i++) { int r = pthread_create(&thread[i], NULL, execute, NULL); assert(r == 0); } for (i = 2; i <= goal; i++) { volatile int j; n = malloc(sizeof *n); assert(n != NULL); n->value = i; CK_LIST_INSERT_HEAD(&head, n, list_entry); for (j = 0; j <= 1000; j++); } for (i = 0; i < n_threads; i++) pthread_join(thread[i], NULL); for (i = 0; i < n_threads; i++) { int r = pthread_create(&thread[i], NULL, execute, NULL); assert(r == 0); } CK_LIST_MOVE(&target, &head, list_entry); for (i = 1; i <= goal; i++) { volatile int j; if (CK_LIST_EMPTY(&target) == false) { struct test *r = CK_LIST_FIRST(&target); CK_LIST_REMOVE(r, list_entry); } for (j = 0; j <= 1000; j++); } for (i = 0; i < n_threads; i++) pthread_join(thread[i], NULL); fprintf(stderr, "done (success)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_queue/validate/ck_slist.c ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "../../common.h" struct test { int value; CK_SLIST_ENTRY(test) list_entry; }; static CK_SLIST_HEAD(test_list, test) head = CK_SLIST_HEAD_INITIALIZER(head); static int goal; static void test_foreach(void) { struct test *n, *next, *safe; int i, s = 0, j = 0, k = 0; for (i = goal; i != 0; i = goal) { s = 0; CK_SLIST_FOREACH(n, &head, list_entry) { j++; if (s == 0) s = n->value; else s = s - 1; if (n->value != s) { ck_error("\nExpected %d, but got %d.\n", s, n->value); } next = CK_SLIST_NEXT(n, list_entry); if (next != NULL && next->value != s - 1) { ck_error("\nExpected %d, but got %d.\n", s, next->value); } i--; } if (i == 0) break; s = 0; CK_SLIST_FOREACH_SAFE(n, &head, list_entry, safe) { k++; if (s == 0) s = n->value; else s = s - 1; if (n->value != s) { ck_error("\nExpected %d, but got %d.\n", s, n->value); } next = CK_SLIST_NEXT(n, list_entry); if (next != NULL && next->value != s - 1) { ck_error("\nExpected %d, but got %d.\n", s, next->value); } i--; } if (i == 0 || CK_SLIST_EMPTY(&head) == true) break; } fprintf(stderr, "(%d, %d) ", j, k); return; } static void * execute(void *c) { (void)c; test_foreach(); return NULL; } int main(int argc, char *argv[]) { pthread_t *thread; struct test *n; struct test_list target; int n_threads, i; if (argc != 3) { ck_error("Usage: %s \n", argv[0]); } n_threads = atoi(argv[1]); if (n_threads < 1) { ck_error("ERROR: Number of threads must be >= 1.\n"); } thread = malloc(sizeof(pthread_t) * n_threads); assert(thread != NULL); goal = atoi(argv[2]); if (goal < 4) { ck_error("ERROR: Number of entries must be >= 4.\n"); } fprintf(stderr, "Beginning serial test..."); CK_SLIST_INIT(&head); for (i = 1; i <= goal; i++) { n = malloc(sizeof *n); assert(n != NULL); n->value = i; CK_SLIST_INSERT_HEAD(&head, n, list_entry); } test_foreach(); for (i = 1; i <= goal; i++) { n = CK_SLIST_FIRST(&head); CK_SLIST_REMOVE_HEAD(&head, list_entry); free(n); } if (CK_SLIST_EMPTY(&head) == false) { ck_error("List is not empty after bulk removal.\n"); } fprintf(stderr, "done (success)\n"); fprintf(stderr, "Beginning parallel traversal..."); n = malloc(sizeof *n); assert(n != NULL); n->value = 1; CK_SLIST_INSERT_HEAD(&head, n, list_entry); for (i = 0; i < n_threads; i++) { int r = pthread_create(&thread[i], NULL, execute, NULL); assert(r == 0); } for (i = 2; i <= goal; i++) { volatile int j; n = malloc(sizeof *n); assert(n != NULL); n->value = i; CK_SLIST_INSERT_HEAD(&head, n, list_entry); for (j = 0; j <= 1000; j++); } for (i = 0; i < n_threads; i++) pthread_join(thread[i], NULL); for (i = 0; i < n_threads; i++) { int r = pthread_create(&thread[i], NULL, execute, NULL); assert(r == 0); } CK_SLIST_MOVE(&target, &head, list_entry); for (i = 1; i <= goal; i++) { volatile int j; if (CK_SLIST_EMPTY(&target) == false) CK_SLIST_REMOVE_HEAD(&target, list_entry); for (j = 0; j <= 1000; j++); if (CK_SLIST_EMPTY(&target) == false) { struct test *r = CK_SLIST_FIRST(&target); CK_SLIST_REMOVE(&target, r, test, list_entry); } } for (i = 0; i < n_threads; i++) pthread_join(thread[i], NULL); fprintf(stderr, "done (success)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_queue/validate/ck_stailq.c ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "../../common.h" struct test { int value; CK_STAILQ_ENTRY(test) list_entry; }; static CK_STAILQ_HEAD(test_list, test) head = CK_STAILQ_HEAD_INITIALIZER(head); static int goal; static void test_foreach(void) { struct test *n, *next, *safe; int i, s = 0, j = 0, k = 0; for (i = goal; i != 0; i = goal) { s = 0; CK_STAILQ_FOREACH(n, &head, list_entry) { j++; if (s == 0) s = n->value; else s = s - 1; if (n->value != s) { ck_error("\nExpected %d, but got %d.\n", s, n->value); } next = CK_STAILQ_NEXT(n, list_entry); if (next != NULL && next->value != s - 1) { ck_error("\nExpected %d, but got %d.\n", s, next->value); } i--; } if (i == 0) break; s = 0; CK_STAILQ_FOREACH_SAFE(n, &head, list_entry, safe) { k++; if (s == 0) s = n->value; else s = s - 1; if (n->value != s) { ck_error("\nExpected %d, but got %d.\n", s, n->value); } next = CK_STAILQ_NEXT(n, list_entry); if (next != NULL && next->value != s - 1) { ck_error("\nExpected %d, but got %d.\n", s, next->value); } i--; } if (i == 0 || CK_STAILQ_EMPTY(&head) == true) break; } fprintf(stderr, "(%d, %d) ", j, k); return; } static void * execute(void *c) { (void)c; test_foreach(); return NULL; } int main(int argc, char *argv[]) { pthread_t *thread; struct test *n, a, b; struct test_list target; int n_threads, i; if (argc != 3) { ck_error("Usage: %s \n", argv[0]); } n_threads = atoi(argv[1]); if (n_threads < 1) { ck_error("ERROR: Number of threads must be >= 1.\n"); } thread = malloc(sizeof(pthread_t) * n_threads); assert(thread != NULL); goal = atoi(argv[2]); if (goal < 4) { ck_error("ERROR: Number of entries must be >= 4.\n"); } fprintf(stderr, "Beginning serial test..."); CK_STAILQ_INIT(&head); for (i = 1; i <= goal; i++) { n = malloc(sizeof *n); assert(n != NULL); n->value = i; CK_STAILQ_INSERT_HEAD(&head, n, list_entry); } test_foreach(); for (i = 1; i <= goal; i++) { n = CK_STAILQ_FIRST(&head); CK_STAILQ_REMOVE(&head, n, test, list_entry); free(n); } if (CK_STAILQ_EMPTY(&head) == false) { ck_error("List is not empty after bulk removal.\n"); } for (i = 1; i <= goal; i++) { n = malloc(sizeof *n); assert(n != NULL); n->value = goal - i; CK_STAILQ_INSERT_TAIL(&head, n, list_entry); } test_foreach(); for (i = 1; i <= goal; i++) { n = CK_STAILQ_FIRST(&head); CK_STAILQ_REMOVE(&head, n, test, list_entry); free(n); } if (CK_STAILQ_EMPTY(&head) == false) { ck_error("List is not empty after bulk removal.\n"); } CK_STAILQ_INSERT_HEAD(&head, &a, list_entry); CK_STAILQ_INSERT_HEAD(&head, &b, list_entry); CK_STAILQ_REMOVE(&head, &a, test, list_entry); if (CK_STAILQ_FIRST(&head) != &b) ck_error("List is in invalid state.\n"); CK_STAILQ_REMOVE(&head, &b, test, list_entry); if (CK_STAILQ_EMPTY(&head) == false) { ck_error("List is not empty after bulk removal.\n"); } CK_STAILQ_INSERT_HEAD(&head, &a, list_entry); CK_STAILQ_INSERT_AFTER(&head, &a, &b, list_entry); if (CK_STAILQ_NEXT(&b, list_entry) != NULL) ck_error("Inserted item after last, it should not have no next.\n"); CK_STAILQ_INIT(&head); CK_STAILQ_INSERT_HEAD(&head, &a, list_entry); if (CK_STAILQ_NEXT(&a, list_entry) != NULL) ck_error("Inserted item as last, but it contains next pointer.\n"); CK_STAILQ_INIT(&head); fprintf(stderr, "done (success)\n"); fprintf(stderr, "Beginning parallel traversal..."); n = malloc(sizeof *n); assert(n != NULL); n->value = 1; CK_STAILQ_INSERT_HEAD(&head, n, list_entry); for (i = 0; i < n_threads; i++) { int r = pthread_create(&thread[i], NULL, execute, NULL); assert(r == 0); } for (i = 2; i <= goal; i++) { volatile int j; n = malloc(sizeof *n); assert(n != NULL); n->value = i; CK_STAILQ_INSERT_HEAD(&head, n, list_entry); for (j = 0; j <= 1000; j++); } for (i = 0; i < n_threads; i++) pthread_join(thread[i], NULL); for (i = 0; i < n_threads; i++) { int r = pthread_create(&thread[i], NULL, execute, NULL); assert(r == 0); } CK_STAILQ_MOVE(&target, &head, list_entry); for (i = 1; i <= goal; i++) { volatile int j; if (CK_STAILQ_EMPTY(&target) == false) { struct test *r = CK_STAILQ_FIRST(&target); CK_STAILQ_REMOVE(&target, r, test, list_entry); } for (j = 0; j <= 1000; j++); } for (i = 0; i < n_threads; i++) pthread_join(thread[i], NULL); fprintf(stderr, "done (success)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rhs/benchmark/parallel_bytestring.c ================================================ /* * Copyright 2012 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyrights * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyrights * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "../../common.h" #include #include "../../../src/ck_ht_hash.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include static ck_rhs_t hs CK_CC_CACHELINE; static char **keys; static size_t keys_length = 0; static size_t keys_capacity = 128; static ck_epoch_t epoch_hs; static ck_epoch_record_t epoch_wr; static int n_threads; static bool next_stage; enum state { HS_STATE_STOP = 0, HS_STATE_GET, HS_STATE_STRICT_REPLACEMENT, HS_STATE_DELETION, HS_STATE_REPLACEMENT, HS_STATE_COUNT }; static ck_spinlock_t mtx = CK_SPINLOCK_INITIALIZER; static struct affinity affinerator = AFFINITY_INITIALIZER; static uint64_t accumulator[HS_STATE_COUNT]; static int barrier[HS_STATE_COUNT]; static int state; struct hs_epoch { ck_epoch_entry_t epoch_entry; }; COMMON_ALARM_DECLARE_GLOBAL(hs_alarm, alarm_event, next_stage) static void alarm_handler(int s) { (void)s; next_stage = true; return; } static unsigned long hs_hash(const void *object, unsigned long seed) { const char *c = object; unsigned long h; h = (unsigned long)MurmurHash64A(c, strlen(c), seed); return h; } static bool hs_compare(const void *previous, const void *compare) { return strcmp(previous, compare) == 0; } static void hs_destroy(ck_epoch_entry_t *e) { free(e); return; } static void * hs_malloc(size_t r) { ck_epoch_entry_t *b; b = malloc(sizeof(*b) + r); return b + 1; } static void hs_free(void *p, size_t b, bool r) { struct hs_epoch *e = p; (void)b; if (r == true) { /* Destruction requires safe memory reclamation. */ ck_epoch_call(&epoch_wr, &(--e)->epoch_entry, hs_destroy); } else { free(--e); } return; } static struct ck_malloc my_allocator = { .malloc = hs_malloc, .free = hs_free }; static void set_init(void) { unsigned int mode = CK_RHS_MODE_OBJECT | CK_RHS_MODE_SPMC; ck_epoch_init(&epoch_hs); ck_epoch_register(&epoch_hs, &epoch_wr, NULL); common_srand48((long int)time(NULL)); if (ck_rhs_init(&hs, mode, hs_hash, hs_compare, &my_allocator, 65536, common_lrand48()) == false) { perror("ck_rhs_init"); exit(EXIT_FAILURE); } return; } static bool set_remove(const char *value) { unsigned long h; h = CK_RHS_HASH(&hs, hs_hash, value); return (bool)ck_rhs_remove(&hs, h, value); } static bool set_replace(const char *value) { unsigned long h; void *previous; h = CK_RHS_HASH(&hs, hs_hash, value); return ck_rhs_set(&hs, h, value, &previous); } static bool set_swap(const char *value) { unsigned long h; void *previous; h = CK_RHS_HASH(&hs, hs_hash, value); return ck_rhs_fas(&hs, h, value, &previous); } static void * set_get(const char *value) { unsigned long h; void *v; h = CK_RHS_HASH(&hs, hs_hash, value); v = ck_rhs_get(&hs, h, value); return v; } static bool set_insert(const char *value) { unsigned long h; h = CK_RHS_HASH(&hs, hs_hash, value); return ck_rhs_put(&hs, h, value); } static size_t set_count(void) { return ck_rhs_count(&hs); } static bool set_reset(void) { return ck_rhs_reset(&hs); } static void * reader(void *unused) { size_t i; ck_epoch_record_t epoch_record; int state_previous = HS_STATE_STOP; int n_state = 0; uint64_t s, j, a; (void)unused; if (aff_iterate(&affinerator) != 0) perror("WARNING: Failed to affine thread"); s = j = a = 0; ck_epoch_register(&epoch_hs, &epoch_record, NULL); for (;;) { j++; ck_epoch_begin(&epoch_record, NULL); s = rdtsc(); for (i = 0; i < keys_length; i++) { char *r; r = set_get(keys[i]); if (r == NULL) { if (n_state == HS_STATE_STRICT_REPLACEMENT) { ck_error("ERROR: Did not find during replacement: %s\n", keys[i]); } continue; } if (strcmp(r, keys[i]) == 0) continue; ck_error("ERROR: Found invalid value: [%s] but expected [%s]\n", (char *)r, keys[i]); } a += rdtsc() - s; ck_epoch_end(&epoch_record, NULL); n_state = ck_pr_load_int(&state); if (n_state != state_previous) { ck_spinlock_lock(&mtx); accumulator[state_previous] += a / (j * keys_length); ck_spinlock_unlock(&mtx); ck_pr_inc_int(&barrier[state_previous]); while (ck_pr_load_int(&barrier[state_previous]) != n_threads + 1) ck_pr_stall(); state_previous = n_state; s = j = a = 0; } } return NULL; } static uint64_t acc(size_t i) { uint64_t r; ck_spinlock_lock(&mtx); r = accumulator[i]; ck_spinlock_unlock(&mtx); return r; } int main(int argc, char *argv[]) { FILE *fp; char buffer[512]; size_t i, j, r; unsigned int d = 0; uint64_t s, e, a, repeated; char **t; pthread_t *readers; double p_r, p_d; COMMON_ALARM_DECLARE_LOCAL(hs_alarm, alarm_event) r = 20; s = 8; p_d = 0.5; p_r = 0.5; n_threads = CORES - 1; if (argc < 2) { ck_error("Usage: parallel [ \n" " ]\n"); } if (argc >= 3) r = atoi(argv[2]); if (argc >= 4) s = (uint64_t)atoi(argv[3]); if (argc >= 5) { n_threads = atoi(argv[4]); if (n_threads < 1) { ck_error("ERROR: Number of readers must be >= 1.\n"); } } if (argc >= 6) { p_r = atof(argv[5]) / 100.00; if (p_r < 0) { ck_error("ERROR: Probability of replacement must be >= 0 and <= 100.\n"); } } if (argc >= 7) { p_d = atof(argv[6]) / 100.00; if (p_d < 0) { ck_error("ERROR: Probability of deletion must be >= 0 and <= 100.\n"); } } COMMON_ALARM_INIT(hs_alarm, alarm_event, r) affinerator.delta = 1; readers = malloc(sizeof(pthread_t) * n_threads); assert(readers != NULL); keys = malloc(sizeof(char *) * keys_capacity); assert(keys != NULL); fp = fopen(argv[1], "r"); assert(fp != NULL); while (fgets(buffer, sizeof(buffer), fp) != NULL) { buffer[strlen(buffer) - 1] = '\0'; keys[keys_length++] = strdup(buffer); assert(keys[keys_length - 1] != NULL); if (keys_length == keys_capacity) { t = realloc(keys, sizeof(char *) * (keys_capacity *= 2)); assert(t != NULL); keys = t; } } t = realloc(keys, sizeof(char *) * keys_length); assert(t != NULL); keys = t; set_init(); for (i = 0; i < (size_t)n_threads; i++) { if (pthread_create(&readers[i], NULL, reader, NULL) != 0) { ck_error("ERROR: Failed to create thread %zu.\n", i); } } for (i = 0; i < keys_length; i++) d += set_insert(keys[i]) == false; fprintf(stderr, " [S] %d readers, 1 writer.\n", n_threads); fprintf(stderr, " [S] %zu entries stored and %u duplicates.\n\n", set_count(), d); fprintf(stderr, " ,- BASIC TEST\n"); fprintf(stderr, " | Executing SMR test..."); a = 0; for (j = 0; j < r; j++) { if (set_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = 0; i < keys_length; i++) d += set_insert(keys[i]) == false; e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing replacement test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_replace(keys[i]); e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing get test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { if (set_get(keys[i]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); a = 0; fprintf(stderr, " | Executing removal test..."); for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_remove(keys[i]); e = rdtsc(); a += e - s; for (i = 0; i < keys_length; i++) set_insert(keys[i]); } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); fprintf(stderr, " | Executing negative look-up test..."); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { set_get("\x50\x03\x04\x05\x06\x10"); } e = rdtsc(); a += e - s; } fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length)); ck_epoch_record_t epoch_temporary = epoch_wr; ck_epoch_synchronize(&epoch_wr); fprintf(stderr, " '- Summary: %u pending, %u peak, %u reclamations -> " "%u pending, %u peak, %u reclamations\n\n", epoch_temporary.n_pending, epoch_temporary.n_peak, epoch_temporary.n_dispatch, epoch_wr.n_pending, epoch_wr.n_peak, epoch_wr.n_dispatch); fprintf(stderr, " ,- READER CONCURRENCY\n"); fprintf(stderr, " | Executing reader test..."); ck_pr_store_int(&state, HS_STATE_GET); while (ck_pr_load_int(&barrier[HS_STATE_STOP]) != n_threads) ck_pr_stall(); ck_pr_inc_int(&barrier[HS_STATE_STOP]); common_sleep(r); ck_pr_store_int(&state, HS_STATE_STRICT_REPLACEMENT); while (ck_pr_load_int(&barrier[HS_STATE_GET]) != n_threads) ck_pr_stall(); fprintf(stderr, "done (reader = %" PRIu64 " ticks)\n", acc(HS_STATE_GET) / n_threads); fprintf(stderr, " | Executing strict replacement test..."); a = repeated = 0; common_alarm(alarm_handler, &alarm_event, r); ck_pr_inc_int(&barrier[HS_STATE_GET]); for (;;) { repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) { if (i & 1) { set_replace(keys[i]); } else { set_swap(keys[i]); } } e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HS_STATE_DELETION); while (ck_pr_load_int(&barrier[HS_STATE_STRICT_REPLACEMENT]) != n_threads) ck_pr_stall(); set_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), acc(HS_STATE_STRICT_REPLACEMENT) / n_threads); common_alarm(alarm_handler, &alarm_event, r); fprintf(stderr, " | Executing deletion test (%.2f)...", p_d * 100); a = repeated = 0; ck_pr_inc_int(&barrier[HS_STATE_STRICT_REPLACEMENT]); for (;;) { double delete; repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) { set_insert(keys[i]); if (p_d != 0.0) { delete = common_drand48(); if (delete <= p_d) set_remove(keys[i]); } } e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HS_STATE_REPLACEMENT); while (ck_pr_load_int(&barrier[HS_STATE_DELETION]) != n_threads) ck_pr_stall(); set_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), acc(HS_STATE_DELETION) / n_threads); common_alarm(alarm_handler, &alarm_event, r); fprintf(stderr, " | Executing replacement test (%.2f)...", p_r * 100); a = repeated = 0; ck_pr_inc_int(&barrier[HS_STATE_DELETION]); for (;;) { double delete, replace; repeated++; s = rdtsc(); for (i = 0; i < keys_length; i++) { set_insert(keys[i]); if (p_d != 0.0) { delete = common_drand48(); if (delete <= p_d) set_remove(keys[i]); } else { delete = 0.0; } if (p_r != 0.0) { replace = common_drand48(); if (replace <= p_r) { if ((i & 1) || (delete <= p_d)) { set_replace(keys[i]); } else { set_swap(keys[i]); } } } } e = rdtsc(); a += e - s; if (next_stage == true) { next_stage = false; break; } } ck_pr_store_int(&state, HS_STATE_STOP); while (ck_pr_load_int(&barrier[HS_STATE_REPLACEMENT]) != n_threads) ck_pr_stall(); set_reset(); ck_epoch_synchronize(&epoch_wr); fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n", a / (repeated * keys_length), acc(HS_STATE_REPLACEMENT) / n_threads); ck_pr_inc_int(&barrier[HS_STATE_REPLACEMENT]); epoch_temporary = epoch_wr; ck_epoch_synchronize(&epoch_wr); fprintf(stderr, " '- Summary: %u pending, %u peak, %u reclamations -> " "%u pending, %u peak, %u reclamations\n\n", epoch_temporary.n_pending, epoch_temporary.n_peak, epoch_temporary.n_dispatch, epoch_wr.n_pending, epoch_wr.n_peak, epoch_wr.n_dispatch); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rhs/benchmark/serial.c ================================================ /* * Copyright 2012 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyrights * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyrights * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "../../common.h" #include "../../../src/ck_ht_hash.h" static ck_rhs_t hs; static char **keys; static size_t keys_length = 0; static size_t keys_capacity = 128; static unsigned long global_seed; static void * hs_malloc(size_t r) { return malloc(r); } static void hs_free(void *p, size_t b, bool r) { (void)b; (void)r; free(p); return; } static struct ck_malloc my_allocator = { .malloc = hs_malloc, .free = hs_free }; static unsigned long hs_hash(const void *object, unsigned long seed) { const char *c = object; unsigned long h; h = (unsigned long)MurmurHash64A(c, strlen(c), seed); return h; } static bool hs_compare(const void *previous, const void *compare) { return strcmp(previous, compare) == 0; } static void set_destroy(void) { ck_rhs_destroy(&hs); return; } static void set_init(unsigned int size, unsigned int mode) { if (ck_rhs_init(&hs, CK_RHS_MODE_OBJECT | CK_RHS_MODE_SPMC | mode, hs_hash, hs_compare, &my_allocator, size, global_seed) == false) { perror("ck_rhs_init"); exit(EXIT_FAILURE); } return; } static bool set_remove(const char *value) { unsigned long h; h = CK_RHS_HASH(&hs, hs_hash, value); return ck_rhs_remove(&hs, h, value) != NULL; } static bool set_swap(const char *value) { unsigned long h; void *previous; h = CK_RHS_HASH(&hs, hs_hash, value); return ck_rhs_fas(&hs, h, value, &previous); } static bool set_replace(const char *value) { unsigned long h; void *previous; h = CK_RHS_HASH(&hs, hs_hash, value); ck_rhs_set(&hs, h, value, &previous); return previous != NULL; } static void * set_get(const char *value) { unsigned long h; void *v; h = CK_RHS_HASH(&hs, hs_hash, value); v = ck_rhs_get(&hs, h, value); return v; } static bool set_insert(const char *value) { unsigned long h; h = CK_RHS_HASH(&hs, hs_hash, value); return ck_rhs_put(&hs, h, value); } static bool set_insert_unique(const char *value) { unsigned long h; h = CK_RHS_HASH(&hs, hs_hash, value); return ck_rhs_put_unique(&hs, h, value); } static size_t set_count(void) { return ck_rhs_count(&hs); } static bool set_reset(void) { return ck_rhs_reset(&hs); } static void set_gc(void) { ck_rhs_gc(&hs); return; } static void set_rebuild(void) { ck_rhs_rebuild(&hs); return; } static void keys_shuffle(char **k) { size_t i, j; char *t; for (i = keys_length; i > 1; i--) { j = rand() % (i - 1); if (j != i - 1) { t = k[i - 1]; k[i - 1] = k[j]; k[j] = t; } } return; } static void run_test(const char *file, size_t r, unsigned int size, unsigned int mode) { FILE *fp; char buffer[512]; size_t i, j; unsigned int d = 0; uint64_t s, e, a, ri, si, ai, sr, rg, sg, ag, sd, ng, ss, sts, su, sgc, sb; struct ck_rhs_stat st; char **t; keys = malloc(sizeof(char *) * keys_capacity); assert(keys != NULL); fp = fopen(file, "r"); assert(fp != NULL); while (fgets(buffer, sizeof(buffer), fp) != NULL) { buffer[strlen(buffer) - 1] = '\0'; keys[keys_length++] = strdup(buffer); assert(keys[keys_length - 1] != NULL); if (keys_length == keys_capacity) { t = realloc(keys, sizeof(char *) * (keys_capacity *= 2)); assert(t != NULL); keys = t; } } t = realloc(keys, sizeof(char *) * keys_length); assert(t != NULL); keys = t; set_init(size, mode); for (i = 0; i < keys_length; i++) d += set_insert(keys[i]) == false; ck_rhs_stat(&hs, &st); fprintf(stderr, "# %zu entries stored, %u duplicates, %u probe.\n", set_count(), d, st.probe_maximum); a = 0; for (j = 0; j < r; j++) { if (set_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = keys_length; i > 0; i--) d += set_insert(keys[i - 1]) == false; e = rdtsc(); a += e - s; } ri = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { if (set_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = 0; i < keys_length; i++) d += set_insert(keys[i]) == false; e = rdtsc(); a += e - s; } si = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { keys_shuffle(keys); if (set_reset() == false) { ck_error("ERROR: Failed to reset hash table.\n"); } s = rdtsc(); for (i = 0; i < keys_length; i++) d += set_insert(keys[i]) == false; e = rdtsc(); a += e - s; } ai = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_swap(keys[i]); e = rdtsc(); a += e - s; } ss = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_replace(keys[i]); e = rdtsc(); a += e - s; } sr = a / (r * keys_length); set_reset(); for (i = 0; i < keys_length; i++) set_insert(keys[i]); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = keys_length; i > 0; i--) { if (set_get(keys[i - 1]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } rg = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { if (set_get(keys[i]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } sg = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { keys_shuffle(keys); s = rdtsc(); for (i = 0; i < keys_length; i++) { if (set_get(keys[i]) == NULL) { ck_error("ERROR: Unexpected NULL value.\n"); } } e = rdtsc(); a += e - s; } ag = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_remove(keys[i]); e = rdtsc(); a += e - s; for (i = 0; i < keys_length; i++) set_insert(keys[i]); } sd = a / (r * keys_length); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) { set_get("\x50\x03\x04\x05\x06\x10"); } e = rdtsc(); a += e - s; } ng = a / (r * keys_length); set_reset(); for (i = 0; i < keys_length; i++) set_insert(keys[i]); for (i = 0; i < keys_length; i++) set_remove(keys[i]); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_insert(keys[i]); e = rdtsc(); a += e - s; for (i = 0; i < keys_length; i++) set_remove(keys[i]); } sts = a / (r * keys_length); set_reset(); /* Prune duplicates. */ for (i = 0; i < keys_length; i++) { if (set_insert(keys[i]) == true) continue; free(keys[i]); keys[i] = keys[--keys_length]; } for (i = 0; i < keys_length; i++) set_remove(keys[i]); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); for (i = 0; i < keys_length; i++) set_insert_unique(keys[i]); e = rdtsc(); a += e - s; for (i = 0; i < keys_length; i++) set_remove(keys[i]); } su = a / (r * keys_length); for (i = 0; i < keys_length; i++) set_insert_unique(keys[i]); for (i = 0; i < keys_length / 2; i++) set_remove(keys[i]); a = 0; for (j = 0; j < r; j++) { s = rdtsc(); set_gc(); e = rdtsc(); a += e - s; } sgc = a / r; a = 0; for (j = 0; j < r; j++) { s = rdtsc(); set_rebuild(); e = rdtsc(); a += e - s; } sb = a / r; printf("%zu " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 " " "%" PRIu64 "\n", keys_length, ri, si, ai, ss, sr, rg, sg, ag, sd, ng, sts, su, sgc, sb); fclose(fp); for (i = 0; i < keys_length; i++) { free(keys[i]); } free(keys); keys_length = 0; set_destroy(); return; } int main(int argc, char *argv[]) { unsigned int r, size; common_srand48((long int)time(NULL)); if (argc < 2) { ck_error("Usage: ck_rhs [ ]\n"); } r = 16; if (argc >= 3) r = atoi(argv[2]); size = 8; if (argc >= 4) size = atoi(argv[3]); global_seed = common_lrand48(); run_test(argv[1], r, size, 0); run_test(argv[1], r, size, CK_RHS_MODE_READ_MOSTLY); fprintf(stderr, "# reverse_insertion serial_insertion random_insertion serial_swap " "serial_replace reverse_get serial_get random_get serial_remove negative_get tombstone " "set_unique gc rebuild\n\n"); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rhs/validate/serial.c ================================================ /* * Copyright 2012 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyrights * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyrights * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" static void * hs_malloc(size_t r) { return malloc(r); } static void hs_free(void *p, size_t b, bool r) { (void)b; (void)r; free(p); return; } static struct ck_malloc my_allocator = { .malloc = hs_malloc, .free = hs_free }; const char *test[] = { "Samy", "Al", "Bahra", "dances", "in", "the", "wind.", "Once", "upon", "a", "time", "his", "gypsy", "ate", "one", "itsy", "bitsy", "spider.", "What", "goes", "up", "must", "come", "down.", "What", "is", "down", "stays", "down.", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q" }; const char *negative = "negative"; /* Purposefully crappy hash function. */ static unsigned long hs_hash(const void *object, unsigned long seed) { const char *c = object; unsigned long h; (void)seed; h = c[0]; return h; } static bool hs_compare(const void *previous, const void *compare) { return strcmp(previous, compare) == 0; } static void * test_ip(void *key, void *closure) { const char *a = key; const char *b = closure; if (strcmp(a, b) != 0) ck_error("Mismatch: %s != %s\n", a, b); return closure; } static void * test_negative(void *key, void *closure) { (void)closure; if (key != NULL) ck_error("ERROR: Apply callback expects NULL argument instead of [%s]\n", key); return NULL; } static void * test_unique(void *key, void *closure) { if (key != NULL) ck_error("ERROR: Apply callback expects NULL argument instead of [%s]\n", key); return closure; } static void * test_remove(void *key, void *closure) { (void)key; (void)closure; return NULL; } static void run_test(unsigned int is, unsigned int ad) { ck_rhs_t hs[16]; const size_t size = sizeof(hs) / sizeof(*hs); size_t i, j; const char *blob = "#blobs"; unsigned long h; if (ck_rhs_init(&hs[0], CK_RHS_MODE_SPMC | CK_RHS_MODE_OBJECT | ad, hs_hash, hs_compare, &my_allocator, is, 6602834) == false) ck_error("ck_rhs_init\n"); for (j = 0; j < size; j++) { for (i = 0; i < sizeof(test) / sizeof(*test); i++) { h = test[i][0]; if (ck_rhs_get(&hs[j], h, test[i]) != NULL) { continue; } if (i & 1) { if (ck_rhs_put_unique(&hs[j], h, test[i]) == false) ck_error("ERROR [%zu]: Failed to insert unique (%s)\n", j, test[i]); } else if (ck_rhs_apply(&hs[j], h, test[i], test_unique, (void *)(uintptr_t)test[i]) == false) { ck_error("ERROR: Failed to apply for insertion.\n"); } if (i & 1) { if (ck_rhs_remove(&hs[j], h, test[i]) == false) ck_error("ERROR [%zu]: Failed to remove unique (%s)\n", j, test[i]); } else if (ck_rhs_apply(&hs[j], h, test[i], test_remove, NULL) == false) { ck_error("ERROR: Failed to remove apply.\n"); } if (ck_rhs_apply(&hs[j], h, test[i], test_negative, (void *)(uintptr_t)test[i]) == false) ck_error("ERROR: Failed to apply.\n"); break; } for (i = 0; i < sizeof(test) / sizeof(*test); i++) { h = test[i][0]; ck_rhs_put(&hs[j], h, test[i]); if (ck_rhs_put(&hs[j], h, test[i]) == true) { ck_error("ERROR [%u] [1]: put must fail on collision (%s).\n", is, test[i]); } if (ck_rhs_get(&hs[j], h, test[i]) == NULL) { ck_error("ERROR [%u]: get must not fail after put\n", is); } } /* Test grow semantics. */ ck_rhs_grow(&hs[j], 128); for (i = 0; i < sizeof(test) / sizeof(*test); i++) { h = test[i][0]; if (ck_rhs_put(&hs[j], h, test[i]) == true) { ck_error("ERROR [%u] [2]: put must fail on collision.\n", is); } if (ck_rhs_get(&hs[j], h, test[i]) == NULL) { ck_error("ERROR [%u]: get must not fail\n", is); } } h = blob[0]; if (ck_rhs_get(&hs[j], h, blob) == NULL) { if (j > 0) ck_error("ERROR [%u]: Blob must always exist after first.\n", is); if (ck_rhs_put(&hs[j], h, blob) == false) { ck_error("ERROR [%u]: A unique blob put failed.\n", is); } } else { if (ck_rhs_put(&hs[j], h, blob) == true) { ck_error("ERROR [%u]: Duplicate blob put succeeded.\n", is); } } /* Grow set and check get semantics. */ ck_rhs_grow(&hs[j], 512); for (i = 0; i < sizeof(test) / sizeof(*test); i++) { h = test[i][0]; if (ck_rhs_get(&hs[j], h, test[i]) == NULL) { ck_error("ERROR [%u]: get must not fail\n", is); } } /* Delete and check negative membership. */ for (i = 0; i < sizeof(test) / sizeof(*test); i++) { void *r; h = test[i][0]; if (ck_rhs_get(&hs[j], h, test[i]) == NULL) continue; if (r = ck_rhs_remove(&hs[j], h, test[i]), r == NULL) { ck_error("ERROR [%u]: remove must not fail\n", is); } if (strcmp(r, test[i]) != 0) { ck_error("ERROR [%u]: Removed incorrect node (%s != %s)\n", (char *)r, test[i], is); } } /* Test replacement semantics. */ for (i = 0; i < sizeof(test) / sizeof(*test); i++) { void *r; bool d; h = test[i][0]; d = ck_rhs_get(&hs[j], h, test[i]) != NULL; if (ck_rhs_set(&hs[j], h, test[i], &r) == false) { ck_error("ERROR [%u]: Failed to set\n", is); } /* Expected replacement. */ if (d == true && (r == NULL || strcmp(r, test[i]) != 0)) { ck_error("ERROR [%u]: Incorrect previous value: %s != %s\n", is, test[i], (char *)r); } /* Replacement should succeed. */ if (ck_rhs_fas(&hs[j], h, test[i], &r) == false) ck_error("ERROR [%u]: ck_rhs_fas must succeed.\n", is); if (strcmp(r, test[i]) != 0) { ck_error("ERROR [%u]: Incorrect replaced value: %s != %s\n", is, test[i], (char *)r); } if (ck_rhs_fas(&hs[j], h, negative, &r) == true) ck_error("ERROR [%u]: Replacement of negative should fail.\n", is); if (ck_rhs_set(&hs[j], h, test[i], &r) == false) { ck_error("ERROR [%u]: Failed to set [1]\n", is); } if (strcmp(r, test[i]) != 0) { ck_error("ERROR [%u]: Invalid &hs[j]: %s != %s\n", (char *)r, test[i], is); } /* Attempt in-place mutation. */ if (ck_rhs_apply(&hs[j], h, test[i], test_ip, (void *)(uintptr_t)test[i]) == false) { ck_error("ERROR [%u]: Failed to apply: %s != %s\n", is, (char *)r, test[i]); } d = ck_rhs_get(&hs[j], h, test[i]) != NULL; if (d == false) ck_error("ERROR [%u]: Expected [%s] to exist.\n", is, test[i]); } if (j == size - 1) break; if (ck_rhs_move(&hs[j + 1], &hs[j], hs_hash, hs_compare, &my_allocator) == false) ck_error("Failed to move hash table"); ck_rhs_gc(&hs[j + 1]); if (ck_rhs_rebuild(&hs[j + 1]) == false) ck_error("Failed to rebuild"); } return; } int main(void) { unsigned int k; for (k = 16; k <= 64; k <<= 1) { run_test(k, 0); break; } return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_ring/benchmark/latency.c ================================================ #include #include #include #include #include #include "../../common.h" #ifndef ITERATIONS #define ITERATIONS (128000) #endif struct entry { int tid; int value; }; int main(int argc, char *argv[]) { int i, r, size; uint64_t s, e, e_a, d_a; struct entry entry = {0, 0}; ck_ring_buffer_t *buf; ck_ring_t ring; if (argc != 2) { ck_error("Usage: latency \n"); } size = atoi(argv[1]); if (size <= 4 || (size & (size - 1))) { ck_error("ERROR: Size must be a power of 2 greater than 4.\n"); } buf = malloc(sizeof(ck_ring_buffer_t) * size); if (buf == NULL) { ck_error("ERROR: Failed to allocate buffer\n"); } ck_ring_init(&ring, size); e_a = d_a = s = e = 0; for (r = 0; r < ITERATIONS; r++) { for (i = 0; i < size / 4; i += 4) { s = rdtsc(); ck_ring_enqueue_spsc(&ring, buf, &entry); ck_ring_enqueue_spsc(&ring, buf, &entry); ck_ring_enqueue_spsc(&ring, buf, &entry); ck_ring_enqueue_spsc(&ring, buf, &entry); e = rdtsc(); } e_a += (e - s) / 4; for (i = 0; i < size / 4; i += 4) { s = rdtsc(); ck_ring_dequeue_spsc(&ring, buf, &entry); ck_ring_dequeue_spsc(&ring, buf, &entry); ck_ring_dequeue_spsc(&ring, buf, &entry); ck_ring_dequeue_spsc(&ring, buf, &entry); e = rdtsc(); } d_a += (e - s) / 4; } printf("spsc %10d %16" PRIu64 " %16" PRIu64 "\n", size, e_a / ITERATIONS, d_a / ITERATIONS); e_a = d_a = s = e = 0; for (r = 0; r < ITERATIONS; r++) { for (i = 0; i < size / 4; i += 4) { s = rdtsc(); ck_ring_enqueue_spmc(&ring, buf, &entry); ck_ring_enqueue_spmc(&ring, buf, &entry); ck_ring_enqueue_spmc(&ring, buf, &entry); ck_ring_enqueue_spmc(&ring, buf, &entry); e = rdtsc(); } e_a += (e - s) / 4; for (i = 0; i < size / 4; i += 4) { s = rdtsc(); ck_ring_dequeue_spmc(&ring, buf, &entry); ck_ring_dequeue_spmc(&ring, buf, &entry); ck_ring_dequeue_spmc(&ring, buf, &entry); ck_ring_dequeue_spmc(&ring, buf, &entry); e = rdtsc(); } d_a += (e - s) / 4; } printf("spmc %10d %16" PRIu64 " %16" PRIu64 "\n", size, e_a / ITERATIONS, d_a / ITERATIONS); ck_ring_init(&ring, size); e_a = d_a = s = e = 0; for (r = 0; r < ITERATIONS; r++) { for (i = 0; i < size / 4; i += 4) { s = rdtsc(); ck_ring_enqueue_mpsc(&ring, buf, &entry); ck_ring_enqueue_mpsc(&ring, buf, &entry); ck_ring_enqueue_mpsc(&ring, buf, &entry); ck_ring_enqueue_mpsc(&ring, buf, &entry); e = rdtsc(); } e_a += (e - s) / 4; for (i = 0; i < size / 4; i += 4) { s = rdtsc(); ck_ring_dequeue_mpsc(&ring, buf, &entry); ck_ring_dequeue_mpsc(&ring, buf, &entry); ck_ring_dequeue_mpsc(&ring, buf, &entry); ck_ring_dequeue_mpsc(&ring, buf, &entry); e = rdtsc(); } d_a += (e - s) / 4; } printf("mpsc %10d %16" PRIu64 " %16" PRIu64 "\n", size, e_a / ITERATIONS, d_a / ITERATIONS); ck_ring_init(&ring, size); e_a = d_a = s = e = 0; for (r = 0; r < ITERATIONS; r++) { for (i = 0; i < size / 4; i += 4) { s = rdtsc(); ck_ring_enqueue_mpmc(&ring, buf, &entry); ck_ring_enqueue_mpmc(&ring, buf, &entry); ck_ring_enqueue_mpmc(&ring, buf, &entry); ck_ring_enqueue_mpmc(&ring, buf, &entry); e = rdtsc(); } e_a += (e - s) / 4; for (i = 0; i < size / 4; i += 4) { s = rdtsc(); ck_ring_dequeue_mpmc(&ring, buf, &entry); ck_ring_dequeue_mpmc(&ring, buf, &entry); ck_ring_dequeue_mpmc(&ring, buf, &entry); ck_ring_dequeue_mpmc(&ring, buf, &entry); e = rdtsc(); } d_a += (e - s) / 4; } printf("mpmc %10d %16" PRIu64 " %16" PRIu64 "\n", size, e_a / ITERATIONS, d_a / ITERATIONS); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_ring/validate/ck_ring_mpmc.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATIONS #define ITERATIONS 128 #endif struct context { unsigned int tid; unsigned int previous; unsigned int next; ck_ring_buffer_t *buffer; }; struct entry { unsigned long value_long; unsigned int magic; unsigned int ref; int tid; int value; }; static int nthr; static ck_ring_t *ring; static ck_ring_t ring_mpmc CK_CC_CACHELINE; static ck_ring_t ring_mw CK_CC_CACHELINE; static struct affinity a; static int size; static int eb; static ck_barrier_centralized_t barrier = CK_BARRIER_CENTRALIZED_INITIALIZER; static struct context *_context; static unsigned int global_counter; static void * test_mpmc(void *c) { unsigned int observed = 0; unsigned int enqueue = 0; unsigned int seed; int i, k, j, tid; struct context *context = c; ck_ring_buffer_t *buffer; unsigned int *csp; csp = malloc(sizeof(*csp) * nthr); assert(csp != NULL); memset(csp, 0, sizeof(*csp) * nthr); buffer = context->buffer; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } tid = ck_pr_faa_int(&eb, 1); ck_pr_fence_memory(); while (ck_pr_load_int(&eb) != nthr - 1); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { struct entry *o = NULL; int spin; /* Keep trying until we encounter at least one node. */ if (j & 1) { if (ck_ring_dequeue_mpmc(&ring_mw, buffer, &o) == false) o = NULL; } else { if (ck_ring_trydequeue_mpmc(&ring_mw, buffer, &o) == false) o = NULL; } if (o == NULL) { o = malloc(sizeof(*o)); if (o == NULL) continue; o->value_long = (unsigned long)ck_pr_faa_uint(&global_counter, 1) + 1; o->magic = 0xdead; o->ref = 0; o->tid = tid; if (ck_ring_enqueue_mpmc(&ring_mw, buffer, o) == false) { free(o); } else { enqueue++; } continue; } observed++; if (o->magic != 0xdead) { ck_error("[%p] (%x)\n", (void *)o, o->magic); } o->magic = 0xbeef; if (csp[o->tid] >= o->value_long) ck_error("queue semantics violated: %lu <= %lu\n", o->value_long, csp[o->tid]); csp[o->tid] = o->value_long; if (ck_pr_faa_uint(&o->ref, 1) != 0) { ck_error("[%p] We dequeued twice.\n", (void *)o); } if ((i % 4) == 0) { spin = common_rand_r(&seed) % 16384; for (k = 0; k < spin; k++) { ck_pr_stall(); } } free(o); } } fprintf(stderr, "[%d] dequeue=%u enqueue=%u\n", tid, observed, enqueue); return NULL; } static void * test_spmc(void *c) { unsigned int observed = 0; unsigned long previous = 0; unsigned int seed; int i, k, j, tid; struct context *context = c; ck_ring_buffer_t *buffer; buffer = context->buffer; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } tid = ck_pr_faa_int(&eb, 1); ck_pr_fence_memory(); while (ck_pr_load_int(&eb) != nthr - 1); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { struct entry *o; int spin; /* Keep trying until we encounter at least one node. */ if (j & 1) { while (ck_ring_dequeue_mpmc(&ring_mpmc, buffer, &o) == false); } else { while (ck_ring_trydequeue_mpmc(&ring_mpmc, buffer, &o) == false); } observed++; if (o->value < 0 || o->value != o->tid || o->magic != 0xdead || (previous != 0 && previous >= o->value_long)) { ck_error("[0x%p] (%x) (%d, %d) >< (0, %d)\n", (void *)o, o->magic, o->tid, o->value, size); } o->magic = 0xbeef; o->value = -31337; o->tid = -31338; previous = o->value_long; if (ck_pr_faa_uint(&o->ref, 1) != 0) { ck_error("[%p] We dequeued twice.\n", (void *)o); } if ((i % 4) == 0) { spin = common_rand_r(&seed) % 16384; for (k = 0; k < spin; k++) { ck_pr_stall(); } } free(o); } } fprintf(stderr, "[%d] Observed %u\n", tid, observed); return NULL; } static void * test(void *c) { struct context *context = c; struct entry *entry; unsigned int s; int i, j; bool r; ck_ring_buffer_t *buffer = context->buffer; ck_barrier_centralized_state_t sense = CK_BARRIER_CENTRALIZED_STATE_INITIALIZER; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } if (context->tid == 0) { struct entry *entries; entries = malloc(sizeof(struct entry) * size); assert(entries != NULL); if (ck_ring_size(ring) != 0) { ck_error("More entries than expected: %u > 0\n", ck_ring_size(ring)); } for (i = 0; i < size; i++) { entries[i].value = i; entries[i].tid = 0; if (true) { r = ck_ring_enqueue_mpmc(ring, buffer, entries + i); } else { r = ck_ring_enqueue_mpmc_size(ring, buffer, entries + i, &s); if ((int)s != i) { ck_error("Size is %u, expected %d.\n", s, size); } } assert(r != false); } if (ck_ring_size(ring) != (unsigned int)size) { ck_error("Less entries than expected: %u < %d\n", ck_ring_size(ring), size); } if (ck_ring_capacity(ring) != ck_ring_size(ring) + 1) { ck_error("Capacity less than expected: %u < %u\n", ck_ring_size(ring), ck_ring_capacity(ring)); } } /* * Wait for all threads. The idea here is to maximize the contention. */ ck_barrier_centralized(&barrier, &sense, nthr); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { buffer = _context[context->previous].buffer; while (ck_ring_dequeue_mpmc(ring + context->previous, buffer, &entry) == false); if (context->previous != (unsigned int)entry->tid) { ck_error("[%u:%p] %u != %u\n", context->tid, (void *)entry, entry->tid, context->previous); } if (entry->value < 0 || entry->value >= size) { ck_error("[%u:%p] %u %u\n", context->tid, (void *)entry, entry->tid, context->previous); } entry->tid = context->tid; buffer = context->buffer; if (true) { r = ck_ring_enqueue_mpmc(ring + context->tid, buffer, entry); } else { r = ck_ring_enqueue_mpmc_size(ring + context->tid, buffer, entry, &s); if ((int)s >= size) { ck_error("Size %u out of range of %d\n", s, size); } } assert(r == true); } } return NULL; } int main(int argc, char *argv[]) { int i, r; unsigned long l; pthread_t *thread; ck_ring_buffer_t *buffer; if (argc != 4) { ck_error("Usage: validate \n"); } a.request = 0; a.delta = atoi(argv[2]); nthr = atoi(argv[1]); assert(nthr >= 1); size = atoi(argv[3]); assert(size >= 4 && (size & size - 1) == 0); size -= 1; ring = malloc(sizeof(ck_ring_t) * nthr); assert(ring); _context = malloc(sizeof(*_context) * nthr); assert(_context); thread = malloc(sizeof(pthread_t) * nthr); assert(thread); fprintf(stderr, "SPSC test:"); for (i = 0; i < nthr; i++) { _context[i].tid = i; if (i == 0) { _context[i].previous = nthr - 1; _context[i].next = i + 1; } else if (i == nthr - 1) { _context[i].next = 0; _context[i].previous = i - 1; } else { _context[i].next = i + 1; _context[i].previous = i - 1; } buffer = malloc(sizeof(ck_ring_buffer_t) * (size + 1)); assert(buffer); memset(buffer, 0, sizeof(ck_ring_buffer_t) * (size + 1)); _context[i].buffer = buffer; ck_ring_init(ring + i, size + 1); r = pthread_create(thread + i, NULL, test, _context + i); assert(r == 0); } for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); fprintf(stderr, " done\n"); fprintf(stderr, "SPMC test:\n"); buffer = malloc(sizeof(ck_ring_buffer_t) * (size + 1)); assert(buffer); memset(buffer, 0, sizeof(void *) * (size + 1)); ck_ring_init(&ring_mpmc, size + 1); for (i = 0; i < nthr - 1; i++) { _context[i].buffer = buffer; r = pthread_create(thread + i, NULL, test_spmc, _context + i); assert(r == 0); } for (l = 0; l < (unsigned long)size * ITERATIONS * (nthr - 1) ; l++) { struct entry *entry = malloc(sizeof *entry); assert(entry != NULL); entry->value_long = l; entry->value = (int)l; entry->tid = (int)l; entry->magic = 0xdead; entry->ref = 0; /* Wait until queue is not full. */ if (l & 1) { while (ck_ring_enqueue_mpmc(&ring_mpmc, buffer, entry) == false) ck_pr_stall(); } else { unsigned int s; while (ck_ring_enqueue_mpmc_size(&ring_mpmc, buffer, entry, &s) == false) { ck_pr_stall(); } if ((int)s >= (size * ITERATIONS * (nthr - 1))) { ck_error("MPMC: Unexpected size of %u\n", s); } } } for (i = 0; i < nthr - 1; i++) pthread_join(thread[i], NULL); ck_pr_store_int(&eb, 0); fprintf(stderr, "MPMC test:\n"); buffer = malloc(sizeof(ck_ring_buffer_t) * (size + 1)); assert(buffer); memset(buffer, 0, sizeof(void *) * (size + 1)); ck_ring_init(&ring_mw, size + 1); for (i = 0; i < nthr - 1; i++) { _context[i].buffer = buffer; r = pthread_create(thread + i, NULL, test_mpmc, _context + i); assert(r == 0); } for (i = 0; i < nthr - 1; i++) pthread_join(thread[i], NULL); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_ring/validate/ck_ring_mpmc_template.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATIONS #define ITERATIONS 128 #endif struct context { unsigned int tid; unsigned int previous; unsigned int next; struct entry **buffer; }; struct entry { unsigned long value_long; unsigned int magic; unsigned int ref; int tid; int value; }; CK_RING_PROTOTYPE(entry, entry *) static int nthr; static ck_ring_t *ring; static ck_ring_t ring_spmc CK_CC_CACHELINE; static struct affinity a; static int size; static int eb; static ck_barrier_centralized_t barrier = CK_BARRIER_CENTRALIZED_INITIALIZER; static struct context *_context; static void * test_spmc(void *c) { unsigned int observed = 0; unsigned long previous = 0; unsigned int seed; int i, k, j, tid; struct context *context = c; struct entry **buffer; buffer = context->buffer; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } tid = ck_pr_faa_int(&eb, 1); ck_pr_fence_memory(); while (ck_pr_load_int(&eb) != nthr - 1); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { struct entry *o; int spin; /* Keep trying until we encounter at least one node. */ if (j & 1) { while (CK_RING_DEQUEUE_MPMC(entry, &ring_spmc, buffer, &o) == false); } else { while (CK_RING_TRYDEQUEUE_MPMC(entry, &ring_spmc, buffer, &o) == false); } observed++; if (o->value < 0 || o->value != o->tid || o->magic != 0xdead || (previous != 0 && previous >= o->value_long)) { ck_error("[0x%p] (%x) (%d, %d) >< (0, %d)\n", (void *)o, o->magic, o->tid, o->value, size); } o->magic = 0xbeef; o->value = -31337; o->tid = -31338; previous = o->value_long; if (ck_pr_faa_uint(&o->ref, 1) != 0) { ck_error("[%p] We dequeued twice.\n", (void *)o); } if ((i % 4) == 0) { spin = common_rand_r(&seed) % 16384; for (k = 0; k < spin; k++) { ck_pr_stall(); } } free(o); } } fprintf(stderr, "[%d] Observed %u\n", tid, observed); return NULL; } static void * test(void *c) { struct context *context = c; struct entry *entry; unsigned int s; int i, j; bool r; struct entry **buffer = context->buffer; ck_barrier_centralized_state_t sense = CK_BARRIER_CENTRALIZED_STATE_INITIALIZER; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } if (context->tid == 0) { struct entry **entries; entries = malloc(sizeof(struct entry *) * size); assert(entries != NULL); if (ck_ring_size(ring) != 0) { ck_error("More entries than expected: %u > 0\n", ck_ring_size(ring)); } for (i = 0; i < size; i++) { entries[i] = malloc(sizeof(struct entry)); assert(entries[i] != NULL); entries[i]->value = i; entries[i]->tid = 0; if (i & 1) { r = CK_RING_ENQUEUE_MPMC(entry, ring, buffer, &entries[i]); } else { r = CK_RING_ENQUEUE_MPMC_SIZE(entry, ring, buffer, &entries[i], &s); if ((int)s != i) { ck_error("Size is %u, expected %d.\n", s, size); } } assert(r != false); } if (ck_ring_size(ring) != (unsigned int)size) { ck_error("Less entries than expected: %u < %d\n", ck_ring_size(ring), size); } if (ck_ring_capacity(ring) != ck_ring_size(ring) + 1) { ck_error("Capacity less than expected: %u < %u\n", ck_ring_size(ring), ck_ring_capacity(ring)); } } /* * Wait for all threads. The idea here is to maximize the contention. */ ck_barrier_centralized(&barrier, &sense, nthr); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { buffer = _context[context->previous].buffer; while (CK_RING_DEQUEUE_MPMC(entry, ring + context->previous, buffer, &entry) == false); if (context->previous != (unsigned int)entry->tid) { ck_error("[%u:%p] %u != %u\n", context->tid, (void *)entry, entry->tid, context->previous); } if (entry->value < 0 || entry->value >= size) { ck_error("[%u:%p] %u %u\n", context->tid, (void *)entry, entry->tid, context->previous); } entry->tid = context->tid; buffer = context->buffer; if (i & 1) { r = CK_RING_ENQUEUE_MPMC(entry, ring + context->tid, buffer, &entry); } else { r = CK_RING_ENQUEUE_MPMC_SIZE(entry, ring + context->tid, buffer, &entry, &s); if ((int)s >= size) { ck_error("Size %u out of range of %d\n", s, size); } } assert(r == true); } } return NULL; } int main(int argc, char *argv[]) { int i, r; unsigned long l; pthread_t *thread; struct entry **buffer; if (argc != 4) { ck_error("Usage: validate \n"); } a.request = 0; a.delta = atoi(argv[2]); nthr = atoi(argv[1]); assert(nthr >= 1); size = atoi(argv[3]); assert(size >= 4 && (size & size - 1) == 0); size -= 1; ring = malloc(sizeof(ck_ring_t) * nthr); assert(ring); _context = malloc(sizeof(*_context) * nthr); assert(_context); thread = malloc(sizeof(pthread_t) * nthr); assert(thread); fprintf(stderr, "SPSC test:"); for (i = 0; i < nthr; i++) { _context[i].tid = i; if (i == 0) { _context[i].previous = nthr - 1; _context[i].next = i + 1; } else if (i == nthr - 1) { _context[i].next = 0; _context[i].previous = i - 1; } else { _context[i].next = i + 1; _context[i].previous = i - 1; } buffer = malloc(sizeof(struct entry *) * (size + 1)); assert(buffer); memset(buffer, 0, sizeof(struct entry *) * (size + 1)); _context[i].buffer = buffer; ck_ring_init(ring + i, size + 1); r = pthread_create(thread + i, NULL, test, _context + i); assert(r == 0); } for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); fprintf(stderr, " done\n"); fprintf(stderr, "MPMC test:\n"); buffer = malloc(sizeof(struct entry *) * (size + 1)); assert(buffer); memset(buffer, 0, sizeof(struct entry *) * (size + 1)); ck_ring_init(&ring_spmc, size + 1); for (i = 0; i < nthr - 1; i++) { _context[i].buffer = buffer; r = pthread_create(thread + i, NULL, test_spmc, _context + i); assert(r == 0); } for (l = 0; l < (unsigned long)size * ITERATIONS * (nthr - 1) ; l++) { struct entry *entry = malloc(sizeof *entry); assert(entry != NULL); entry->value_long = l; entry->value = (int)l; entry->tid = (int)l; entry->magic = 0xdead; entry->ref = 0; /* Wait until queue is not full. */ if (l & 1) { while (CK_RING_ENQUEUE_MPMC(entry, &ring_spmc, buffer, &entry) == false) { ck_pr_stall(); } } else { unsigned int s; while (CK_RING_ENQUEUE_MPMC_SIZE(entry, &ring_spmc, buffer, &entry, &s) == false) { ck_pr_stall(); } if ((int)s >= (size * ITERATIONS * (nthr - 1))) { ck_error("MPMC: Unexpected size of %u\n", s); } } } for (i = 0; i < nthr - 1; i++) pthread_join(thread[i], NULL); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_ring/validate/ck_ring_spmc.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATIONS #define ITERATIONS 128 #endif struct context { unsigned int tid; unsigned int previous; unsigned int next; ck_ring_buffer_t *buffer; }; struct entry { unsigned long value_long; unsigned int magic; unsigned int ref; int tid; int value; }; static int nthr; static ck_ring_t *ring; static ck_ring_t ring_spmc CK_CC_CACHELINE; static struct affinity a; static int size; static int eb; static ck_barrier_centralized_t barrier = CK_BARRIER_CENTRALIZED_INITIALIZER; static struct context *_context; static void * test_spmc(void *c) { unsigned int observed = 0; unsigned long previous = 0; unsigned int seed; int i, k, j, tid; struct context *context = c; ck_ring_buffer_t *buffer; buffer = context->buffer; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } tid = ck_pr_faa_int(&eb, 1); ck_pr_fence_memory(); while (ck_pr_load_int(&eb) != nthr - 1); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { struct entry *o; int spin; /* Keep trying until we encounter at least one node. */ if (j & 1) { while (ck_ring_dequeue_spmc(&ring_spmc, buffer, &o) == false); } else { while (ck_ring_trydequeue_spmc(&ring_spmc, buffer, &o) == false); } observed++; if (o->value < 0 || o->value != o->tid || o->magic != 0xdead || (previous != 0 && previous >= o->value_long)) { ck_error("[0x%p] (%x) (%d, %d) >< (0, %d)\n", (void *)o, o->magic, o->tid, o->value, size); } o->magic = 0xbeef; o->value = -31337; o->tid = -31338; previous = o->value_long; if (ck_pr_faa_uint(&o->ref, 1) != 0) { ck_error("[%p] We dequeued twice.\n", (void *)o); } if ((i % 4) == 0) { spin = common_rand_r(&seed) % 16384; for (k = 0; k < spin; k++) { ck_pr_stall(); } } free(o); } } fprintf(stderr, "[%d] Observed %u\n", tid, observed); return NULL; } static void * test(void *c) { struct context *context = c; struct entry *entry; unsigned int s; int i, j; bool r; ck_ring_buffer_t *buffer = context->buffer; ck_barrier_centralized_state_t sense = CK_BARRIER_CENTRALIZED_STATE_INITIALIZER; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } if (context->tid == 0) { struct entry *entries; entries = malloc(sizeof(struct entry) * size); assert(entries != NULL); if (ck_ring_size(ring) != 0) { ck_error("More entries than expected: %u > 0\n", ck_ring_size(ring)); } for (i = 0; i < size; i++) { entries[i].value = i; entries[i].tid = 0; if (i & 1) { r = ck_ring_enqueue_spmc(ring, buffer, entries + i); } else { r = ck_ring_enqueue_spmc_size(ring, buffer, entries + i, &s); if ((int)s != i) { ck_error("Size is %u, expected %d.\n", s, size); } } assert(r != false); } if (ck_ring_size(ring) != (unsigned int)size) { ck_error("Less entries than expected: %u < %d\n", ck_ring_size(ring), size); } if (ck_ring_capacity(ring) != ck_ring_size(ring) + 1) { ck_error("Capacity less than expected: %u < %u\n", ck_ring_size(ring), ck_ring_capacity(ring)); } } /* * Wait for all threads. The idea here is to maximize the contention. */ ck_barrier_centralized(&barrier, &sense, nthr); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { buffer = _context[context->previous].buffer; while (ck_ring_dequeue_spmc(ring + context->previous, buffer, &entry) == false); if (context->previous != (unsigned int)entry->tid) { ck_error("[%u:%p] %u != %u\n", context->tid, (void *)entry, entry->tid, context->previous); } if (entry->value < 0 || entry->value >= size) { ck_error("[%u:%p] %u %u\n", context->tid, (void *)entry, entry->tid, context->previous); } entry->tid = context->tid; buffer = context->buffer; if (i & 1) { r = ck_ring_enqueue_spmc(ring + context->tid, buffer, entry); } else { r = ck_ring_enqueue_spmc_size(ring + context->tid, buffer, entry, &s); if ((int)s >= size) { ck_error("Size %u out of range of %d\n", s, size); } } assert(r == true); } } return NULL; } int main(int argc, char *argv[]) { int i, r; unsigned long l; pthread_t *thread; ck_ring_buffer_t *buffer; if (argc != 4) { ck_error("Usage: validate \n"); } a.request = 0; a.delta = atoi(argv[2]); nthr = atoi(argv[1]); assert(nthr >= 1); size = atoi(argv[3]); assert(size >= 4 && (size & size - 1) == 0); size -= 1; ring = malloc(sizeof(ck_ring_t) * nthr); assert(ring); _context = malloc(sizeof(*_context) * nthr); assert(_context); thread = malloc(sizeof(pthread_t) * nthr); assert(thread); fprintf(stderr, "SPSC test:"); for (i = 0; i < nthr; i++) { _context[i].tid = i; if (i == 0) { _context[i].previous = nthr - 1; _context[i].next = i + 1; } else if (i == nthr - 1) { _context[i].next = 0; _context[i].previous = i - 1; } else { _context[i].next = i + 1; _context[i].previous = i - 1; } buffer = malloc(sizeof(ck_ring_buffer_t) * (size + 1)); assert(buffer); memset(buffer, 0, sizeof(ck_ring_buffer_t) * (size + 1)); _context[i].buffer = buffer; ck_ring_init(ring + i, size + 1); r = pthread_create(thread + i, NULL, test, _context + i); assert(r == 0); } for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); fprintf(stderr, " done\n"); fprintf(stderr, "SPMC test:\n"); buffer = malloc(sizeof(ck_ring_buffer_t) * (size + 1)); assert(buffer); memset(buffer, 0, sizeof(void *) * (size + 1)); ck_ring_init(&ring_spmc, size + 1); for (i = 0; i < nthr - 1; i++) { _context[i].buffer = buffer; r = pthread_create(thread + i, NULL, test_spmc, _context + i); assert(r == 0); } for (l = 0; l < (unsigned long)size * ITERATIONS * (nthr - 1) ; l++) { struct entry *entry = malloc(sizeof *entry); assert(entry != NULL); entry->value_long = l; entry->value = (int)l; entry->tid = (int)l; entry->magic = 0xdead; entry->ref = 0; /* Wait until queue is not full. */ if (l & 1) { while (ck_ring_enqueue_spmc(&ring_spmc, buffer, entry) == false) ck_pr_stall(); } else { unsigned int s; while (ck_ring_enqueue_spmc_size(&ring_spmc, buffer, entry, &s) == false) { ck_pr_stall(); } if ((int)s >= (size * ITERATIONS * (nthr - 1))) { ck_error("MPMC: Unexpected size of %u\n", s); } } } for (i = 0; i < nthr - 1; i++) pthread_join(thread[i], NULL); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_ring/validate/ck_ring_spmc_template.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATIONS #define ITERATIONS 128 #endif struct context { unsigned int tid; unsigned int previous; unsigned int next; struct entry **buffer; }; struct entry { unsigned long value_long; unsigned int magic; unsigned int ref; int tid; int value; }; CK_RING_PROTOTYPE(entry, entry *) static int nthr; static ck_ring_t *ring; static ck_ring_t ring_spmc CK_CC_CACHELINE; static struct affinity a; static int size; static int eb; static ck_barrier_centralized_t barrier = CK_BARRIER_CENTRALIZED_INITIALIZER; static struct context *_context; static void * test_spmc(void *c) { unsigned int observed = 0; unsigned long previous = 0; unsigned int seed; int i, k, j, tid; struct context *context = c; struct entry **buffer; buffer = context->buffer; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } tid = ck_pr_faa_int(&eb, 1); ck_pr_fence_memory(); while (ck_pr_load_int(&eb) != nthr - 1); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { struct entry *o; int spin; /* Keep trying until we encounter at least one node. */ if (j & 1) { while (CK_RING_DEQUEUE_SPMC(entry, &ring_spmc, buffer, &o) == false); } else { while (CK_RING_TRYDEQUEUE_SPMC(entry, &ring_spmc, buffer, &o) == false); } observed++; if (o->value < 0 || o->value != o->tid || o->magic != 0xdead || (previous != 0 && previous >= o->value_long)) { ck_error("[0x%p] (%x) (%d, %d) >< (0, %d)\n", (void *)o, o->magic, o->tid, o->value, size); } o->magic = 0xbeef; o->value = -31337; o->tid = -31338; previous = o->value_long; if (ck_pr_faa_uint(&o->ref, 1) != 0) { ck_error("[%p] We dequeued twice.\n", (void *)o); } if ((i % 4) == 0) { spin = common_rand_r(&seed) % 16384; for (k = 0; k < spin; k++) { ck_pr_stall(); } } free(o); } } fprintf(stderr, "[%d] Observed %u\n", tid, observed); return NULL; } static void * test(void *c) { struct context *context = c; struct entry *entry; unsigned int s; int i, j; bool r; struct entry **buffer = context->buffer; ck_barrier_centralized_state_t sense = CK_BARRIER_CENTRALIZED_STATE_INITIALIZER; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } if (context->tid == 0) { struct entry **entries; entries = malloc(sizeof(struct entry *) * size); assert(entries != NULL); if (ck_ring_size(ring) != 0) { ck_error("More entries than expected: %u > 0\n", ck_ring_size(ring)); } for (i = 0; i < size; i++) { entries[i] = malloc(sizeof(struct entry)); assert(entries[i] != NULL); entries[i]->value = i; entries[i]->tid = 0; if (i & 1) { r = CK_RING_ENQUEUE_SPMC(entry, ring, buffer, &entries[i]); } else { r = CK_RING_ENQUEUE_SPMC_SIZE(entry, ring, buffer, &entries[i], &s); if ((int)s != i) { ck_error("Size is %u, expected %d.\n", s, size); } } assert(r != false); } if (ck_ring_size(ring) != (unsigned int)size) { ck_error("Less entries than expected: %u < %d\n", ck_ring_size(ring), size); } if (ck_ring_capacity(ring) != ck_ring_size(ring) + 1) { ck_error("Capacity less than expected: %u < %u\n", ck_ring_size(ring), ck_ring_capacity(ring)); } } /* * Wait for all threads. The idea here is to maximize the contention. */ ck_barrier_centralized(&barrier, &sense, nthr); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { buffer = _context[context->previous].buffer; while (CK_RING_DEQUEUE_SPMC(entry, ring + context->previous, buffer, &entry) == false); if (context->previous != (unsigned int)entry->tid) { ck_error("[%u:%p] %u != %u\n", context->tid, (void *)entry, entry->tid, context->previous); } if (entry->value < 0 || entry->value >= size) { ck_error("[%u:%p] %u %u\n", context->tid, (void *)entry, entry->tid, context->previous); } entry->tid = context->tid; buffer = context->buffer; if (i & 1) { r = CK_RING_ENQUEUE_SPMC(entry, ring + context->tid, buffer, &entry); } else { r = CK_RING_ENQUEUE_SPMC_SIZE(entry, ring + context->tid, buffer, &entry, &s); if ((int)s >= size) { ck_error("Size %u out of range of %d\n", s, size); } } assert(r == true); } } return NULL; } int main(int argc, char *argv[]) { int i, r; unsigned long l; pthread_t *thread; struct entry **buffer; if (argc != 4) { ck_error("Usage: validate \n"); } a.request = 0; a.delta = atoi(argv[2]); nthr = atoi(argv[1]); assert(nthr >= 1); size = atoi(argv[3]); assert(size >= 4 && (size & size - 1) == 0); size -= 1; ring = malloc(sizeof(ck_ring_t) * nthr); assert(ring); _context = malloc(sizeof(*_context) * nthr); assert(_context); thread = malloc(sizeof(pthread_t) * nthr); assert(thread); fprintf(stderr, "SPSC test:"); for (i = 0; i < nthr; i++) { _context[i].tid = i; if (i == 0) { _context[i].previous = nthr - 1; _context[i].next = i + 1; } else if (i == nthr - 1) { _context[i].next = 0; _context[i].previous = i - 1; } else { _context[i].next = i + 1; _context[i].previous = i - 1; } buffer = malloc(sizeof(struct entry *) * (size + 1)); assert(buffer); memset(buffer, 0, sizeof(struct entry *) * (size + 1)); _context[i].buffer = buffer; ck_ring_init(ring + i, size + 1); r = pthread_create(thread + i, NULL, test, _context + i); assert(r == 0); } for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); fprintf(stderr, " done\n"); fprintf(stderr, "SPMC test:\n"); buffer = malloc(sizeof(struct entry *) * (size + 1)); assert(buffer); memset(buffer, 0, sizeof(struct entry *) * (size + 1)); ck_ring_init(&ring_spmc, size + 1); for (i = 0; i < nthr - 1; i++) { _context[i].buffer = buffer; r = pthread_create(thread + i, NULL, test_spmc, _context + i); assert(r == 0); } for (l = 0; l < (unsigned long)size * ITERATIONS * (nthr - 1) ; l++) { struct entry *entry = malloc(sizeof *entry); assert(entry != NULL); entry->value_long = l; entry->value = (int)l; entry->tid = (int)l; entry->magic = 0xdead; entry->ref = 0; /* Wait until queue is not full. */ if (l & 1) { while (CK_RING_ENQUEUE_SPMC(entry, &ring_spmc, buffer, &entry) == false) { ck_pr_stall(); } } else { unsigned int s; while (CK_RING_ENQUEUE_SPMC_SIZE(entry, &ring_spmc, buffer, &entry, &s) == false) { ck_pr_stall(); } if ((int)s >= (size * ITERATIONS * (nthr - 1))) { ck_error("MPMC: Unexpected size of %u\n", s); } } } for (i = 0; i < nthr - 1; i++) pthread_join(thread[i], NULL); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_ring/validate/ck_ring_spsc.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATIONS #define ITERATIONS 128 #endif struct context { unsigned int tid; unsigned int previous; unsigned int next; void *buffer; }; struct entry { int tid; int value; }; static int nthr; static ck_ring_t *ring; static struct affinity a; static int size; static ck_barrier_centralized_t barrier = CK_BARRIER_CENTRALIZED_INITIALIZER; static struct context *_context; static void * test(void *c) { struct context *context = c; struct entry *entry; unsigned int s; int i, j; bool r; ck_barrier_centralized_state_t sense = CK_BARRIER_CENTRALIZED_STATE_INITIALIZER; ck_ring_buffer_t *buffer; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } buffer = context->buffer; if (context->tid == 0) { struct entry *entries; entries = malloc(sizeof(struct entry) * size); assert(entries != NULL); if (ck_ring_size(ring) != 0) { ck_error("More entries than expected: %u > 0\n", ck_ring_size(ring)); } for (i = 0; i < size; i++) { entries[i].value = i; entries[i].tid = 0; if (i & 1) { r = ck_ring_enqueue_spsc(ring, buffer, entries + i); } else { r = ck_ring_enqueue_spsc_size(ring, buffer, entries + i, &s); if ((int)s != i) { ck_error("Size is %u, expected %d\n", s, i + 1); } } assert(r != false); } if (ck_ring_size(ring) != (unsigned int)size) { ck_error("Less entries than expected: %u < %d\n", ck_ring_size(ring), size); } if (ck_ring_capacity(ring) != ck_ring_size(ring) + 1) { ck_error("Capacity less than expected: %u < %u\n", ck_ring_size(ring), ck_ring_capacity(ring)); } } ck_barrier_centralized(&barrier, &sense, nthr); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { buffer = _context[context->previous].buffer; while (ck_ring_dequeue_spsc(ring + context->previous, buffer, &entry) == false); if (context->previous != (unsigned int)entry->tid) { ck_error("[%u:%p] %u != %u\n", context->tid, (void *)entry, entry->tid, context->previous); } if (entry->value != j) { ck_error("[%u:%p] %u != %u\n", context->tid, (void *)entry, entry->tid, context->previous); } entry->tid = context->tid; buffer = context->buffer; if (i & 1) { r = ck_ring_enqueue_spsc(ring + context->tid, buffer, entry); } else { r = ck_ring_enqueue_spsc_size(ring + context->tid, buffer, entry, &s); if ((int)s >= size) { ck_error("Size %u is out of range %d\n", s, size); } } assert(r == true); } } return NULL; } int main(int argc, char *argv[]) { int i, r; ck_ring_buffer_t *buffer; pthread_t *thread; if (argc != 4) { ck_error("Usage: validate \n"); } a.request = 0; a.delta = atoi(argv[2]); nthr = atoi(argv[1]); assert(nthr >= 1); size = atoi(argv[3]); assert(size >= 4 && (size & size - 1) == 0); size -= 1; ring = malloc(sizeof(ck_ring_t) * nthr); assert(ring); _context = malloc(sizeof(*_context) * nthr); assert(_context); thread = malloc(sizeof(pthread_t) * nthr); assert(thread); for (i = 0; i < nthr; i++) { _context[i].tid = i; if (i == 0) { _context[i].previous = nthr - 1; _context[i].next = i + 1; } else if (i == nthr - 1) { _context[i].next = 0; _context[i].previous = i - 1; } else { _context[i].next = i + 1; _context[i].previous = i - 1; } buffer = malloc(sizeof(ck_ring_buffer_t) * (size + 1)); assert(buffer); _context[i].buffer = buffer; ck_ring_init(ring + i, size + 1); r = pthread_create(thread + i, NULL, test, _context + i); assert(r == 0); } for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/benchmark/ck_neutral.c ================================================ #include "../ck_neutral.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/benchmark/ck_rp.c ================================================ #include "../ck_rp.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/benchmark/ck_wp.c ================================================ #include "../ck_wp.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/benchmark/latency.h ================================================ /* * Copyright 2013-2015 Samy Al Bahra. * Copyright 2013 Brendon Scheinman. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS 1000000 #endif static void ck_spinlock_fas_lock_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; ck_spinlock_fas_lock(lock); } static void ck_spinlock_fas_unlock_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; ck_spinlock_fas_unlock(lock); } static bool ck_spinlock_fas_locked_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; return ck_spinlock_fas_locked(lock); } CK_COHORT_PROTOTYPE(fas_fas, ck_spinlock_fas_lock_with_context, ck_spinlock_fas_unlock_with_context, ck_spinlock_fas_locked_with_context, ck_spinlock_fas_lock_with_context, ck_spinlock_fas_unlock_with_context, ck_spinlock_fas_locked_with_context) LOCK_PROTOTYPE(fas_fas) int main(void) { uint64_t s_b, e_b, i; ck_spinlock_fas_t global_lock = CK_SPINLOCK_FAS_INITIALIZER; ck_spinlock_fas_t local_lock = CK_SPINLOCK_FAS_INITIALIZER; CK_COHORT_INSTANCE(fas_fas) cohort = CK_COHORT_INITIALIZER; LOCK_INSTANCE(fas_fas) rw_cohort = LOCK_INITIALIZER; CK_COHORT_INIT(fas_fas, &cohort, &global_lock, &local_lock, CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT); LOCK_INIT(fas_fas, &rw_cohort, CK_RWCOHORT_WP_DEFAULT_WAIT_LIMIT); for (i = 0; i < STEPS; i++) { WRITE_LOCK(fas_fas, &rw_cohort, &cohort, NULL, NULL); WRITE_UNLOCK(fas_fas, &rw_cohort, &cohort, NULL, NULL); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { WRITE_LOCK(fas_fas, &rw_cohort, &cohort, NULL, NULL); WRITE_UNLOCK(fas_fas, &rw_cohort, &cohort, NULL, NULL); } e_b = rdtsc(); printf("WRITE: rwlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); for (i = 0; i < STEPS; i++) { READ_LOCK(fas_fas, &rw_cohort, &cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, &cohort, NULL, NULL); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { READ_LOCK(fas_fas, &rw_cohort, &cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, &cohort, NULL, NULL); } e_b = rdtsc(); printf("READ: rwlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/benchmark/throughput.h ================================================ /* * Copyright 2013-2015 Samy Al Bahra. * Copyright 2013 Brendon Scheinman. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #define max(x, y) (((x) > (y)) ? (x) : (y)) #ifndef STEPS #define STEPS 1000000 #endif static unsigned int barrier; static unsigned int flag CK_CC_CACHELINE; static struct affinity affinity; static unsigned int nthr; static void ck_spinlock_fas_lock_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; ck_spinlock_fas_lock(lock); return; } static void ck_spinlock_fas_unlock_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; ck_spinlock_fas_unlock(lock); return; } static bool ck_spinlock_fas_locked_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; return ck_spinlock_fas_locked(lock); } CK_COHORT_PROTOTYPE(fas_fas, ck_spinlock_fas_lock_with_context, ck_spinlock_fas_unlock_with_context, ck_spinlock_fas_locked_with_context, ck_spinlock_fas_lock_with_context, ck_spinlock_fas_unlock_with_context, ck_spinlock_fas_locked_with_context) LOCK_PROTOTYPE(fas_fas) struct cohort_record { CK_COHORT_INSTANCE(fas_fas) cohort; } CK_CC_CACHELINE; static struct cohort_record *cohorts; static ck_spinlock_t global_lock = CK_SPINLOCK_INITIALIZER; static LOCK_INSTANCE(fas_fas) rw_cohort = LOCK_INITIALIZER; static unsigned int n_cohorts; struct block { unsigned int tid; }; static void * thread_rwlock(void *pun) { uint64_t s_b, e_b, a, i; uint64_t *value = pun; CK_COHORT_INSTANCE(fas_fas) *cohort; unsigned int core; if (aff_iterate_core(&affinity, &core) != 0) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } cohort = &((cohorts + (core / (int)(affinity.delta)) % n_cohorts)->cohort); ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) != nthr) ck_pr_stall(); for (i = 1, a = 0;; i++) { s_b = rdtsc(); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); e_b = rdtsc(); a += (e_b - s_b) >> 4; if (ck_pr_load_uint(&flag) == 1) break; } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) != nthr * 2) ck_pr_stall(); *value = (a / i); return NULL; } int main(int argc, char *argv[]) { unsigned int i; pthread_t *threads; uint64_t *latency; struct block *context; ck_spinlock_fas_t *local_lock; if (argc != 4) { ck_error("Usage: throughput \n"); } n_cohorts = atoi(argv[1]); if (n_cohorts <= 0) { ck_error("ERROR: Number of cohorts must be greater than 0\n"); } nthr = n_cohorts * atoi(argv[2]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } cohorts = malloc(sizeof(struct cohort_record) * n_cohorts); if (cohorts == NULL) { ck_error("ERROR: Could not allocate cohort structures\n"); } context = malloc(sizeof(struct block) * nthr); if (context == NULL) { ck_error("ERROR: Could not allocate thread contexts\n"); } affinity.delta = atoi(argv[3]); affinity.request = 0; latency = malloc(sizeof(*latency) * nthr); if (latency == NULL) { ck_error("ERROR: Could not create latency buffer\n"); } memset(latency, 0, sizeof(*latency) * nthr); fprintf(stderr, "Creating cohorts..."); for (i = 0 ; i < n_cohorts ; i++) { local_lock = malloc(max(CK_MD_CACHELINE, sizeof(ck_spinlock_fas_t))); if (local_lock == NULL) { ck_error("ERROR: Could not allocate local lock\n"); } CK_COHORT_INIT(fas_fas, &((cohorts + i)->cohort), &global_lock, local_lock, CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT); local_lock = NULL; } fprintf(stderr, "done\n"); fprintf(stderr, "Creating threads (rwlock)..."); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, thread_rwlock, latency + i) != 0) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); common_sleep(10); ck_pr_store_uint(&flag, 1); fprintf(stderr, "Waiting for threads to finish acquisition regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done\n\n"); for (i = 1; i <= nthr; i++) printf("%10u %20" PRIu64 "\n", i, latency[i - 1]); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/ck_neutral.h ================================================ #define LOCK_PROTOTYPE CK_RWCOHORT_NEUTRAL_PROTOTYPE #define LOCK_INSTANCE CK_RWCOHORT_NEUTRAL_INSTANCE #define LOCK_INITIALIZER CK_RWCOHORT_NEUTRAL_INITIALIZER #define LOCK_INIT(N, C, W) CK_RWCOHORT_NEUTRAL_INIT(N, C) #define READ_LOCK CK_RWCOHORT_NEUTRAL_READ_LOCK #define WRITE_LOCK CK_RWCOHORT_NEUTRAL_WRITE_LOCK #define READ_UNLOCK CK_RWCOHORT_NEUTRAL_READ_UNLOCK #define WRITE_UNLOCK CK_RWCOHORT_NEUTRAL_WRITE_UNLOCK ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/ck_rp.h ================================================ #define LOCK_PROTOTYPE CK_RWCOHORT_RP_PROTOTYPE #define LOCK_INSTANCE CK_RWCOHORT_RP_INSTANCE #define LOCK_INITIALIZER CK_RWCOHORT_RP_INITIALIZER #define LOCK_INIT CK_RWCOHORT_RP_INIT #define READ_LOCK CK_RWCOHORT_RP_READ_LOCK #define READ_UNLOCK CK_RWCOHORT_RP_READ_UNLOCK #define WRITE_LOCK CK_RWCOHORT_RP_WRITE_LOCK #define WRITE_UNLOCK CK_RWCOHORT_RP_WRITE_UNLOCK ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/ck_wp.h ================================================ #define LOCK_PROTOTYPE CK_RWCOHORT_WP_PROTOTYPE #define LOCK_INSTANCE CK_RWCOHORT_WP_INSTANCE #define LOCK_INITIALIZER CK_RWCOHORT_WP_INITIALIZER #define LOCK_INIT CK_RWCOHORT_WP_INIT #define READ_LOCK CK_RWCOHORT_WP_READ_LOCK #define WRITE_LOCK CK_RWCOHORT_WP_WRITE_LOCK #define READ_UNLOCK CK_RWCOHORT_WP_READ_UNLOCK #define WRITE_UNLOCK CK_RWCOHORT_WP_WRITE_UNLOCK ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/validate/ck_neutral.c ================================================ #include "../ck_neutral.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/validate/ck_rp.c ================================================ #include "../ck_rp.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/validate/ck_wp.c ================================================ #include "../ck_wp.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwcohort/validate/validate.h ================================================ /* * Copyright 2013-2015 Samy Al Bahra. * Copything 2013 Brendon Scheinman. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 1000000 #endif static struct affinity a; static unsigned int locked; static int nthr; static ck_spinlock_fas_t global_fas_lock = CK_SPINLOCK_FAS_INITIALIZER; static void ck_spinlock_fas_lock_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; ck_spinlock_fas_lock(lock); } static void ck_spinlock_fas_unlock_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; ck_spinlock_fas_unlock(lock); } static bool ck_spinlock_fas_locked_with_context(ck_spinlock_fas_t *lock, void *context) { (void)context; return ck_spinlock_fas_locked(lock); } CK_COHORT_PROTOTYPE(fas_fas, ck_spinlock_fas_lock_with_context, ck_spinlock_fas_unlock_with_context, ck_spinlock_fas_locked_with_context, ck_spinlock_fas_lock_with_context, ck_spinlock_fas_unlock_with_context, ck_spinlock_fas_locked_with_context) LOCK_PROTOTYPE(fas_fas) static CK_COHORT_INSTANCE(fas_fas) *cohorts; static LOCK_INSTANCE(fas_fas) rw_cohort = LOCK_INITIALIZER; static int n_cohorts; static void * thread(void *null CK_CC_UNUSED) { int i = ITERATE; unsigned int l; unsigned int core; CK_COHORT_INSTANCE(fas_fas) *cohort; if (aff_iterate_core(&a, &core)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } cohort = cohorts + (core / (int)(a.delta)) % n_cohorts; while (i--) { WRITE_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } WRITE_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); READ_LOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } READ_UNLOCK(fas_fas, &rw_cohort, cohort, NULL, NULL); } return (NULL); } int main(int argc, char *argv[]) { pthread_t *threads; int threads_per_cohort; ck_spinlock_fas_t *local_lock; int i; if (argc != 4) { ck_error("Usage: validate \n"); } n_cohorts = atoi(argv[1]); if (n_cohorts <= 0) { ck_error("ERROR: Number of cohorts must be greater than 0\n"); } threads_per_cohort = atoi(argv[2]); if (threads_per_cohort <= 0) { ck_error("ERROR: Threads per cohort must be greater than 0\n"); } nthr = n_cohorts * threads_per_cohort; threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } a.delta = atoi(argv[3]); fprintf(stderr, "Creating cohorts..."); cohorts = malloc(sizeof(CK_COHORT_INSTANCE(fas_fas)) * n_cohorts); if (cohorts == NULL) { ck_error("ERROR: Could not allocate base cohort structures\n"); } for (i = 0 ; i < n_cohorts ; i++) { local_lock = malloc(sizeof(ck_spinlock_fas_t)); CK_COHORT_INIT(fas_fas, cohorts + i, &global_fas_lock, local_lock, CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT); } fprintf(stderr, "done\n"); fprintf(stderr, "Creating threads..."); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, thread, NULL)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "done\n"); fprintf(stderr, "Waiting for threads to finish correctness regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwlock/benchmark/latency.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "../../common.h" #define CK_F_PR_RTM #ifndef STEPS #define STEPS 2000000 #endif int main(void) { uint64_t s_b, e_b, i; ck_rwlock_t rwlock = CK_RWLOCK_INITIALIZER; for (i = 0; i < STEPS; i++) { ck_rwlock_write_lock(&rwlock); ck_rwlock_write_unlock(&rwlock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_rwlock_write_lock(&rwlock); ck_rwlock_write_unlock(&rwlock); } e_b = rdtsc(); printf(" WRITE: rwlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); #ifdef CK_F_PR_RTM struct ck_elide_config config = CK_ELIDE_CONFIG_DEFAULT_INITIALIZER; struct ck_elide_stat st = CK_ELIDE_STAT_INITIALIZER; for (i = 0; i < STEPS; i++) { CK_ELIDE_LOCK(ck_rwlock_write, &rwlock); CK_ELIDE_UNLOCK(ck_rwlock_write, &rwlock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { CK_ELIDE_LOCK(ck_rwlock_write, &rwlock); CK_ELIDE_UNLOCK(ck_rwlock_write, &rwlock); } e_b = rdtsc(); printf(" (rtm) WRITE: rwlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); for (i = 0; i < STEPS; i++) { CK_ELIDE_LOCK_ADAPTIVE(ck_rwlock_write, &st, &config, &rwlock); CK_ELIDE_UNLOCK_ADAPTIVE(ck_rwlock_write, &st, &rwlock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { CK_ELIDE_LOCK_ADAPTIVE(ck_rwlock_write, &st, &config, &rwlock); CK_ELIDE_UNLOCK_ADAPTIVE(ck_rwlock_write, &st, &rwlock); } e_b = rdtsc(); printf(" (rtm-adaptive) WRITE: rwlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); #endif /* CK_F_PR_RTM */ for (i = 0; i < STEPS; i++) { ck_rwlock_read_lock(&rwlock); ck_rwlock_read_unlock(&rwlock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_rwlock_read_lock(&rwlock); ck_rwlock_read_unlock(&rwlock); } e_b = rdtsc(); printf(" READ: rwlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); #ifdef CK_F_PR_RTM ck_elide_stat_init(&st); for (i = 0; i < STEPS; i++) { CK_ELIDE_LOCK(ck_rwlock_read, &rwlock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rwlock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { CK_ELIDE_LOCK(ck_rwlock_read, &rwlock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rwlock); } e_b = rdtsc(); printf(" (rtm) READ: rwlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); for (i = 0; i < STEPS; i++) { CK_ELIDE_LOCK_ADAPTIVE(ck_rwlock_read, &st, &config, &rwlock); CK_ELIDE_UNLOCK_ADAPTIVE(ck_rwlock_read, &st, &rwlock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { CK_ELIDE_LOCK_ADAPTIVE(ck_rwlock_read, &st, &config, &rwlock); CK_ELIDE_UNLOCK_ADAPTIVE(ck_rwlock_read, &st, &rwlock); } e_b = rdtsc(); printf(" (rtm-adaptive) READ: rwlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); #endif /* CK_F_PR_RTM */ return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwlock/benchmark/throughput.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS 1000000 #endif static int barrier; static int threads; static unsigned int flag CK_CC_CACHELINE; static struct { ck_rwlock_t lock; } rw CK_CC_CACHELINE = { .lock = CK_RWLOCK_INITIALIZER }; static struct affinity affinity; #ifdef CK_F_PR_RTM static void * thread_lock_rtm(void *pun) { uint64_t s_b, e_b, a, i; uint64_t *value = pun; if (aff_iterate(&affinity) != 0) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads) ck_pr_stall(); for (i = 1, a = 0;; i++) { s_b = rdtsc(); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_LOCK(ck_rwlock_read, &rw.lock); CK_ELIDE_UNLOCK(ck_rwlock_read, &rw.lock); e_b = rdtsc(); a += (e_b - s_b) >> 4; if (ck_pr_load_uint(&flag) == 1) break; } ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads * 2) ck_pr_stall(); *value = (a / i); return NULL; } #endif /* CK_F_PR_RTM */ static void * thread_lock(void *pun) { uint64_t s_b, e_b, a, i; uint64_t *value = pun; if (aff_iterate(&affinity) != 0) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads) ck_pr_stall(); for (i = 1, a = 0;; i++) { s_b = rdtsc(); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); ck_rwlock_read_lock(&rw.lock); ck_rwlock_read_unlock(&rw.lock); e_b = rdtsc(); a += (e_b - s_b) >> 4; if (ck_pr_load_uint(&flag) == 1) break; } ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads * 2) ck_pr_stall(); *value = (a / i); return NULL; } static void rwlock_test(pthread_t *p, int d, uint64_t *latency, void *(*f)(void *), const char *label) { int t; ck_pr_store_int(&barrier, 0); ck_pr_store_uint(&flag, 0); affinity.delta = d; affinity.request = 0; fprintf(stderr, "Creating threads (%s)...", label); for (t = 0; t < threads; t++) { if (pthread_create(&p[t], NULL, f, latency + t) != 0) { ck_error("ERROR: Could not create thread %d\n", t); } } fprintf(stderr, "done\n"); common_sleep(10); ck_pr_store_uint(&flag, 1); fprintf(stderr, "Waiting for threads to finish acquisition regression..."); for (t = 0; t < threads; t++) pthread_join(p[t], NULL); fprintf(stderr, "done\n\n"); for (t = 1; t <= threads; t++) printf("%10u %20" PRIu64 "\n", t, latency[t - 1]); fprintf(stderr, "\n"); return; } int main(int argc, char *argv[]) { int d; pthread_t *p; uint64_t *latency; if (argc != 3) { ck_error("Usage: throughput \n"); } threads = atoi(argv[2]); if (threads <= 0) { ck_error("ERROR: Threads must be a value > 0.\n"); } p = malloc(sizeof(pthread_t) * threads); if (p == NULL) { ck_error("ERROR: Failed to initialize thread.\n"); } latency = malloc(sizeof(uint64_t) * threads); if (latency == NULL) { ck_error("ERROR: Failed to create latency buffer.\n"); } d = atoi(argv[1]); rwlock_test(p, d, latency, thread_lock, "rwlock"); #ifdef CK_F_PR_RTM rwlock_test(p, d, latency, thread_lock_rtm, "rwlock, rtm"); #endif /* CK_F_PR_RTM */ return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_rwlock/validate/validate.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 1000000 #endif static struct affinity a; static unsigned int locked; static unsigned int tid = 2; static int nthr; static ck_rwlock_t lock = CK_RWLOCK_INITIALIZER; static ck_rwlock_recursive_t r_lock = CK_RWLOCK_RECURSIVE_INITIALIZER; static void * thread_recursive(void *null CK_CC_UNUSED) { int i = ITERATE; unsigned int l; unsigned int t = ck_pr_faa_uint(&tid, 1); if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { while (ck_rwlock_recursive_write_trylock(&r_lock, t) == false) ck_pr_stall(); ck_rwlock_recursive_write_lock(&r_lock, t); ck_rwlock_recursive_write_lock(&r_lock, t); ck_rwlock_recursive_write_lock(&r_lock, t); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } ck_rwlock_recursive_write_unlock(&r_lock); ck_rwlock_recursive_write_unlock(&r_lock); ck_rwlock_recursive_write_unlock(&r_lock); ck_rwlock_recursive_write_unlock(&r_lock); ck_rwlock_recursive_read_lock(&r_lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } ck_rwlock_recursive_read_unlock(&r_lock); } return (NULL); } #ifdef CK_F_PR_RTM static void * thread_rtm_adaptive(void *null CK_CC_UNUSED) { unsigned int i = ITERATE; unsigned int l; struct ck_elide_config config = CK_ELIDE_CONFIG_DEFAULT_INITIALIZER; struct ck_elide_stat st = CK_ELIDE_STAT_INITIALIZER; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { CK_ELIDE_LOCK_ADAPTIVE(ck_rwlock_write, &st, &config, &lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } CK_ELIDE_UNLOCK_ADAPTIVE(ck_rwlock_write, &st, &lock); CK_ELIDE_LOCK(ck_rwlock_read, &lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } CK_ELIDE_UNLOCK(ck_rwlock_read, &lock); } return NULL; } static void * thread_rtm_mix(void *null CK_CC_UNUSED) { unsigned int i = ITERATE; unsigned int l; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { if (i & 1) { CK_ELIDE_LOCK(ck_rwlock_write, &lock); } else { ck_rwlock_write_lock(&lock); } { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } if (i & 1) { CK_ELIDE_UNLOCK(ck_rwlock_write, &lock); } else { ck_rwlock_write_unlock(&lock); } if (i & 1) { CK_ELIDE_LOCK(ck_rwlock_read, &lock); } else { ck_rwlock_read_lock(&lock); } { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } if (i & 1) { CK_ELIDE_UNLOCK(ck_rwlock_read, &lock); } else { ck_rwlock_read_unlock(&lock); } } return (NULL); } static void * thread_rtm(void *null CK_CC_UNUSED) { unsigned int i = ITERATE; unsigned int l; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { CK_ELIDE_LOCK(ck_rwlock_write, &lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } CK_ELIDE_UNLOCK(ck_rwlock_write, &lock); CK_ELIDE_LOCK(ck_rwlock_read, &lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } CK_ELIDE_UNLOCK(ck_rwlock_read, &lock); } return (NULL); } #endif /* CK_F_PR_RTM */ static void * thread(void *null CK_CC_UNUSED) { unsigned int i = ITERATE; unsigned int l; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { ck_rwlock_write_lock(&lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } ck_rwlock_write_unlock(&lock); ck_rwlock_read_lock(&lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } ck_rwlock_read_unlock(&lock); } return (NULL); } static void rwlock_test(pthread_t *threads, void *(*f)(void *), const char *test) { int i; fprintf(stderr, "Creating threads (%s)...", test); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, f, NULL)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return; } int main(int argc, char *argv[]) { pthread_t *threads; if (argc != 3) { ck_error("Usage: validate \n"); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } a.delta = atoi(argv[2]); rwlock_test(threads, thread, "regular"); #ifdef CK_F_PR_RTM rwlock_test(threads, thread_rtm, "rtm"); rwlock_test(threads, thread_rtm_mix, "rtm-mix"); rwlock_test(threads, thread_rtm_adaptive, "rtm-adaptive"); #endif rwlock_test(threads, thread_recursive, "recursive"); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_sequence/benchmark/ck_sequence.c ================================================ /* * Copyright 2013-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS (65536 * 64) #endif static ck_sequence_t seqlock CK_CC_CACHELINE = CK_SEQUENCE_INITIALIZER; int main(void) { unsigned int i = 0; unsigned int version; uint64_t a, s; /* Read-side latency. */ a = 0; for (i = 0; i < STEPS / 4; i++) { s = rdtsc(); ck_sequence_read_retry(&seqlock, ck_sequence_read_begin(&seqlock)); ck_sequence_read_retry(&seqlock, ck_sequence_read_begin(&seqlock)); ck_sequence_read_retry(&seqlock, ck_sequence_read_begin(&seqlock)); ck_sequence_read_retry(&seqlock, ck_sequence_read_begin(&seqlock)); a += rdtsc() - s; } printf("read: %" PRIu64 "\n", a / STEPS); a = 0; for (i = 0; i < STEPS / 4; i++) { s = rdtsc(); CK_SEQUENCE_READ(&seqlock, &version); CK_SEQUENCE_READ(&seqlock, &version); CK_SEQUENCE_READ(&seqlock, &version); CK_SEQUENCE_READ(&seqlock, &version); a += rdtsc() - s; } printf("READ %" PRIu64 "\n", a / STEPS); /* Write-side latency. */ a = 0; for (i = 0; i < STEPS / 4; i++) { s = rdtsc(); ck_sequence_write_begin(&seqlock); ck_sequence_write_end(&seqlock); ck_sequence_write_begin(&seqlock); ck_sequence_write_end(&seqlock); ck_sequence_write_begin(&seqlock); ck_sequence_write_end(&seqlock); ck_sequence_write_begin(&seqlock); ck_sequence_write_end(&seqlock); a += rdtsc() - s; } printf("write: %" PRIu64 "\n", a / STEPS); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_sequence/validate/ck_sequence.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS 1000000 #endif struct example { unsigned int a; unsigned int b; unsigned int c; }; static struct example global CK_CC_CACHELINE; static ck_sequence_t seqlock CK_CC_CACHELINE = CK_SEQUENCE_INITIALIZER; static unsigned int barrier; static struct affinity affinerator; static void validate(struct example *copy) { if (copy->b != copy->a + 1000) { ck_error("ERROR: Failed regression: copy->b (%u != %u + %u / %u)\n", copy->b, copy->a, 1000, copy->a + 1000); } if (copy->c != copy->a + copy->b) { ck_error("ERROR: Failed regression: copy->c (%u != %u + %u / %u)\n", copy->c, copy->a, copy->b, copy->a + copy->b); } return; } static void * consumer(void *unused CK_CC_UNUSED) { struct example copy; uint32_t version; unsigned int retries = 0; unsigned int i; unused = NULL; if (aff_iterate(&affinerator)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (ck_pr_load_uint(&barrier) == 0); for (i = 0; i < STEPS; i++) { /* * Attempt a read of the data structure. If the structure * has been modified between ck_sequence_read_begin and * ck_sequence_read_retry then attempt another read since * the data may be in an inconsistent state. */ do { version = ck_sequence_read_begin(&seqlock); copy.a = ck_pr_load_uint(&global.a); copy.b = ck_pr_load_uint(&global.b); copy.c = ck_pr_load_uint(&global.c); retries++; } while (ck_sequence_read_retry(&seqlock, version) == true); validate(©); CK_SEQUENCE_READ(&seqlock, &version) { copy.a = ck_pr_load_uint(&global.a); copy.b = ck_pr_load_uint(&global.b); copy.c = ck_pr_load_uint(&global.c); retries++; } validate(©); } fprintf(stderr, "%u retries.\n", retries - STEPS); ck_pr_dec_uint(&barrier); return (NULL); } int main(int argc, char *argv[]) { pthread_t *threads; unsigned int counter = 0; bool first = true; int n_threads, i; if (argc != 3) { ck_error("Usage: ck_sequence \n"); } n_threads = atoi(argv[1]); if (n_threads <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * n_threads); if (threads == NULL) { ck_error("ERROR: Could not allocate memory for threads\n"); } affinerator.delta = atoi(argv[2]); affinerator.request = 0; for (i = 0; i < n_threads; i++) { if (pthread_create(&threads[i], NULL, consumer, NULL)) { ck_error("ERROR: Failed to create thread %d\n", i); } } for (;;) { /* * Update the shared data in a non-blocking fashion. * If the data is modified by multiple writers then * ck_sequence_write_begin must be called after acquiring * the associated lock and ck_sequence_write_end must be * called before relinquishing the lock. */ ck_sequence_write_begin(&seqlock); global.a = counter++; global.b = global.a + 1000; global.c = global.b + global.a; ck_sequence_write_end(&seqlock); if (first == true) { ck_pr_store_uint(&barrier, n_threads); first = false; } counter++; if (ck_pr_load_uint(&barrier) == 0) break; } printf("%u updates made.\n", counter); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/ck_anderson.c ================================================ #include "../ck_anderson.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/ck_cas.c ================================================ #include "../ck_cas.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/ck_clh.c ================================================ #include "../ck_clh.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/ck_dec.c ================================================ #include "../ck_dec.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/ck_fas.c ================================================ #include "../ck_fas.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/ck_hclh.c ================================================ #include "../ck_hclh.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/ck_mcs.c ================================================ #include "../ck_mcs.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/ck_spinlock.c ================================================ #include "../ck_spinlock.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/ck_ticket.c ================================================ #include "../ck_ticket.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/ck_ticket_pb.c ================================================ #include "../ck_ticket_pb.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/latency.h ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS 30000000 #endif LOCK_DEFINE; int main(void) { CK_CC_UNUSED unsigned int nthr = 1; #ifdef LOCK_INIT LOCK_INIT; #endif #ifdef LOCK_STATE LOCK_STATE; #endif uint64_t s_b, e_b, i; CK_CC_UNUSED int core = 0; s_b = rdtsc(); for (i = 0; i < STEPS; ++i) { #ifdef LOCK LOCK; UNLOCK; LOCK; UNLOCK; LOCK; UNLOCK; LOCK; UNLOCK; #endif } e_b = rdtsc(); printf("%15" PRIu64 "\n", (e_b - s_b) / 4 / STEPS); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/linux_spinlock.c ================================================ #include "../linux_spinlock.h" #ifdef THROUGHPUT #include "throughput.h" #elif defined(LATENCY) #include "latency.h" #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/benchmark/throughput.h ================================================ /* * Copyright 2008-2012 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" /* 8! = 40320, evenly divide 1 .. 8 processor workload. */ #define WORKLOAD (40320 * 2056) #ifndef ITERATE #define ITERATE 65536 #endif struct block { unsigned int tid; }; static struct affinity a; static unsigned int ready; struct counters { uint64_t value; } CK_CC_CACHELINE; static struct counters *count; static uint64_t nthr; static unsigned int barrier; int critical __attribute__((aligned(64))); LOCK_DEFINE; CK_CC_USED static void gen_lock(void) { CK_CC_UNUSED int core = 0; #ifdef LOCK_STATE LOCK_STATE; #endif #ifdef LOCK LOCK; #endif } CK_CC_USED static void gen_unlock(void) { #ifdef LOCK_STATE LOCK_STATE; #endif #ifdef UNLOCK UNLOCK; #endif } static void * fairness(void *null) { #ifdef LOCK_STATE LOCK_STATE; #endif struct block *context = null; unsigned int i = context->tid; volatile int j; long int base; unsigned int core; if (aff_iterate_core(&a, &core)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (ck_pr_load_uint(&ready) == 0); ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) != nthr); while (ready) { LOCK; count[i].value++; if (critical) { base = common_lrand48() % critical; for (j = 0; j < base; j++); } UNLOCK; } return (NULL); } int main(int argc, char *argv[]) { uint64_t v, d; unsigned int i; pthread_t *threads; struct block *context; if (argc != 4) { ck_error("Usage: " LOCK_NAME " \n"); exit(EXIT_FAILURE); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); exit(EXIT_FAILURE); } #ifdef LOCK_INIT LOCK_INIT; #endif critical = atoi(argv[3]); if (critical < 0) { ck_error("ERROR: critical section cannot be negative\n"); exit(EXIT_FAILURE); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); exit(EXIT_FAILURE); } context = malloc(sizeof(struct block) * nthr); if (context == NULL) { ck_error("ERROR: Could not allocate thread contexts\n"); exit(EXIT_FAILURE); } a.delta = atoi(argv[2]); a.request = 0; count = malloc(sizeof(*count) * nthr); if (count == NULL) { ck_error("ERROR: Could not create acquisition buffer\n"); exit(EXIT_FAILURE); } memset(count, 0, sizeof(*count) * nthr); fprintf(stderr, "Creating threads (fairness)..."); for (i = 0; i < nthr; i++) { context[i].tid = i; if (pthread_create(&threads[i], NULL, fairness, context + i)) { ck_error("ERROR: Could not create thread %d\n", i); exit(EXIT_FAILURE); } } fprintf(stderr, "done\n"); ck_pr_store_uint(&ready, 1); common_sleep(10); ck_pr_store_uint(&ready, 0); fprintf(stderr, "Waiting for threads to finish acquisition regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done\n\n"); for (i = 0, v = 0; i < nthr; i++) { printf("%d %15" PRIu64 "\n", i, count[i].value); v += count[i].value; } printf("\n# total : %15" PRIu64 "\n", v); printf("# throughput : %15" PRIu64 " a/s\n", (v /= nthr) / 10); for (i = 0, d = 0; i < nthr; i++) d += (count[i].value - v) * (count[i].value - v); printf("# average : %15" PRIu64 "\n", v); printf("# deviation : %.2f (%.2f%%)\n\n", sqrt(d / nthr), (sqrt(d / nthr) / v) * 100.00); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/ck_anderson.h ================================================ #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LOCK_NAME "ck_anderson" #define LOCK_DEFINE static ck_spinlock_anderson_t lock CK_CC_CACHELINE #define LOCK_STATE ck_spinlock_anderson_thread_t *nad = NULL #define LOCK ck_spinlock_anderson_lock(&lock, &nad) #define UNLOCK ck_spinlock_anderson_unlock(&lock, nad) #define LOCK_INIT ck_spinlock_anderson_init(&lock, malloc(MAX(64,sizeof(ck_spinlock_anderson_thread_t)) * nthr), nthr) #define LOCKED ck_spinlock_anderson_locked(&lock) #define NO_LOCAL ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/ck_cas.h ================================================ #define LOCK_NAME "ck_cas" #define LOCK_DEFINE static ck_spinlock_cas_t CK_CC_CACHELINE lock = CK_SPINLOCK_CAS_INITIALIZER #define LOCK ck_spinlock_cas_lock_eb(&lock) #define UNLOCK ck_spinlock_cas_unlock(&lock) #define LOCKED ck_spinlock_cas_locked(&lock) ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/ck_clh.h ================================================ #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LOCK_NAME "ck_clh" #define LOCK_DEFINE static ck_spinlock_clh_t CK_CC_CACHELINE *lock = NULL #define LOCK_STATE ck_spinlock_clh_t *na = malloc(MAX(sizeof(ck_spinlock_clh_t), 64)) #define LOCK ck_spinlock_clh_lock(&lock, na) #define UNLOCK ck_spinlock_clh_unlock(&na) #define LOCK_INIT ck_spinlock_clh_init(&lock, malloc(MAX(sizeof(ck_spinlock_clh_t), 64))) #define LOCKED ck_spinlock_clh_locked(&lock) ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/ck_dec.h ================================================ #define LOCK_NAME "ck_dec" #define LOCK_DEFINE static ck_spinlock_dec_t CK_CC_CACHELINE lock = CK_SPINLOCK_DEC_INITIALIZER #define LOCK ck_spinlock_dec_lock_eb(&lock) #define UNLOCK ck_spinlock_dec_unlock(&lock) #define LOCKED ck_spinlock_dec_locked(&lock) ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/ck_fas.h ================================================ #define LOCK_NAME "ck_fas" #define LOCK_DEFINE static ck_spinlock_fas_t CK_CC_CACHELINE lock = CK_SPINLOCK_FAS_INITIALIZER #define LOCK ck_spinlock_fas_lock_eb(&lock) #define UNLOCK ck_spinlock_fas_unlock(&lock) #define LOCKED ck_spinlock_fas_locked(&lock) ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/ck_hclh.h ================================================ #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LOCK_NAME "ck_clh" #define LOCK_DEFINE static ck_spinlock_hclh_t CK_CC_CACHELINE *glob_lock; \ static ck_spinlock_hclh_t CK_CC_CACHELINE *local_lock[CORES / 2] #define LOCK_STATE ck_spinlock_hclh_t *na = malloc(MAX(sizeof(ck_spinlock_hclh_t), 64)) #define LOCK ck_spinlock_hclh_lock(&glob_lock, &local_lock[(core % CORES) / 2], na) #define UNLOCK ck_spinlock_hclh_unlock(&na) #define LOCK_INIT do { \ int _i; \ ck_spinlock_hclh_init(&glob_lock, malloc(MAX(sizeof(ck_spinlock_hclh_t), 64)), -1); \ for (_i = 0; _i < CORES / 2; _i++) { \ ck_spinlock_hclh_init(&local_lock[_i], malloc(MAX(sizeof(ck_spinlock_hclh_t), 64)), _i); } \ } while (0) #define LOCKED ck_spinlock_hclh_locked(&glob_lock) ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/ck_mcs.h ================================================ #define LOCK_NAME "ck_mcs" #define LOCK_DEFINE static ck_spinlock_mcs_t CK_CC_CACHELINE lock = NULL #define LOCK_STATE ck_spinlock_mcs_context_t node CK_CC_CACHELINE; #define LOCK ck_spinlock_mcs_lock(&lock, &node) #define UNLOCK ck_spinlock_mcs_unlock(&lock, &node) #define LOCKED ck_spinlock_mcs_locked(&lock) ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/ck_spinlock.h ================================================ #define LOCK_NAME "ck_spinlock" #define LOCK_DEFINE static ck_spinlock_t CK_CC_CACHELINE lock = CK_SPINLOCK_INITIALIZER #define LOCK ck_spinlock_lock_eb(&lock) #define UNLOCK ck_spinlock_unlock(&lock) #define LOCKED ck_spinlock_locked(&lock) ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/ck_ticket.h ================================================ #include #define LOCK_NAME "ck_ticket" #define LOCK_DEFINE static ck_spinlock_ticket_t CK_CC_CACHELINE lock = CK_SPINLOCK_TICKET_INITIALIZER #define LOCK ck_spinlock_ticket_lock(&lock) #define UNLOCK ck_spinlock_ticket_unlock(&lock) #ifdef CK_F_SPINLOCK_TICKET_TRYLOCK #define TRYLOCK ck_spinlock_ticket_trylock(&lock) #endif #define LOCKED ck_spinlock_ticket_locked(&lock) ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/ck_ticket_pb.h ================================================ #define LOCK_NAME "ck_ticket_pb" #define LOCK_DEFINE static ck_spinlock_ticket_t CK_CC_CACHELINE lock = CK_SPINLOCK_TICKET_INITIALIZER #define LOCK ck_spinlock_ticket_lock_pb(&lock, 0) #define UNLOCK ck_spinlock_ticket_unlock(&lock) #define LOCKED ck_spinlock_ticket_locked(&lock) ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/linux_spinlock.h ================================================ #include CK_CC_INLINE static void spin_lock(volatile unsigned int *lock) { #ifdef __x86_64__ __asm__ __volatile__( "\n1:\t" "lock ; decl %0\n\t" "jns 2f\n" "3:\n" "rep;nop\n\t" "cmpl $0,%0\n\t" "jle 3b\n\t" "jmp 1b\n" "2:\t" : "=m" (*lock) : : "memory"); #else *lock = 1; #endif return; } CK_CC_INLINE static void spin_unlock(volatile unsigned int *lock) { #ifdef __x86_64__ __asm__ __volatile__("movl $1,%0" :"=m" (*lock) :: "memory"); #else *lock = 0; return; #endif } #define LOCK_NAME "linux_spinlock" #define LOCK_DEFINE volatile unsigned int lock = 1 #define LOCK spin_lock(&lock) #define UNLOCK spin_unlock(&lock) ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/ck_anderson.c ================================================ #include "../ck_anderson.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/ck_cas.c ================================================ #include "../ck_cas.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/ck_clh.c ================================================ #include "../ck_clh.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/ck_dec.c ================================================ #include "../ck_dec.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/ck_fas.c ================================================ #include "../ck_fas.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/ck_hclh.c ================================================ #include "../ck_hclh.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/ck_mcs.c ================================================ #include "../ck_mcs.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/ck_spinlock.c ================================================ #include "../ck_spinlock.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/ck_ticket.c ================================================ #include "../ck_ticket.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/ck_ticket_pb.c ================================================ #include "../ck_ticket_pb.h" #include "validate.h" ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/linux_spinlock.c ================================================ #ifdef __x86_64__ #include "../linux_spinlock.h" #include "validate.h" #else #include int main(void) { fprintf(stderr, "Unsupported.\n"); return 0; } #endif ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_spinlock/validate/validate.h ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 1000000 #endif struct block { unsigned int tid; }; static struct affinity a; static unsigned int locked = 0; static uint64_t nthr; LOCK_DEFINE; static void * thread(void *null CK_CC_UNUSED) { #ifdef LOCK_STATE LOCK_STATE; #endif unsigned int i = ITERATE; unsigned int j; unsigned int core; if (aff_iterate_core(&a, &core)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { #ifdef TRYLOCK if (i & 1) { LOCK; } else { while (TRYLOCK == false) ck_pr_stall(); } #else LOCK; #endif #ifdef LOCKED if (LOCKED == false) ck_error("is_locked operation failed."); #endif ck_pr_store_uint(&locked, locked + 1); ck_pr_store_uint(&locked, locked + 1); ck_pr_store_uint(&locked, locked + 1); ck_pr_store_uint(&locked, locked + 1); ck_pr_store_uint(&locked, locked + 1); ck_pr_store_uint(&locked, locked + 1); ck_pr_store_uint(&locked, locked + 1); ck_pr_store_uint(&locked, locked + 1); ck_pr_store_uint(&locked, locked + 1); ck_pr_store_uint(&locked, locked + 1); j = ck_pr_load_uint(&locked); if (j != 10) { ck_error("ERROR (WR): Race condition (%u)\n", j); exit(EXIT_FAILURE); } ck_pr_store_uint(&locked, locked - 1); ck_pr_store_uint(&locked, locked - 1); ck_pr_store_uint(&locked, locked - 1); ck_pr_store_uint(&locked, locked - 1); ck_pr_store_uint(&locked, locked - 1); ck_pr_store_uint(&locked, locked - 1); ck_pr_store_uint(&locked, locked - 1); ck_pr_store_uint(&locked, locked - 1); ck_pr_store_uint(&locked, locked - 1); ck_pr_store_uint(&locked, locked - 1); UNLOCK; LOCK; j = ck_pr_load_uint(&locked); if (j != 0) { ck_error("ERROR (RD): Race condition (%u)\n", j); exit(EXIT_FAILURE); } UNLOCK; } return (NULL); } int main(int argc, char *argv[]) { uint64_t i; pthread_t *threads; if (argc != 3) { ck_error("Usage: " LOCK_NAME " \n"); exit(EXIT_FAILURE); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); exit(EXIT_FAILURE); } #ifdef LOCK_INIT LOCK_INIT; #endif threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); exit(EXIT_FAILURE); } a.delta = atoi(argv[2]); a.request = 0; fprintf(stderr, "Creating threads (mutual exclusion)..."); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, thread, NULL)) { ck_error("ERROR: Could not create thread %" PRIu64 "\n", i); exit(EXIT_FAILURE); } } fprintf(stderr, "done\n"); fprintf(stderr, "Waiting for threads to finish correctness regression..."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_stack/benchmark/latency.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "../../common.h" #ifndef ENTRIES #define ENTRIES 4096 #endif #ifndef STEPS #define STEPS 40000 #endif /* * Note the redundant post-increment of r. This is to silence * some irrelevant GCC warnings. */ static ck_stack_t stack CK_CC_CACHELINE; int main(void) { ck_stack_entry_t entry[ENTRIES]; ck_spinlock_fas_t mutex = CK_SPINLOCK_FAS_INITIALIZER; volatile ck_stack_entry_t * volatile r; uint64_t s, e, a; unsigned int i; unsigned int j; a = 0; for (i = 0; i < STEPS; i++) { ck_stack_init(&stack); s = rdtsc(); for (j = 0; j < ENTRIES; j++) { ck_spinlock_fas_lock(&mutex); ck_stack_push_spnc(&stack, entry + j); ck_spinlock_fas_unlock(&mutex); } e = rdtsc(); a += e - s; } printf(" spinlock_push: %16" PRIu64 "\n", a / STEPS / ENTRIES); a = 0; for (i = 0; i < STEPS; i++) { ck_stack_init(&stack); for (j = 0; j < ENTRIES; j++) ck_stack_push_spnc(&stack, entry + j); s = rdtsc(); for (j = 0; j < ENTRIES; j++) { ck_spinlock_fas_lock(&mutex); r = ck_stack_pop_npsc(&stack); ck_spinlock_fas_unlock(&mutex); } e = rdtsc(); a += e - s; } printf(" spinlock_pop: %16" PRIu64 "\n", a / STEPS / ENTRIES); r++; #ifdef CK_F_STACK_PUSH_UPMC a = 0; for (i = 0; i < STEPS; i++) { ck_stack_init(&stack); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_stack_push_upmc(&stack, entry + j); e = rdtsc(); a += e - s; } printf("ck_stack_push_upmc: %16" PRIu64 "\n", a / STEPS / ENTRIES); #endif /* CK_F_STACK_PUSH_UPMC */ #ifdef CK_F_STACK_PUSH_MPMC a = 0; for (i = 0; i < STEPS; i++) { ck_stack_init(&stack); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_stack_push_mpmc(&stack, entry + j); e = rdtsc(); a += e - s; } printf("ck_stack_push_mpmc: %16" PRIu64 "\n", a / STEPS / ENTRIES); #endif /* CK_F_STACK_PUSH_MPMC */ #ifdef CK_F_STACK_PUSH_MPNC a = 0; for (i = 0; i < STEPS; i++) { ck_stack_init(&stack); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_stack_push_mpnc(&stack, entry + j); e = rdtsc(); a += e - s; } printf("ck_stack_push_mpnc: %16" PRIu64 "\n", a / STEPS / ENTRIES); #endif /* CK_F_STACK_PUSH_MPNC */ #if defined(CK_F_STACK_PUSH_UPMC) && defined(CK_F_STACK_POP_UPMC) a = 0; for (i = 0; i < STEPS; i++) { ck_stack_init(&stack); for (j = 0; j < ENTRIES; j++) ck_stack_push_upmc(&stack, entry + j); s = rdtsc(); for (j = 0; j < ENTRIES; j++) r = ck_stack_pop_upmc(&stack); e = rdtsc(); a += e - s; } printf(" ck_stack_pop_upmc: %16" PRIu64 "\n", a / STEPS / (sizeof(entry) / sizeof(*entry))); #endif /* CK_F_STACK_PUSH_UPMC && CK_F_STACK_POP_UPMC */ #if defined(CK_F_STACK_POP_MPMC) && defined(CK_F_STACK_PUSH_MPMC) a = 0; for (i = 0; i < STEPS; i++) { ck_stack_init(&stack); for (j = 0; j < ENTRIES; j++) ck_stack_push_mpmc(&stack, entry + j); s = rdtsc(); for (j = 0; j < ENTRIES; j++) r = ck_stack_pop_mpmc(&stack); e = rdtsc(); a += e - s; } printf(" ck_stack_pop_mpmc: %16" PRIu64 "\n", a / STEPS / (sizeof(entry) / sizeof(*entry))); r++; #endif return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_stack/validate/pair.c ================================================ /* * Copyright 2009 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #ifdef SPINLOCK #include #endif #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITEMS #define ITEMS (5765760) #endif #define TVTOD(tv) ((tv).tv_sec+((tv).tv_usec / (double)1000000)) struct entry { int value; #if defined(SPINLOCK) || defined(PTHREADS) struct entry *next; #else ck_stack_entry_t next; #endif } CK_CC_CACHELINE; #ifdef SPINLOCK static struct entry *stack CK_CC_CACHELINE; ck_spinlock_fas_t stack_spinlock = CK_SPINLOCK_FAS_INITIALIZER; #define UNLOCK ck_spinlock_fas_unlock #if defined(EB) #define LOCK ck_spinlock_fas_lock_eb #else #define LOCK ck_spinlock_fas_lock #endif #elif defined(PTHREADS) static struct entry *stack CK_CC_CACHELINE; pthread_mutex_t stack_spinlock = PTHREAD_MUTEX_INITIALIZER; #define LOCK pthread_mutex_lock #define UNLOCK pthread_mutex_unlock #else static ck_stack_t stack CK_CC_CACHELINE; CK_STACK_CONTAINER(struct entry, next, getvalue) #endif static struct affinity affinerator; static unsigned long long nthr; static volatile unsigned int barrier = 0; static unsigned int critical; static void * stack_thread(void *buffer) { #if (defined(MPMC) && defined(CK_F_STACK_POP_MPMC)) || (defined(UPMC) && defined(CK_F_STACK_POP_UPMC)) || (defined(TRYUPMC) && defined(CK_F_STACK_TRYPOP_UPMC)) || (defined(TRYMPMC) && defined(CK_F_STACK_TRYPOP_MPMC)) ck_stack_entry_t *ref; #endif struct entry *entry = buffer; unsigned long long i, n = ITEMS; unsigned int seed; int j; if (aff_iterate(&affinerator)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } while (barrier == 0); for (i = 0; i < n; i++) { #if defined(MPMC) ck_stack_push_mpmc(&stack, &entry->next); #elif defined(TRYMPMC) while (ck_stack_trypush_mpmc(&stack, &entry->next) == false) ck_pr_stall(); #elif defined(UPMC) ck_stack_push_upmc(&stack, &entry->next); #elif defined(TRYUPMC) while (ck_stack_trypush_upmc(&stack, &entry->next) == false) ck_pr_stall(); #elif defined(SPINLOCK) || defined(PTHREADS) LOCK(&stack_spinlock); ck_pr_store_ptr(&entry->next, stack); ck_pr_store_ptr(&stack, entry); UNLOCK(&stack_spinlock); #else # error Undefined operation. #endif if (critical) { j = common_rand_r(&seed) % critical; while (j--) __asm__ __volatile__("" ::: "memory"); } #if defined(MPMC) #ifdef CK_F_STACK_POP_MPMC ref = ck_stack_pop_mpmc(&stack); entry = getvalue(ref); #endif #elif defined(TRYMPMC) #ifdef CK_F_STACK_TRYPOP_MPMC while (ck_stack_trypop_mpmc(&stack, &ref) == false) ck_pr_stall(); entry = getvalue(ref); #endif /* CK_F_STACK_TRYPOP_MPMC */ #elif defined(UPMC) ref = ck_stack_pop_upmc(&stack); entry = getvalue(ref); #elif defined(SPINLOCK) || defined(PTHREADS) LOCK(&stack_spinlock); entry = stack; stack = stack->next; UNLOCK(&stack_spinlock); #else # error Undefined operation. #endif } return (NULL); } static void stack_assert(void) { #if defined(SPINLOCK) || defined(PTHREADS) assert(stack == NULL); #else assert(CK_STACK_ISEMPTY(&stack)); #endif return; } int main(int argc, char *argv[]) { struct entry *bucket; unsigned long long i, d; pthread_t *thread; struct timeval stv, etv; #if (defined(TRYMPMC) || defined(MPMC)) && (!defined(CK_F_STACK_PUSH_MPMC) || !defined(CK_F_STACK_POP_MPMC)) fprintf(stderr, "Unsupported.\n"); return 0; #endif if (argc != 4) { ck_error("Usage: stack \n"); } { char *e; nthr = strtol(argv[1], &e, 10); if (errno == ERANGE) { perror("ERROR: too many threads"); exit(EXIT_FAILURE); } else if (*e != '\0') { ck_error("ERROR: input format is incorrect\n"); } d = strtol(argv[2], &e, 10); if (errno == ERANGE) { perror("ERROR: delta is too large"); exit(EXIT_FAILURE); } else if (*e != '\0') { ck_error("ERROR: input format is incorrect\n"); } critical = strtoul(argv[3], &e, 10); if (errno == ERANGE) { perror("ERROR: critical section is too large"); exit(EXIT_FAILURE); } else if (*e != '\0') { ck_error("ERROR: input format is incorrect\n"); } } srand(getpid()); affinerator.request = 0; affinerator.delta = d; bucket = malloc(sizeof(struct entry) * nthr); assert(bucket != NULL); thread = malloc(sizeof(pthread_t) * nthr); assert(thread != NULL); for (i = 0; i < nthr; i++) pthread_create(&thread[i], NULL, stack_thread, bucket + i); barrier = 1; for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); barrier = 0; for (i = 0; i < nthr; i++) pthread_create(&thread[i], NULL, stack_thread, bucket + i); common_gettimeofday(&stv, NULL); barrier = 1; for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); common_gettimeofday(&etv, NULL); stack_assert(); #ifdef _WIN32 printf("%3llu %.6f\n", nthr, TVTOD(etv) - TVTOD(stv)); #else printf("%3llu %.6lf\n", nthr, TVTOD(etv) - TVTOD(stv)); #endif return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_stack/validate/pop.c ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #ifdef SPINLOCK #include #endif #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITEMS #define ITEMS (5765760 * 2) #endif #define TVTOD(tv) ((tv).tv_sec+((tv).tv_usec / (double)1000000)) struct entry { int value; #ifdef SPINLOCK struct entry *next; #else ck_stack_entry_t next; #endif }; #ifdef SPINLOCK static struct entry *stack CK_CC_CACHELINE; ck_spinlock_fas_t stack_spinlock = CK_SPINLOCK_FAS_INITIALIZER; #define UNLOCK ck_spinlock_fas_unlock #if defined(EB) #define LOCK ck_spinlock_fas_lock_eb #else #define LOCK ck_spinlock_fas_lock #endif #else static ck_stack_t stack CK_CC_CACHELINE; CK_STACK_CONTAINER(struct entry, next, getvalue) #endif static struct affinity affinerator = AFFINITY_INITIALIZER; static unsigned long long nthr; static volatile unsigned int barrier = 0; static unsigned int critical; static void * stack_thread(void *unused CK_CC_UNUSED) { #if (defined(MPMC) && defined(CK_F_STACK_POP_MPMC)) || (defined(UPMC) && defined(CK_F_STACK_POP_UPMC)) || (defined(TRYMPMC) && defined(CK_F_STACK_TRYPOP_MPMC)) || (defined(TRYUPMC) && defined(CK_F_STACK_TRYPOP_UPMC)) ck_stack_entry_t *ref; #endif struct entry *entry = NULL; unsigned long long i, n = ITEMS / nthr; unsigned int seed; int j, previous = INT_MAX; if (aff_iterate(&affinerator)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } while (barrier == 0); for (i = 0; i < n; i++) { #ifdef MPMC #ifdef CK_F_STACK_POP_MPMC ref = ck_stack_pop_mpmc(&stack); assert(ref); entry = getvalue(ref); #endif /* CK_F_STACK_POP_MPMC */ #elif defined(TRYMPMC) #ifdef CK_F_STACK_TRYPOP_MPMC while (ck_stack_trypop_mpmc(&stack, &ref) == false) ck_pr_stall(); assert(ref); entry = getvalue(ref); #endif /* CK_F_STACK_TRYPOP_MPMC */ #elif defined(UPMC) ref = ck_stack_pop_upmc(&stack); assert(ref); entry = getvalue(ref); #elif defined(TRYUPMC) while (ck_stack_trypop_upmc(&stack, &ref) == false) ck_pr_stall(); assert(ref); entry = getvalue(ref); #elif defined(SPINLOCK) LOCK(&stack_spinlock); entry = stack; stack = stack->next; UNLOCK(&stack_spinlock); #else # error Undefined operation. #endif if (critical) { j = common_rand_r(&seed) % critical; while (j--) __asm__ __volatile__("" ::: "memory"); } assert (previous >= entry->value); previous = entry->value; } return (NULL); } static void stack_assert(void) { #ifdef SPINLOCK assert(stack == NULL); #else assert(CK_STACK_ISEMPTY(&stack)); #endif return; } static void push_stack(struct entry *bucket) { unsigned long long i; #ifdef SPINLOCK stack = NULL; #else ck_stack_init(&stack); #endif for (i = 0; i < ITEMS; i++) { bucket[i].value = i % INT_MAX; #ifdef SPINLOCK bucket[i].next = stack; stack = bucket + i; #else ck_stack_push_spnc(&stack, &bucket[i].next); #endif } #ifndef SPINLOCK ck_stack_entry_t *entry; i = 0; CK_STACK_FOREACH(&stack, entry) { i++; } assert(i == ITEMS); #endif return; } int main(int argc, char *argv[]) { struct entry *bucket; unsigned long long i, d; pthread_t *thread; struct timeval stv, etv; #if (defined(TRYMPMC) || defined(MPMC)) && (!defined(CK_F_STACK_PUSH_MPMC) || !defined(CK_F_STACK_POP_MPMC)) fprintf(stderr, "Unsupported.\n"); return 0; #endif if (argc != 4) { ck_error("Usage: stack \n"); } { char *e; nthr = strtol(argv[1], &e, 10); if (errno == ERANGE) { perror("ERROR: too many threads"); exit(EXIT_FAILURE); } else if (*e != '\0') { ck_error("ERROR: input format is incorrect\n"); } d = strtol(argv[2], &e, 10); if (errno == ERANGE) { perror("ERROR: delta is too large"); exit(EXIT_FAILURE); } else if (*e != '\0') { ck_error("ERROR: input format is incorrect\n"); } critical = strtoul(argv[3], &e, 10); if (errno == ERANGE) { perror("ERROR: critical section is too large"); exit(EXIT_FAILURE); } else if (*e != '\0') { ck_error("ERROR: input format is incorrect\n"); } } srand(getpid()); affinerator.delta = d; bucket = malloc(sizeof(struct entry) * ITEMS); assert(bucket != NULL); thread = malloc(sizeof(pthread_t) * nthr); assert(thread != NULL); push_stack(bucket); for (i = 0; i < nthr; i++) pthread_create(&thread[i], NULL, stack_thread, NULL); barrier = 1; for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); barrier = 0; push_stack(bucket); for (i = 0; i < nthr; i++) pthread_create(&thread[i], NULL, stack_thread, NULL); common_gettimeofday(&stv, NULL); barrier = 1; for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); common_gettimeofday(&etv, NULL); stack_assert(); #ifdef _WIN32 printf("%3llu %.6f\n", nthr, TVTOD(etv) - TVTOD(stv)); #else printf("%3llu %.6lf\n", nthr, TVTOD(etv) - TVTOD(stv)); #endif return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_stack/validate/push.c ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #ifdef SPINLOCK #include #endif #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITEMS #define ITEMS (5765760 * 2) #endif #define TVTOD(tv) ((tv).tv_sec+((tv).tv_usec / (double)1000000)) struct entry { int value; #ifdef SPINLOCK struct entry *next; #else ck_stack_entry_t next; #endif }; #ifdef SPINLOCK static struct entry *stack CK_CC_CACHELINE; #else static ck_stack_t stack CK_CC_CACHELINE; #endif CK_STACK_CONTAINER(struct entry, next, getvalue) static struct affinity affinerator = AFFINITY_INITIALIZER; static unsigned long long nthr; static volatile unsigned int barrier = 0; static unsigned int critical; #if defined(SPINLOCK) ck_spinlock_fas_t stack_spinlock = CK_SPINLOCK_FAS_INITIALIZER; #define UNLOCK ck_spinlock_fas_unlock #if defined(EB) #define LOCK ck_spinlock_fas_lock_eb #else #define LOCK ck_spinlock_fas_lock #endif #elif defined(PTHREAD) pthread_mutex_t stack_spinlock = PTHREAD_MUTEX_INITIALIZER; #define LOCK pthread_mutex_lock #define UNLOCK pthread_mutex_unlock #endif static void * stack_thread(void *buffer) { struct entry *bucket = buffer; unsigned long long i, n = ITEMS / nthr; unsigned int seed; int j; if (aff_iterate(&affinerator)) { perror("ERROR: failed to affine thread"); exit(EXIT_FAILURE); } while (barrier == 0); for (i = 0; i < n; i++) { bucket[i].value = (i + 1) * 2; #if defined(MPNC) ck_stack_push_mpnc(&stack, &bucket[i].next); #elif defined(MPMC) ck_stack_push_mpmc(&stack, &bucket[i].next); #elif defined(TRYMPMC) while (ck_stack_trypush_mpmc(&stack, &bucket[i].next) == false) ck_pr_stall(); #elif defined(TRYUPMC) while (ck_stack_trypush_upmc(&stack, &bucket[i].next) == false) ck_pr_stall(); #elif defined(UPMC) ck_stack_push_upmc(&stack, &bucket[i].next); #elif defined(SPINLOCK) || defined(PTHREADS) LOCK(&stack_spinlock); bucket[i].next = stack; stack = bucket + i; UNLOCK(&stack_spinlock); #else # error Undefined operation. #endif if (critical) { j = common_rand_r(&seed) % critical; while (j--) __asm__ __volatile__("" ::: "memory"); } } return (NULL); } static void stack_assert(void) { #ifndef SPINLOCK ck_stack_entry_t *n; #endif struct entry *p; unsigned long long c = 0; #ifdef SPINLOCK for (p = stack; p; p = p->next) c++; #else CK_STACK_FOREACH(&stack, n) { p = getvalue(n); (void)((volatile struct entry *)p)->value; c++; } #endif assert(c == ITEMS); return; } int main(int argc, char *argv[]) { struct entry *bucket; unsigned long long i, d, n; pthread_t *thread; struct timeval stv, etv; if (argc != 4) { ck_error("Usage: stack \n"); } { char *e; nthr = strtol(argv[1], &e, 10); if (errno == ERANGE) { perror("ERROR: too many threads"); exit(EXIT_FAILURE); } else if (*e != '\0') { ck_error("ERROR: input format is incorrect\n"); } d = strtol(argv[2], &e, 10); if (errno == ERANGE) { perror("ERROR: delta is too large"); exit(EXIT_FAILURE); } else if (*e != '\0') { ck_error("ERROR: input format is incorrect\n"); } critical = strtoul(argv[3], &e, 10); if (errno == ERANGE) { perror("ERROR: critical section is too large"); exit(EXIT_FAILURE); } else if (*e != '\0') { ck_error("ERROR: input format is incorrect\n"); } } srand(getpid()); affinerator.request = 0; affinerator.delta = d; n = ITEMS / nthr; #ifndef SPINLOCK ck_stack_init(&stack); #else stack = NULL; #endif bucket = malloc(sizeof(struct entry) * ITEMS); assert(bucket != NULL); thread = malloc(sizeof(pthread_t) * nthr); assert(thread != NULL); for (i = 0; i < nthr; i++) pthread_create(&thread[i], NULL, stack_thread, bucket + i * n); barrier = 1; for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); barrier = 0; #ifndef SPINLOCK ck_stack_init(&stack); #else stack = NULL; #endif for (i = 0; i < nthr; i++) pthread_create(&thread[i], NULL, stack_thread, bucket + i * n); common_gettimeofday(&stv, NULL); barrier = 1; for (i = 0; i < nthr; i++) pthread_join(thread[i], NULL); common_gettimeofday(&etv, NULL); stack_assert(); #ifdef _WIN32 printf("%3llu %.6f\n", nthr, TVTOD(etv) - TVTOD(stv)); #else printf("%3llu %.6lf\n", nthr, TVTOD(etv) - TVTOD(stv)); #endif return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_stack/validate/serial.c ================================================ /* * Copyright 2009-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #ifndef SIZE #define SIZE 1024000 #endif struct entry { int value; ck_stack_entry_t next; }; CK_STACK_CONTAINER(struct entry, next, get_entry) #define LOOP(PUSH, POP) \ for (i = 0; i < SIZE; i++) { \ entries[i].value = i; \ PUSH(stack, &entries[i].next); \ } \ for (i = SIZE - 1; i >= 0; i--) { \ entry = POP(stack); \ assert(entry); \ assert(get_entry(entry)->value == i); \ } static void serial(ck_stack_t *stack) { struct entry *entries; ck_stack_entry_t *entry; int i; ck_stack_init(stack); entries = malloc(sizeof(struct entry) * SIZE); assert(entries != NULL); LOOP(ck_stack_push_upmc, ck_stack_pop_upmc); #ifdef CK_F_STACK_POP_MPMC LOOP(ck_stack_push_mpmc, ck_stack_pop_mpmc); #endif LOOP(ck_stack_push_mpnc, ck_stack_pop_upmc); LOOP(ck_stack_push_spnc, ck_stack_pop_npsc); return; } int main(void) { ck_stack_t stack CK_CC_CACHELINE; serial(&stack); return (0); } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_swlock/benchmark/latency.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "../../common.h" #define CK_F_PR_RTM #ifndef STEPS #define STEPS 2000000 #endif int main(void) { uint64_t s_b, e_b, i; ck_swlock_t swlock = CK_SWLOCK_INITIALIZER; for (i = 0; i < STEPS; i++) { ck_swlock_write_lock(&swlock); ck_swlock_write_unlock(&swlock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_swlock_write_lock(&swlock); ck_swlock_write_unlock(&swlock); } e_b = rdtsc(); printf(" WRITE: swlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); for (i = 0; i < STEPS; i++) { ck_swlock_read_lock(&swlock); ck_swlock_read_unlock(&swlock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_swlock_read_lock(&swlock); ck_swlock_read_unlock(&swlock); } e_b = rdtsc(); printf(" READ: swlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); for (i = 0; i < STEPS; i++) { ck_swlock_write_latch(&swlock); ck_swlock_write_unlatch(&swlock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_swlock_write_latch(&swlock); ck_swlock_write_unlatch(&swlock); } e_b = rdtsc(); printf(" LATCH: swlock %15" PRIu64 "\n", (e_b - s_b) / STEPS); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_swlock/benchmark/throughput.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS 1000000 #endif static int barrier; static int threads; static unsigned int flag CK_CC_CACHELINE; static struct { ck_swlock_t lock; } rw CK_CC_CACHELINE = { .lock = CK_SWLOCK_INITIALIZER }; static struct affinity affinity; static void * thread_lock(void *pun) { uint64_t s_b, e_b, a, i; uint64_t *value = pun; if (aff_iterate(&affinity) != 0) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads) ck_pr_stall(); for (i = 1, a = 0;; i++) { s_b = rdtsc(); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); ck_swlock_read_lock(&rw.lock); ck_swlock_read_unlock(&rw.lock); e_b = rdtsc(); a += (e_b - s_b) >> 4; if (ck_pr_load_uint(&flag) == 1) break; } ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads * 2) ck_pr_stall(); *value = (a / i); return NULL; } static void swlock_test(pthread_t *p, int d, uint64_t *latency, void *(*f)(void *), const char *label) { int t; ck_pr_store_int(&barrier, 0); ck_pr_store_uint(&flag, 0); affinity.delta = d; affinity.request = 0; fprintf(stderr, "Creating threads (%s)...", label); for (t = 0; t < threads; t++) { if (pthread_create(&p[t], NULL, f, latency + t) != 0) { ck_error("ERROR: Could not create thread %d\n", t); } } fprintf(stderr, "done\n"); common_sleep(10); ck_pr_store_uint(&flag, 1); fprintf(stderr, "Waiting for threads to finish acquisition regression..."); for (t = 0; t < threads; t++) pthread_join(p[t], NULL); fprintf(stderr, "done\n\n"); for (t = 1; t <= threads; t++) printf("%10u %20" PRIu64 "\n", t, latency[t - 1]); fprintf(stderr, "\n"); return; } int main(int argc, char *argv[]) { int d; pthread_t *p; uint64_t *latency; if (argc != 3) { ck_error("Usage: throughput \n"); } threads = atoi(argv[2]); if (threads <= 0) { ck_error("ERROR: Threads must be a value > 0.\n"); } p = malloc(sizeof(pthread_t) * threads); if (p == NULL) { ck_error("ERROR: Failed to initialize thread.\n"); } latency = malloc(sizeof(uint64_t) * threads); if (latency == NULL) { ck_error("ERROR: Failed to create latency buffer.\n"); } d = atoi(argv[1]); swlock_test(p, d, latency, thread_lock, "swlock"); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_swlock/validate/validate.c ================================================ /* * Copyright 2014 Jaidev Sridhar. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 1000000 #endif static struct affinity a; static unsigned int locked; static int nthr; static ck_swlock_t lock = CK_SWLOCK_INITIALIZER; static ck_swlock_t copy; #ifdef CK_F_PR_RTM static void * thread_rtm_adaptive(void *arg) { unsigned int i = ITERATE; unsigned int l; int tid = ck_pr_load_int(arg); struct ck_elide_config config = CK_ELIDE_CONFIG_DEFAULT_INITIALIZER; struct ck_elide_stat st = CK_ELIDE_STAT_INITIALIZER; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { if (tid == 0) { CK_ELIDE_LOCK_ADAPTIVE(ck_swlock_write, &st, &config, &lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } CK_ELIDE_UNLOCK_ADAPTIVE(ck_swlock_write, &st, &lock); } CK_ELIDE_LOCK(ck_swlock_read, &lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } CK_ELIDE_UNLOCK(ck_swlock_read, &lock); } return NULL; } static void * thread_rtm_mix(void *arg) { unsigned int i = ITERATE; unsigned int l; int tid = ck_pr_load_int(arg); if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { if (tid == 0) { if (i & 1) { CK_ELIDE_LOCK(ck_swlock_write, &lock); } else { ck_swlock_write_lock(&lock); } { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } if (i & 1) { CK_ELIDE_UNLOCK(ck_swlock_write, &lock); } else { ck_swlock_write_unlock(&lock); } } if (i & 1) { CK_ELIDE_LOCK(ck_swlock_read, &lock); } else { ck_swlock_read_lock(&lock); } { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } if (i & 1) { CK_ELIDE_UNLOCK(ck_swlock_read, &lock); } else { ck_swlock_read_unlock(&lock); } } return (NULL); } static void * thread_rtm(void *arg) { unsigned int i = ITERATE; unsigned int l; int tid = ck_pr_load_int(arg); if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { if (tid == 0) { CK_ELIDE_LOCK(ck_swlock_write, &lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } CK_ELIDE_UNLOCK(ck_swlock_write, &lock); } CK_ELIDE_LOCK(ck_swlock_read, &lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } CK_ELIDE_UNLOCK(ck_swlock_read, &lock); } return (NULL); } #endif /* CK_F_PR_RTM */ static void * thread_latch(void *arg) { unsigned int i = ITERATE; unsigned int l; int tid = ck_pr_load_int(arg); if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { if (tid == 0) { /* Writer */ ck_swlock_write_latch(&lock); { memcpy(©, &lock, sizeof(ck_swlock_t)); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } memcpy(&lock, ©, sizeof(ck_swlock_t)); } ck_swlock_write_unlatch(&lock); } ck_swlock_read_lock(&lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } ck_swlock_read_unlock(&lock); } return (NULL); } static void * thread(void *arg) { unsigned int i = ITERATE; unsigned int l; int tid = ck_pr_load_int(arg); if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { if (tid == 0) { /* Writer */ ck_swlock_write_lock(&lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } ck_swlock_write_unlock(&lock); } ck_swlock_read_lock(&lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } ck_swlock_read_unlock(&lock); } return (NULL); } static void swlock_test(pthread_t *threads, void *(*f)(void *), const char *test) { int i, tid[nthr]; fprintf(stderr, "Creating threads (%s)...", test); for (i = 0; i < nthr; i++) { ck_pr_store_int(&tid[i], i); if (pthread_create(&threads[i], NULL, f, &tid[i])) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return; } int main(int argc, char *argv[]) { pthread_t *threads; if (argc != 3) { ck_error("Usage: validate \n"); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } a.delta = atoi(argv[2]); swlock_test(threads, thread, "regular"); swlock_test(threads, thread_latch, "latch"); #ifdef CK_F_PR_RTM swlock_test(threads, thread_rtm, "rtm"); swlock_test(threads, thread_rtm_mix, "rtm-mix"); swlock_test(threads, thread_rtm_adaptive, "rtm-adaptive"); #endif return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_tflock/benchmark/latency.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "../../common.h" #define CK_F_PR_RTM #ifndef STEPS #define STEPS 2000000 #endif int main(void) { uint64_t s_b, e_b, i; ck_tflock_ticket_t tflock = CK_TFLOCK_TICKET_INITIALIZER; for (i = 0; i < STEPS; i++) { ck_tflock_ticket_write_lock(&tflock); ck_tflock_ticket_write_unlock(&tflock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_tflock_ticket_write_lock(&tflock); ck_tflock_ticket_write_unlock(&tflock); } e_b = rdtsc(); printf(" WRITE: tflock %15" PRIu64 "\n", (e_b - s_b) / STEPS); for (i = 0; i < STEPS; i++) { ck_tflock_ticket_read_lock(&tflock); ck_tflock_ticket_read_unlock(&tflock); } s_b = rdtsc(); for (i = 0; i < STEPS; i++) { ck_tflock_ticket_read_lock(&tflock); ck_tflock_ticket_read_unlock(&tflock); } e_b = rdtsc(); printf(" READ: tflock %15" PRIu64 "\n", (e_b - s_b) / STEPS); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_tflock/benchmark/throughput.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "../../common.h" #ifndef STEPS #define STEPS 1000000 #endif static int barrier; static int threads; static unsigned int flag CK_CC_CACHELINE; static struct { ck_tflock_ticket_t lock; } rw CK_CC_CACHELINE = { .lock = CK_TFLOCK_TICKET_INITIALIZER }; static struct affinity affinity; static void * thread_lock(void *pun) { uint64_t s_b, e_b, a, i; uint64_t *value = pun; if (aff_iterate(&affinity) != 0) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads) ck_pr_stall(); for (i = 1, a = 0;; i++) { s_b = rdtsc(); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); ck_tflock_ticket_read_lock(&rw.lock); ck_tflock_ticket_read_unlock(&rw.lock); e_b = rdtsc(); a += (e_b - s_b) >> 4; if (ck_pr_load_uint(&flag) == 1) break; } ck_pr_inc_int(&barrier); while (ck_pr_load_int(&barrier) != threads * 2) ck_pr_stall(); *value = (a / i); return NULL; } static void tflock_test(pthread_t *p, int d, uint64_t *latency, void *(*f)(void *), const char *label) { int t; ck_pr_store_int(&barrier, 0); ck_pr_store_uint(&flag, 0); affinity.delta = d; affinity.request = 0; fprintf(stderr, "Creating threads (%s)...", label); for (t = 0; t < threads; t++) { if (pthread_create(&p[t], NULL, f, latency + t) != 0) { ck_error("ERROR: Could not create thread %d\n", t); } } fprintf(stderr, "done\n"); common_sleep(10); ck_pr_store_uint(&flag, 1); fprintf(stderr, "Waiting for threads to finish acquisition regression..."); for (t = 0; t < threads; t++) pthread_join(p[t], NULL); fprintf(stderr, "done\n\n"); for (t = 1; t <= threads; t++) printf("%10u %20" PRIu64 "\n", t, latency[t - 1]); fprintf(stderr, "\n"); return; } int main(int argc, char *argv[]) { int d; pthread_t *p; uint64_t *latency; if (argc != 3) { ck_error("Usage: throughput \n"); } threads = atoi(argv[2]); if (threads <= 0) { ck_error("ERROR: Threads must be a value > 0.\n"); } p = malloc(sizeof(pthread_t) * threads); if (p == NULL) { ck_error("ERROR: Failed to initialize thread.\n"); } latency = malloc(sizeof(uint64_t) * threads); if (latency == NULL) { ck_error("ERROR: Failed to create latency buffer.\n"); } d = atoi(argv[1]); tflock_test(p, d, latency, thread_lock, "tflock"); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/ck_tflock/validate/validate.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../common.h" #ifndef ITERATE #define ITERATE 1000000 #endif static struct affinity a; static unsigned int locked; static int nthr; static ck_tflock_ticket_t lock = CK_TFLOCK_TICKET_INITIALIZER; static void * thread(void *null CK_CC_UNUSED) { unsigned int i = ITERATE; unsigned int l; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } while (i--) { ck_tflock_ticket_write_lock(&lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); ck_pr_inc_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 8) { ck_error("ERROR [WR:%d]: %u != 2\n", __LINE__, l); } ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); ck_pr_dec_uint(&locked); l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [WR:%d]: %u != 0\n", __LINE__, l); } } ck_tflock_ticket_write_unlock(&lock); ck_tflock_ticket_read_lock(&lock); { l = ck_pr_load_uint(&locked); if (l != 0) { ck_error("ERROR [RD:%d]: %u != 0\n", __LINE__, l); } } ck_tflock_ticket_read_unlock(&lock); } return (NULL); } static void tflock_ticket_test(pthread_t *threads, void *(*f)(void *), const char *test) { int i; fprintf(stderr, "Creating threads (%s)...", test); for (i = 0; i < nthr; i++) { if (pthread_create(&threads[i], NULL, f, NULL)) { ck_error("ERROR: Could not create thread %d\n", i); } } fprintf(stderr, "."); for (i = 0; i < nthr; i++) pthread_join(threads[i], NULL); fprintf(stderr, "done (passed)\n"); return; } int main(int argc, char *argv[]) { pthread_t *threads; if (argc != 3) { ck_error("Usage: validate \n"); } nthr = atoi(argv[1]); if (nthr <= 0) { ck_error("ERROR: Number of threads must be greater than 0\n"); } threads = malloc(sizeof(pthread_t) * nthr); if (threads == NULL) { ck_error("ERROR: Could not allocate thread structures\n"); } a.delta = atoi(argv[2]); tflock_ticket_test(threads, thread, "regular"); ck_tflock_ticket_init(&lock); return 0; } ================================================ FILE: third_party/concurrency_kit/ck/regressions/common.h ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_COMMON_H #define CK_COMMON_H #include #include #include #include #include #include #ifdef __linux__ #include #include #include #elif defined(__MACH__) #include #include #elif defined(__FreeBSD__) #include #include #endif #if defined(_WIN32) #include #define NOMINMAX #include #define DELTA_EPOCH 11644473600000000ULL #else #include #include #endif #ifndef CORES #define CORES 8 #endif CK_CC_INLINE static void common_srand(unsigned int i) { #ifdef _WIN32 srand(i); #else srandom(i); #endif } CK_CC_INLINE static int common_rand(void) { #ifdef _WIN32 return rand(); #else return random(); #endif } CK_CC_INLINE static int common_rand_r(unsigned int *i) { #ifdef _WIN32 (void)i; /* * When linked with -mthreads, rand() is thread-safe. * rand_s is also an option. */ return rand(); #else return rand_r(i); #endif } CK_CC_INLINE static void common_srand48(long int i) { #ifdef _WIN32 srand(i); #else srand48(i); #endif } CK_CC_INLINE static long int common_lrand48(void) { #ifdef _WIN32 return rand(); #else return lrand48(); #endif } CK_CC_INLINE static double common_drand48(void) { #ifdef _WIN32 return (double)rand()/RAND_MAX; #else return drand48(); #endif } CK_CC_INLINE static void common_sleep(unsigned int n) { #ifdef _WIN32 Sleep(n * 1000); #else sleep(n); #endif } CK_CC_INLINE static int common_gettimeofday(struct timeval *tv, void *tz) { #ifdef _WIN32 FILETIME ft; uint64_t tmp_time = 0; static bool tzflag = false; struct timezone *tzp = tz; if (tv != NULL) { GetSystemTimeAsFileTime(&ft); tmp_time |= ft.dwHighDateTime; tmp_time <<= 32; tmp_time |= ft.dwLowDateTime; /* GetSystemTimeAsFileTime returns 100 nanosecond intervals. */ tmp_time /= 10; /* Windows' epoch starts on 01/01/1601, while Unix' starts on 01/01/1970. */ tmp_time -= DELTA_EPOCH; tv->tv_sec = (long)(tmp_time / 1000000UL); tv->tv_usec = (long)(tmp_time % 1000000UL); } if (tz != NULL) { if (tzflag == false) { _tzset(); tzflag = true; } tzp->tz_minuteswest = _timezone / 60; tzp->tz_dsttime = _daylight; } return 0; #else return gettimeofday(tv, tz); #endif } CK_CC_UNUSED static unsigned int common_alarm(void (*sig_handler)(int), void *alarm_event, unsigned int duration) { #ifdef _WIN32 (void)sig_handler; (void)duration; bool success; HANDLE *alarm_handle = alarm_event; success = SetEvent(*alarm_handle); assert(success != false); return 0; #else (void)alarm_event; signal(SIGALRM, sig_handler); return alarm(duration); #endif } #ifdef _WIN32 #ifndef SECOND_TIMER #define SECOND_TIMER 10000000 #endif #define COMMON_ALARM_DECLARE_GLOBAL(prefix, alarm_event_name, flag_name) \ static HANDLE prefix##_common_win_alarm_timer; \ static HANDLE alarm_event_name; \ static LARGE_INTEGER prefix##_common_alarm_timer_length; \ \ static void CALLBACK \ prefix##_common_win_alarm_handler(LPVOID arg, DWORD timer_low_value, DWORD timer_high_value) \ { \ (void)arg; \ (void)timer_low_value; \ (void)timer_high_value; \ flag_name = true; \ return; \ } \ \ static void * \ prefix##_common_win_alarm(void *unused) \ { \ (void)unused; \ bool timer_success = false; \ for (;;) { \ WaitForSingleObjectEx(alarm_event_name, INFINITE, true); \ timer_success = SetWaitableTimer(prefix##_common_win_alarm_timer, \ &prefix##_common_alarm_timer_length, \ 0, \ prefix##_common_win_alarm_handler, NULL, false); \ assert(timer_success != false); \ WaitForSingleObjectEx(prefix##_common_win_alarm_timer, INFINITE, true); \ } \ \ return NULL; \ } #define COMMON_ALARM_DECLARE_LOCAL(prefix, alarm_event_name) \ int64_t prefix##_common_alarm_tl; \ pthread_t prefix##_common_win_alarm_thread; #define COMMON_ALARM_INIT(prefix, alarm_event_name, duration) \ prefix##_common_alarm_tl = -1 * (duration) * SECOND_TIMER; \ prefix##_common_alarm_timer_length.LowPart = \ (DWORD) (prefix##_common_alarm_tl & 0xFFFFFFFF); \ prefix##_common_alarm_timer_length.HighPart = \ (LONG) (prefix##_common_alarm_tl >> 32); \ alarm_event_name = CreateEvent(NULL, false, false, NULL); \ assert(alarm_event_name != NULL); \ prefix##_common_win_alarm_timer = CreateWaitableTimer(NULL, true, NULL); \ assert(prefix##_common_win_alarm_timer != NULL); \ if (pthread_create(&prefix##_common_win_alarm_thread, \ NULL, \ prefix##_common_win_alarm, \ NULL) != 0) \ ck_error("ERROR: Failed to create common_win_alarm thread.\n"); #else #define COMMON_ALARM_DECLARE_GLOBAL(prefix, alarm_event_name, flag_name) #define COMMON_ALARM_DECLARE_LOCAL(prefix, alarm_event_name) \ int alarm_event_name = 0; #define COMMON_ALARM_INIT(prefix, alarm_event_name, duration) #endif struct affinity { unsigned int delta; unsigned int request; }; #define AFFINITY_INITIALIZER {0, 0} #ifdef __linux__ #ifndef gettid static pid_t gettid(void) { return syscall(__NR_gettid); } #endif /* gettid */ CK_CC_UNUSED static int aff_iterate(struct affinity *acb) { cpu_set_t s; unsigned int c; c = ck_pr_faa_uint(&acb->request, acb->delta); CPU_ZERO(&s); CPU_SET(c % CORES, &s); return sched_setaffinity(gettid(), sizeof(s), &s); } CK_CC_UNUSED static int aff_iterate_core(struct affinity *acb, unsigned int *core) { cpu_set_t s; *core = ck_pr_faa_uint(&acb->request, acb->delta); CPU_ZERO(&s); CPU_SET((*core) % CORES, &s); return sched_setaffinity(gettid(), sizeof(s), &s); } #elif defined(__MACH__) CK_CC_UNUSED static int aff_iterate(struct affinity *acb) { thread_affinity_policy_data_t policy; unsigned int c; c = ck_pr_faa_uint(&acb->request, acb->delta) % CORES; policy.affinity_tag = c; return thread_policy_set(mach_thread_self(), THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, THREAD_AFFINITY_POLICY_COUNT); } CK_CC_UNUSED static int aff_iterate_core(struct affinity *acb, unsigned int *core) { thread_affinity_policy_data_t policy; *core = ck_pr_faa_uint(&acb->request, acb->delta) % CORES; policy.affinity_tag = *core; return thread_policy_set(mach_thread_self(), THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, THREAD_AFFINITY_POLICY_COUNT); } #elif defined(__FreeBSD__) CK_CC_UNUSED static int aff_iterate(struct affinity *acb CK_CC_UNUSED) { unsigned int c; cpuset_t mask; c = ck_pr_faa_uint(&acb->request, acb->delta) % CORES; CPU_ZERO(&mask); CPU_SET(c, &mask); return (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask), &mask)); } CK_CC_UNUSED static int aff_iterate_core(struct affinity *acb CK_CC_UNUSED, unsigned int *core) { cpuset_t mask; *core = ck_pr_faa_uint(&acb->request, acb->delta) % CORES; CPU_ZERO(&mask); CPU_SET(*core, &mask); return (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask), &mask)); } #else CK_CC_UNUSED static int aff_iterate(struct affinity *acb CK_CC_UNUSED) { return (0); } CK_CC_UNUSED static int aff_iterate_core(struct affinity *acb CK_CC_UNUSED, unsigned int *core) { *core = 0; return (0); } #endif CK_CC_INLINE static uint64_t rdtsc(void) { #if defined(__x86_64__) uint32_t eax = 0, edx; #if defined(CK_MD_RDTSCP) __asm__ __volatile__("rdtscp" : "+a" (eax), "=d" (edx) : : "%ecx", "memory"); return (((uint64_t)edx << 32) | eax); #else __asm__ __volatile__("cpuid;" "rdtsc;" : "+a" (eax), "=d" (edx) : : "%ebx", "%ecx", "memory"); __asm__ __volatile__("xorl %%eax, %%eax;" "cpuid;" : : : "%eax", "%ebx", "%ecx", "%edx", "memory"); return (((uint64_t)edx << 32) | eax); #endif /* !CK_MD_RDTSCP */ #elif defined(__x86__) uint32_t eax = 0, edx; #if defined(CK_MD_RDTSCP) __asm__ __volatile__("rdtscp" : "+a" (eax), "=d" (edx) : : "%ecx", "memory"); return (((uint64_t)edx << 32) | eax); #else __asm__ __volatile__("pushl %%ebx;" "cpuid;" "rdtsc;" : "+a" (eax), "=d" (edx) : : "%ecx", "memory"); __asm__ __volatile__("xorl %%eax, %%eax;" "cpuid;" "popl %%ebx;" : : : "%eax", "%ecx", "%edx", "memory"); return (((uint64_t)edx << 32) | eax); #endif /* !CK_MD_RDTSCP */ #elif defined(__sparcv9__) uint64_t r; __asm__ __volatile__("rd %%tick, %0" : "=r" (r) : : "memory"); return r; #elif defined(__ppc64__) uint32_t high, low, snapshot; do { __asm__ __volatile__("isync;" "mftbu %0;" "mftb %1;" "mftbu %2;" : "=r" (high), "=r" (low), "=r" (snapshot) : : "memory"); } while (snapshot != high); return (((uint64_t)high << 32) | low); #elif defined(__aarch64__) uint64_t r; __asm __volatile__ ("mrs %0, cntvct_el0" : "=r" (r) : : "memory"); return r; #else return 0; #endif } CK_CC_USED static void ck_error(const char *message, ...) { va_list ap; va_start(ap, message); vfprintf(stderr, message, ap); va_end(ap); exit(EXIT_FAILURE); } #define ck_test(A, B, ...) do { \ if (A) \ ck_error(B, ##__VA_ARGS__); \ } while (0) #endif /* CK_COMMON_H */ ================================================ FILE: third_party/concurrency_kit/ck/src/ck_array.c ================================================ /* * Copyright 2013-2015 Samy Al Bahra * Copyright 2013-2014 AppNexus, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include static struct _ck_array * ck_array_create(struct ck_malloc *allocator, unsigned int length) { struct _ck_array *active; active = allocator->malloc(sizeof(struct _ck_array) + sizeof(void *) * length); if (active == NULL) return NULL; active->n_committed = 0; active->length = length; return active; } bool ck_array_init(struct ck_array *array, unsigned int mode, struct ck_malloc *allocator, unsigned int length) { struct _ck_array *active; (void)mode; if (allocator->realloc == NULL || allocator->malloc == NULL || allocator->free == NULL || length == 0) return false; active = ck_array_create(allocator, length); if (active == NULL) return false; array->n_entries = 0; array->allocator = allocator; array->active = active; array->transaction = NULL; return true; } bool ck_array_put(struct ck_array *array, void *value) { struct _ck_array *target; unsigned int size; /* * If no transaction copy has been necessary, attempt to do in-place * modification of the array. */ if (array->transaction == NULL) { target = array->active; if (array->n_entries == target->length) { size = target->length << 1; target = array->allocator->realloc(target, sizeof(struct _ck_array) + sizeof(void *) * array->n_entries, sizeof(struct _ck_array) + sizeof(void *) * size, true); if (target == NULL) return false; ck_pr_store_uint(&target->length, size); /* Serialize with respect to contents. */ ck_pr_fence_store(); ck_pr_store_ptr(&array->active, target); } target->values[array->n_entries++] = value; return true; } target = array->transaction; if (array->n_entries == target->length) { size = target->length << 1; target = array->allocator->realloc(target, sizeof(struct _ck_array) + sizeof(void *) * array->n_entries, sizeof(struct _ck_array) + sizeof(void *) * size, true); if (target == NULL) return false; target->length = size; array->transaction = target; } target->values[array->n_entries++] = value; return false; } int ck_array_put_unique(struct ck_array *array, void *value) { unsigned int i, limit; void **v; limit = array->n_entries; if (array->transaction != NULL) { v = array->transaction->values; } else { v = array->active->values; } for (i = 0; i < limit; i++) { if (v[i] == value) return 1; } return -!ck_array_put(array, value); } bool ck_array_remove(struct ck_array *array, void *value) { struct _ck_array *target; unsigned int i; if (array->transaction != NULL) { target = array->transaction; for (i = 0; i < array->n_entries; i++) { if (target->values[i] == value) { target->values[i] = target->values[--array->n_entries]; return true; } } return false; } target = array->active; for (i = 0; i < array->n_entries; i++) { if (target->values[i] == value) break; } if (i == array->n_entries) return false; /* If there are pending additions, immediately eliminate the operation. */ if (target->n_committed != array->n_entries) { ck_pr_store_ptr(&target->values[i], target->values[--array->n_entries]); return true; } /* * The assumption is that these allocations are small to begin with. * If there is no immediate opportunity for transaction, allocate a * transactional array which will be applied upon commit time. */ target = ck_array_create(array->allocator, array->n_entries); if (target == NULL) return false; memcpy(target->values, array->active->values, sizeof(void *) * array->n_entries); target->length = array->n_entries; target->n_committed = array->n_entries; target->values[i] = target->values[--array->n_entries]; array->transaction = target; return true; } bool ck_array_commit(ck_array_t *array) { struct _ck_array *m = array->transaction; if (m != NULL) { struct _ck_array *p; m->n_committed = array->n_entries; ck_pr_fence_store(); p = array->active; ck_pr_store_ptr(&array->active, m); array->allocator->free(p, sizeof(struct _ck_array) + p->length * sizeof(void *), true); array->transaction = NULL; return true; } ck_pr_fence_store(); ck_pr_store_uint(&array->active->n_committed, array->n_entries); return true; } void ck_array_deinit(struct ck_array *array, bool defer) { array->allocator->free(array->active, sizeof(struct _ck_array) + sizeof(void *) * array->active->length, defer); if (array->transaction != NULL) { array->allocator->free(array->transaction, sizeof(struct _ck_array) + sizeof(void *) * array->transaction->length, defer); } array->transaction = array->active = NULL; return; } ================================================ FILE: third_party/concurrency_kit/ck/src/ck_barrier_centralized.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include void ck_barrier_centralized(struct ck_barrier_centralized *barrier, struct ck_barrier_centralized_state *state, unsigned int n_threads) { unsigned int sense, value; /* * Every execution context has a sense associated with it. * This sense is reversed when the barrier is entered. Every * thread will spin on the global sense until the last thread * reverses it. */ sense = state->sense = ~state->sense; value = ck_pr_faa_uint(&barrier->value, 1); if (value == n_threads - 1) { ck_pr_store_uint(&barrier->value, 0); ck_pr_fence_memory(); ck_pr_store_uint(&barrier->sense, sense); return; } ck_pr_fence_atomic_load(); while (sense != ck_pr_load_uint(&barrier->sense)) ck_pr_stall(); ck_pr_fence_acquire(); return; } ================================================ FILE: third_party/concurrency_kit/ck/src/ck_barrier_combining.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include struct ck_barrier_combining_queue { struct ck_barrier_combining_group *head; struct ck_barrier_combining_group *tail; }; CK_CC_INLINE static struct ck_barrier_combining_group * ck_barrier_combining_queue_dequeue(struct ck_barrier_combining_queue *queue) { struct ck_barrier_combining_group *front = NULL; if (queue->head != NULL) { front = queue->head; queue->head = queue->head->next; } return front; } CK_CC_INLINE static void ck_barrier_combining_insert(struct ck_barrier_combining_group *parent, struct ck_barrier_combining_group *tnode, struct ck_barrier_combining_group **child) { *child = tnode; tnode->parent = parent; /* * After inserting, we must increment the parent group's count for * number of threads expected to reach it; otherwise, the * barrier may end prematurely. */ parent->k++; return; } /* * This implementation of software combining tree barriers * uses level order traversal to insert new thread groups * into the barrier's tree. We use a queue to implement this * traversal. */ CK_CC_INLINE static void ck_barrier_combining_queue_enqueue(struct ck_barrier_combining_queue *queue, struct ck_barrier_combining_group *node_value) { node_value->next = NULL; if (queue->head == NULL) { queue->head = queue->tail = node_value; return; } queue->tail->next = node_value; queue->tail = node_value; return; } void ck_barrier_combining_group_init(struct ck_barrier_combining *root, struct ck_barrier_combining_group *tnode, unsigned int nthr) { struct ck_barrier_combining_group *node; struct ck_barrier_combining_queue queue; queue.head = queue.tail = NULL; tnode->k = nthr; tnode->count = 0; tnode->sense = 0; tnode->left = tnode->right = NULL; /* * Finds the first available node for linkage into the combining * tree. The use of a spinlock is excusable as this is a one-time * initialization cost. */ ck_spinlock_fas_lock(&root->mutex); ck_barrier_combining_queue_enqueue(&queue, root->root); while (queue.head != NULL) { node = ck_barrier_combining_queue_dequeue(&queue); /* If the left child is free, link the group there. */ if (node->left == NULL) { ck_barrier_combining_insert(node, tnode, &node->left); goto leave; } /* If the right child is free, link the group there. */ if (node->right == NULL) { ck_barrier_combining_insert(node, tnode, &node->right); goto leave; } /* * If unsuccessful, try inserting as a child of the children of the * current node. */ ck_barrier_combining_queue_enqueue(&queue, node->left); ck_barrier_combining_queue_enqueue(&queue, node->right); } leave: ck_spinlock_fas_unlock(&root->mutex); return; } void ck_barrier_combining_init(struct ck_barrier_combining *root, struct ck_barrier_combining_group *init_root) { init_root->k = 0; init_root->count = 0; init_root->sense = 0; init_root->parent = init_root->left = init_root->right = NULL; ck_spinlock_fas_init(&root->mutex); root->root = init_root; return; } static void ck_barrier_combining_aux(struct ck_barrier_combining *barrier, struct ck_barrier_combining_group *tnode, unsigned int sense) { /* * If this is the last thread in the group, it moves on to the parent group. * Otherwise, it spins on this group's sense. */ if (ck_pr_faa_uint(&tnode->count, 1) == tnode->k - 1) { /* * If we are and will be the last thread entering the barrier for the * current group then signal the parent group if one exists. */ if (tnode->parent != NULL) ck_barrier_combining_aux(barrier, tnode->parent, sense); /* * Once the thread returns from its parent(s), it reinitializes the group's * arrival count and signals other threads to continue by flipping the group * sense. Order of these operations is not important since we assume a static * number of threads are members of a barrier for the lifetime of the barrier. * Since count is explicitly reinitialized, it is guaranteed that at any point * tnode->count is equivalent to tnode->k if and only if that many threads * are at the barrier. */ ck_pr_store_uint(&tnode->count, 0); ck_pr_fence_store(); ck_pr_store_uint(&tnode->sense, ~tnode->sense); } else { ck_pr_fence_memory(); while (sense != ck_pr_load_uint(&tnode->sense)) ck_pr_stall(); } return; } void ck_barrier_combining(struct ck_barrier_combining *barrier, struct ck_barrier_combining_group *tnode, struct ck_barrier_combining_state *state) { ck_barrier_combining_aux(barrier, tnode, state->sense); /* Reverse the execution context's sense for the next barrier. */ state->sense = ~state->sense; return; } ================================================ FILE: third_party/concurrency_kit/ck/src/ck_barrier_dissemination.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "ck_internal.h" void ck_barrier_dissemination_init(struct ck_barrier_dissemination *barrier, struct ck_barrier_dissemination_flag **barrier_internal, unsigned int nthr) { unsigned int i, j, k, size, offset; bool p = nthr & (nthr - 1); barrier->nthr = nthr; barrier->size = size = ck_internal_log(ck_internal_power_2(nthr)); ck_pr_store_uint(&barrier->tid, 0); for (i = 0; i < nthr; ++i) { barrier[i].flags[0] = barrier_internal[i]; barrier[i].flags[1] = barrier_internal[i] + size; } for (i = 0; i < nthr; ++i) { for (k = 0, offset = 1; k < size; ++k, offset <<= 1) { /* * Determine the thread's partner, j, for the current round, k. * Partners are chosen such that by the completion of the barrier, * every thread has been directly (having one of its flag set) or * indirectly (having one of its partners's flags set) signaled * by every other thread in the barrier. */ if (p == false) j = (i + offset) & (nthr - 1); else j = (i + offset) % nthr; /* Set the thread's partner for round k. */ barrier[i].flags[0][k].pflag = &barrier[j].flags[0][k].tflag; barrier[i].flags[1][k].pflag = &barrier[j].flags[1][k].tflag; /* Set the thread's flags to false. */ barrier[i].flags[0][k].tflag = barrier[i].flags[1][k].tflag = 0; } } return; } void ck_barrier_dissemination_subscribe(struct ck_barrier_dissemination *barrier, struct ck_barrier_dissemination_state *state) { state->parity = 0; state->sense = ~0; state->tid = ck_pr_faa_uint(&barrier->tid, 1); return; } unsigned int ck_barrier_dissemination_size(unsigned int nthr) { return (ck_internal_log(ck_internal_power_2(nthr)) << 1); } void ck_barrier_dissemination(struct ck_barrier_dissemination *barrier, struct ck_barrier_dissemination_state *state) { unsigned int i; unsigned int size = barrier->size; for (i = 0; i < size; ++i) { unsigned int *pflag, *tflag; pflag = barrier[state->tid].flags[state->parity][i].pflag; tflag = &barrier[state->tid].flags[state->parity][i].tflag; /* Unblock current partner. */ ck_pr_store_uint(pflag, state->sense); /* Wait until some other thread unblocks this one. */ while (ck_pr_load_uint(tflag) != state->sense) ck_pr_stall(); } /* * Dissemination barriers use two sets of flags to prevent race conditions * between successive calls to the barrier. Parity indicates which set will * be used for the next barrier. They also use a sense reversal technique * to avoid re-initialization of the flags for every two calls to the barrier. */ if (state->parity == 1) state->sense = ~state->sense; state->parity = 1 - state->parity; ck_pr_fence_acquire(); return; } ================================================ FILE: third_party/concurrency_kit/ck/src/ck_barrier_mcs.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include void ck_barrier_mcs_init(struct ck_barrier_mcs *barrier, unsigned int nthr) { unsigned int i, j; ck_pr_store_uint(&barrier->tid, 0); for (i = 0; i < nthr; ++i) { for (j = 0; j < 4; ++j) { /* * If there are still threads that don't have parents, * add it as a child. */ barrier[i].havechild[j] = ((i << 2) + j < nthr - 1) ? ~0 : 0; /* * childnotready is initialized to havechild to ensure * a thread does not wait for a child that does not exist. */ barrier[i].childnotready[j] = barrier[i].havechild[j]; } /* The root thread does not have a parent. */ barrier[i].parent = (i == 0) ? &barrier[i].dummy : &barrier[(i - 1) >> 2].childnotready[(i - 1) & 3]; /* Leaf threads do not have any children. */ barrier[i].children[0] = ((i << 1) + 1 >= nthr) ? &barrier[i].dummy : &barrier[(i << 1) + 1].parentsense; barrier[i].children[1] = ((i << 1) + 2 >= nthr) ? &barrier[i].dummy : &barrier[(i << 1) + 2].parentsense; barrier[i].parentsense = 0; } return; } void ck_barrier_mcs_subscribe(struct ck_barrier_mcs *barrier, struct ck_barrier_mcs_state *state) { state->sense = ~0; state->vpid = ck_pr_faa_uint(&barrier->tid, 1); return; } CK_CC_INLINE static bool ck_barrier_mcs_check_children(unsigned int *childnotready) { if (ck_pr_load_uint(&childnotready[0]) != 0) return false; if (ck_pr_load_uint(&childnotready[1]) != 0) return false; if (ck_pr_load_uint(&childnotready[2]) != 0) return false; if (ck_pr_load_uint(&childnotready[3]) != 0) return false; return true; } CK_CC_INLINE static void ck_barrier_mcs_reinitialize_children(struct ck_barrier_mcs *node) { ck_pr_store_uint(&node->childnotready[0], node->havechild[0]); ck_pr_store_uint(&node->childnotready[1], node->havechild[1]); ck_pr_store_uint(&node->childnotready[2], node->havechild[2]); ck_pr_store_uint(&node->childnotready[3], node->havechild[3]); return; } void ck_barrier_mcs(struct ck_barrier_mcs *barrier, struct ck_barrier_mcs_state *state) { /* * Wait until all children have reached the barrier and are done waiting * for their children. */ while (ck_barrier_mcs_check_children(barrier[state->vpid].childnotready) == false) ck_pr_stall(); /* Reinitialize for next barrier. */ ck_barrier_mcs_reinitialize_children(&barrier[state->vpid]); /* Inform parent thread and its children have arrived at the barrier. */ ck_pr_store_uint(barrier[state->vpid].parent, 0); /* Wait until parent indicates all threads have arrived at the barrier. */ if (state->vpid != 0) { while (ck_pr_load_uint(&barrier[state->vpid].parentsense) != state->sense) ck_pr_stall(); } /* Inform children of successful barrier. */ ck_pr_store_uint(barrier[state->vpid].children[0], state->sense); ck_pr_store_uint(barrier[state->vpid].children[1], state->sense); state->sense = ~state->sense; ck_pr_fence_memory(); return; } ================================================ FILE: third_party/concurrency_kit/ck/src/ck_barrier_tournament.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "ck_internal.h" /* * This is a tournament barrier implementation. Threads are statically * assigned roles to perform for each round of the barrier. Winners * move on to the next round, while losers spin in their current rounds * on their own flags. During the last round, the champion of the tournament * sets the last flag that begins the wakeup process. */ enum { CK_BARRIER_TOURNAMENT_BYE, CK_BARRIER_TOURNAMENT_CHAMPION, CK_BARRIER_TOURNAMENT_DROPOUT, CK_BARRIER_TOURNAMENT_LOSER, CK_BARRIER_TOURNAMENT_WINNER }; void ck_barrier_tournament_subscribe(struct ck_barrier_tournament *barrier, struct ck_barrier_tournament_state *state) { state->sense = ~0; state->vpid = ck_pr_faa_uint(&barrier->tid, 1); return; } void ck_barrier_tournament_init(struct ck_barrier_tournament *barrier, struct ck_barrier_tournament_round **rounds, unsigned int nthr) { unsigned int i, k, size, twok, twokm1, imod2k; ck_pr_store_uint(&barrier->tid, 0); barrier->size = size = ck_barrier_tournament_size(nthr); for (i = 0; i < nthr; ++i) { /* The first role is always CK_BARRIER_TOURNAMENT_DROPOUT. */ rounds[i][0].flag = 0; rounds[i][0].role = CK_BARRIER_TOURNAMENT_DROPOUT; for (k = 1, twok = 2, twokm1 = 1; k < size; ++k, twokm1 = twok, twok <<= 1) { rounds[i][k].flag = 0; imod2k = i & (twok - 1); if (imod2k == 0) { if ((i + twokm1 < nthr) && (twok < nthr)) rounds[i][k].role = CK_BARRIER_TOURNAMENT_WINNER; else if (i + twokm1 >= nthr) rounds[i][k].role = CK_BARRIER_TOURNAMENT_BYE; } if (imod2k == twokm1) rounds[i][k].role = CK_BARRIER_TOURNAMENT_LOSER; else if ((i == 0) && (twok >= nthr)) rounds[i][k].role = CK_BARRIER_TOURNAMENT_CHAMPION; if (rounds[i][k].role == CK_BARRIER_TOURNAMENT_LOSER) rounds[i][k].opponent = &rounds[i - twokm1][k].flag; else if (rounds[i][k].role == CK_BARRIER_TOURNAMENT_WINNER || rounds[i][k].role == CK_BARRIER_TOURNAMENT_CHAMPION) rounds[i][k].opponent = &rounds[i + twokm1][k].flag; } } ck_pr_store_ptr(&barrier->rounds, rounds); return; } unsigned int ck_barrier_tournament_size(unsigned int nthr) { return (ck_internal_log(ck_internal_power_2(nthr)) + 1); } void ck_barrier_tournament(struct ck_barrier_tournament *barrier, struct ck_barrier_tournament_state *state) { struct ck_barrier_tournament_round **rounds = ck_pr_load_ptr(&barrier->rounds); int round = 1; if (barrier->size == 1) return; for (;; ++round) { switch (rounds[state->vpid][round].role) { case CK_BARRIER_TOURNAMENT_BYE: break; case CK_BARRIER_TOURNAMENT_CHAMPION: /* * The CK_BARRIER_TOURNAMENT_CHAMPION waits until it wins the tournament; it then * sets the final flag before the wakeup phase of the barrier. */ while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense) ck_pr_stall(); ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense); goto wakeup; case CK_BARRIER_TOURNAMENT_DROPOUT: /* NOTREACHED */ break; case CK_BARRIER_TOURNAMENT_LOSER: /* * CK_BARRIER_TOURNAMENT_LOSERs set the flags of their opponents and wait until * their opponents release them after the tournament is over. */ ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense); while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense) ck_pr_stall(); goto wakeup; case CK_BARRIER_TOURNAMENT_WINNER: /* * CK_BARRIER_TOURNAMENT_WINNERs wait until their current opponent sets their flag; they then * continue to the next round of the tournament. */ while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense) ck_pr_stall(); break; } } wakeup: for (round -= 1 ;; --round) { switch (rounds[state->vpid][round].role) { case CK_BARRIER_TOURNAMENT_BYE: break; case CK_BARRIER_TOURNAMENT_CHAMPION: /* NOTREACHED */ break; case CK_BARRIER_TOURNAMENT_DROPOUT: goto leave; break; case CK_BARRIER_TOURNAMENT_LOSER: /* NOTREACHED */ break; case CK_BARRIER_TOURNAMENT_WINNER: /* * Winners inform their old opponents the tournament is over * by setting their flags. */ ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense); break; } } leave: ck_pr_fence_memory(); state->sense = ~state->sense; return; } ================================================ FILE: third_party/concurrency_kit/ck/src/ck_epoch.c ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * The implementation here is inspired from the work described in: * Fraser, K. 2004. Practical Lock-Freedom. PhD Thesis, University * of Cambridge Computing Laboratory. */ #include #include #include #include #include #include #include /* * Only three distinct values are used for reclamation, but reclamation occurs * at e+2 rather than e+1. Any thread in a "critical section" would have * acquired some snapshot (e) of the global epoch value (e_g) and set an active * flag. Any hazardous references will only occur after a full memory barrier. * For example, assume an initial e_g value of 1, e value of 0 and active value * of 0. * * ck_epoch_begin(...) * e = e_g * active = 1 * memory_barrier(); * * Any serialized reads may observe e = 0 or e = 1 with active = 0, or e = 0 or * e = 1 with active = 1. The e_g value can only go from 1 to 2 if every thread * has already observed the value of "1" (or the value we are incrementing * from). This guarantees us that for any given value e_g, any threads with-in * critical sections (referred to as "active" threads from here on) would have * an e value of e_g-1 or e_g. This also means that hazardous references may be * shared in both e_g-1 and e_g even if they are logically deleted in e_g. * * For example, assume all threads have an e value of e_g. Another thread may * increment to e_g to e_g+1. Older threads may have a reference to an object * which is only deleted in e_g+1. It could be that reader threads are * executing some hash table look-ups, while some other writer thread (which * causes epoch counter tick) actually deletes the same items that reader * threads are looking up (this writer thread having an e value of e_g+1). * This is possible if the writer thread re-observes the epoch after the * counter tick. * * Psuedo-code for writer: * ck_epoch_begin() * ht_delete(x) * ck_epoch_end() * ck_epoch_begin() * ht_delete(x) * ck_epoch_end() * * Psuedo-code for reader: * for (;;) { * x = ht_lookup(x) * ck_pr_inc(&x->value); * } * * Of course, it is also possible for references logically deleted at e_g-1 to * still be accessed at e_g as threads are "active" at the same time * (real-world time) mutating shared objects. * * Now, if the epoch counter is ticked to e_g+1, then no new hazardous * references could exist to objects logically deleted at e_g-1. The reason for * this is that at e_g+1, all epoch read-side critical sections started at * e_g-1 must have been completed. If any epoch read-side critical sections at * e_g-1 were still active, then we would never increment to e_g+1 (active != 0 * ^ e != e_g). Additionally, e_g may still have hazardous references to * objects logically deleted at e_g-1 which means objects logically deleted at * e_g-1 cannot be deleted at e_g+1 unless all threads have observed e_g+1 * (since it is valid for active threads to be at e_g and threads at e_g still * require safe memory accesses). * * However, at e_g+2, all active threads must be either at e_g+1 or e_g+2. * Though e_g+2 may share hazardous references with e_g+1, and e_g+1 shares * hazardous references to e_g, no active threads are at e_g or e_g-1. This * means no hazardous references could exist to objects deleted at e_g-1 (at * e_g+2). * * To summarize these important points, * 1) Active threads will always have a value of e_g or e_g-1. * 2) Items that are logically deleted e_g or e_g-1 cannot be physically * deleted. * 3) Objects logically deleted at e_g-1 can be physically destroyed at e_g+2 * or at e_g+1 if no threads are at e_g. * * Last but not least, if we are at e_g+2, then no active thread is at e_g * which means it is safe to apply modulo-3 arithmetic to e_g value in order to * re-use e_g to represent the e_g+3 state. This means it is sufficient to * represent e_g using only the values 0, 1 or 2. Every time a thread re-visits * a e_g (which can be determined with a non-empty deferral list) it can assume * objects in the e_g deferral list involved at least three e_g transitions and * are thus, safe, for physical deletion. * * Blocking semantics for epoch reclamation have additional restrictions. * Though we only require three deferral lists, reasonable blocking semantics * must be able to more gracefully handle bursty write work-loads which could * easily cause e_g wrap-around if modulo-3 arithmetic is used. This allows for * easy-to-trigger live-lock situations. The work-around to this is to not * apply modulo arithmetic to e_g but only to deferral list indexing. */ #define CK_EPOCH_GRACE 3U enum { CK_EPOCH_STATE_USED = 0, CK_EPOCH_STATE_FREE = 1 }; CK_STACK_CONTAINER(struct ck_epoch_record, record_next, ck_epoch_record_container) CK_STACK_CONTAINER(struct ck_epoch_entry, stack_entry, ck_epoch_entry_container) #define CK_EPOCH_SENSE_MASK (CK_EPOCH_SENSE - 1) bool _ck_epoch_delref(struct ck_epoch_record *record, struct ck_epoch_section *section) { struct ck_epoch_ref *current, *other; unsigned int i = section->bucket; current = &record->local.bucket[i]; current->count--; if (current->count > 0) return false; /* * If the current bucket no longer has any references, then * determine whether we have already transitioned into a newer * epoch. If so, then make sure to update our shared snapshot * to allow for forward progress. * * If no other active bucket exists, then the record will go * inactive in order to allow for forward progress. */ other = &record->local.bucket[(i + 1) & CK_EPOCH_SENSE_MASK]; if (other->count > 0 && ((int)(current->epoch - other->epoch) < 0)) { /* * The other epoch value is actually the newest, * transition to it. */ ck_pr_store_uint(&record->epoch, other->epoch); } return true; } void _ck_epoch_addref(struct ck_epoch_record *record, struct ck_epoch_section *section) { struct ck_epoch *global = record->global; struct ck_epoch_ref *ref; unsigned int epoch, i; epoch = ck_pr_load_uint(&global->epoch); i = epoch & CK_EPOCH_SENSE_MASK; ref = &record->local.bucket[i]; if (ref->count++ == 0) { #ifndef CK_MD_TSO struct ck_epoch_ref *previous; /* * The system has already ticked. If another non-zero bucket * exists, make sure to order our observations with respect * to it. Otherwise, it is possible to acquire a reference * from the previous epoch generation. * * On TSO architectures, the monoticity of the global counter * and load-{store, load} ordering are sufficient to guarantee * this ordering. */ previous = &record->local.bucket[(i + 1) & CK_EPOCH_SENSE_MASK]; if (previous->count > 0) ck_pr_fence_acqrel(); #endif /* !CK_MD_TSO */ /* * If this is this is a new reference into the current * bucket then cache the associated epoch value. */ ref->epoch = epoch; } section->bucket = i; return; } void ck_epoch_init(struct ck_epoch *global) { ck_stack_init(&global->records); global->epoch = 1; global->n_free = 0; ck_pr_fence_store(); return; } struct ck_epoch_record * ck_epoch_recycle(struct ck_epoch *global, void *ct) { struct ck_epoch_record *record; ck_stack_entry_t *cursor; unsigned int state; if (ck_pr_load_uint(&global->n_free) == 0) return NULL; CK_STACK_FOREACH(&global->records, cursor) { record = ck_epoch_record_container(cursor); if (ck_pr_load_uint(&record->state) == CK_EPOCH_STATE_FREE) { /* Serialize with respect to deferral list clean-up. */ ck_pr_fence_load(); state = ck_pr_fas_uint(&record->state, CK_EPOCH_STATE_USED); if (state == CK_EPOCH_STATE_FREE) { ck_pr_dec_uint(&global->n_free); ck_pr_store_ptr(&record->ct, ct); /* * The context pointer is ordered by a * subsequent protected section. */ return record; } } } return NULL; } void ck_epoch_register(struct ck_epoch *global, struct ck_epoch_record *record, void *ct) { size_t i; record->global = global; record->state = CK_EPOCH_STATE_USED; record->active = 0; record->epoch = 0; record->n_dispatch = 0; record->n_peak = 0; record->n_pending = 0; record->ct = ct; memset(&record->local, 0, sizeof record->local); for (i = 0; i < CK_EPOCH_LENGTH; i++) ck_stack_init(&record->pending[i]); ck_pr_fence_store(); ck_stack_push_upmc(&global->records, &record->record_next); return; } void ck_epoch_unregister(struct ck_epoch_record *record) { struct ck_epoch *global = record->global; size_t i; record->active = 0; record->epoch = 0; record->n_dispatch = 0; record->n_peak = 0; record->n_pending = 0; memset(&record->local, 0, sizeof record->local); for (i = 0; i < CK_EPOCH_LENGTH; i++) ck_stack_init(&record->pending[i]); ck_pr_store_ptr(&record->ct, NULL); ck_pr_fence_store(); ck_pr_store_uint(&record->state, CK_EPOCH_STATE_FREE); ck_pr_inc_uint(&global->n_free); return; } static struct ck_epoch_record * ck_epoch_scan(struct ck_epoch *global, struct ck_epoch_record *cr, unsigned int epoch, bool *af) { ck_stack_entry_t *cursor; if (cr == NULL) { cursor = CK_STACK_FIRST(&global->records); *af = false; } else { cursor = &cr->record_next; *af = true; } while (cursor != NULL) { unsigned int state, active; cr = ck_epoch_record_container(cursor); state = ck_pr_load_uint(&cr->state); if (state & CK_EPOCH_STATE_FREE) { cursor = CK_STACK_NEXT(cursor); continue; } active = ck_pr_load_uint(&cr->active); *af |= active; if (active != 0 && ck_pr_load_uint(&cr->epoch) != epoch) return cr; cursor = CK_STACK_NEXT(cursor); } return NULL; } static void ck_epoch_dispatch(struct ck_epoch_record *record, unsigned int e) { unsigned int epoch = e & (CK_EPOCH_LENGTH - 1); ck_stack_entry_t *head, *next, *cursor; unsigned int n_pending, n_peak; unsigned int i = 0; head = ck_stack_batch_pop_upmc(&record->pending[epoch]); for (cursor = head; cursor != NULL; cursor = next) { struct ck_epoch_entry *entry = ck_epoch_entry_container(cursor); next = CK_STACK_NEXT(cursor); entry->function(entry); i++; } n_peak = ck_pr_load_uint(&record->n_peak); n_pending = ck_pr_load_uint(&record->n_pending); /* We don't require accuracy around peak calculation. */ if (n_pending > n_peak) ck_pr_store_uint(&record->n_peak, n_peak); if (i > 0) { ck_pr_add_uint(&record->n_dispatch, i); ck_pr_sub_uint(&record->n_pending, i); } return; } /* * Reclaim all objects associated with a record. */ void ck_epoch_reclaim(struct ck_epoch_record *record) { unsigned int epoch; for (epoch = 0; epoch < CK_EPOCH_LENGTH; epoch++) ck_epoch_dispatch(record, epoch); return; } CK_CC_FORCE_INLINE static void epoch_block(struct ck_epoch *global, struct ck_epoch_record *cr, ck_epoch_wait_cb_t *cb, void *ct) { if (cb != NULL) cb(global, cr, ct); return; } /* * This function must not be called with-in read section. */ void ck_epoch_synchronize_wait(struct ck_epoch *global, ck_epoch_wait_cb_t *cb, void *ct) { struct ck_epoch_record *cr; unsigned int delta, epoch, goal, i; bool active; ck_pr_fence_memory(); /* * The observation of the global epoch must be ordered with respect to * all prior operations. The re-ordering of loads is permitted given * monoticity of global epoch counter. * * If UINT_MAX concurrent mutations were to occur then it is possible * to encounter an ABA-issue. If this is a concern, consider tuning * write-side concurrency. */ delta = epoch = ck_pr_load_uint(&global->epoch); goal = epoch + CK_EPOCH_GRACE; for (i = 0, cr = NULL; i < CK_EPOCH_GRACE - 1; cr = NULL, i++) { bool r; /* * Determine whether all threads have observed the current * epoch with respect to the updates on invocation. */ while (cr = ck_epoch_scan(global, cr, delta, &active), cr != NULL) { unsigned int e_d; ck_pr_stall(); /* * Another writer may have already observed a grace * period. */ e_d = ck_pr_load_uint(&global->epoch); if (e_d == delta) { epoch_block(global, cr, cb, ct); continue; } /* * If the epoch has been updated, we may have already * met our goal. */ delta = e_d; if ((goal > epoch) & (delta >= goal)) goto leave; epoch_block(global, cr, cb, ct); /* * If the epoch has been updated, then a grace period * requires that all threads are observed idle at the * same epoch. */ cr = NULL; } /* * If we have observed all threads as inactive, then we assume * we are at a grace period. */ if (active == false) break; /* * Increment current epoch. CAS semantics are used to eliminate * increment operations for synchronization that occurs for the * same global epoch value snapshot. * * If we can guarantee there will only be one active barrier or * epoch tick at a given time, then it is sufficient to use an * increment operation. In a multi-barrier workload, however, * it is possible to overflow the epoch value if we apply * modulo-3 arithmetic. */ r = ck_pr_cas_uint_value(&global->epoch, delta, delta + 1, &delta); /* Order subsequent thread active checks. */ ck_pr_fence_atomic_load(); /* * If CAS has succeeded, then set delta to latest snapshot. * Otherwise, we have just acquired latest snapshot. */ delta = delta + r; } /* * A majority of use-cases will not require full barrier semantics. * However, if non-temporal instructions are used, full barrier * semantics are necessary. */ leave: ck_pr_fence_memory(); return; } void ck_epoch_synchronize(struct ck_epoch_record *record) { ck_epoch_synchronize_wait(record->global, NULL, NULL); return; } void ck_epoch_barrier(struct ck_epoch_record *record) { ck_epoch_synchronize(record); ck_epoch_reclaim(record); return; } void ck_epoch_barrier_wait(struct ck_epoch_record *record, ck_epoch_wait_cb_t *cb, void *ct) { ck_epoch_synchronize_wait(record->global, cb, ct); ck_epoch_reclaim(record); return; } /* * It may be worth it to actually apply these deferral semantics to an epoch * that was observed at ck_epoch_call time. The problem is that the latter * would require a full fence. * * ck_epoch_call will dispatch to the latest epoch snapshot that was observed. * There are cases where it will fail to reclaim as early as it could. If this * becomes a problem, we could actually use a heap for epoch buckets but that * is far from ideal too. */ bool ck_epoch_poll(struct ck_epoch_record *record) { bool active; unsigned int epoch; struct ck_epoch_record *cr = NULL; struct ck_epoch *global = record->global; epoch = ck_pr_load_uint(&global->epoch); /* Serialize epoch snapshots with respect to global epoch. */ ck_pr_fence_memory(); cr = ck_epoch_scan(global, cr, epoch, &active); if (cr != NULL) { record->epoch = epoch; return false; } /* We are at a grace period if all threads are inactive. */ if (active == false) { record->epoch = epoch; for (epoch = 0; epoch < CK_EPOCH_LENGTH; epoch++) ck_epoch_dispatch(record, epoch); return true; } /* If an active thread exists, rely on epoch observation. */ (void)ck_pr_cas_uint(&global->epoch, epoch, epoch + 1); ck_epoch_dispatch(record, epoch + 1); return true; } ================================================ FILE: third_party/concurrency_kit/ck/src/ck_hp.c ================================================ /* * Copyright 2010-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * (c) Copyright 2008, IBM Corporation. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * This is an implementation of hazard pointers as detailed in: * http://www.research.ibm.com/people/m/michael/ieeetpds-2004.pdf * * This API provides a publishing mechanism that defers destruction of * hazard pointers until it is safe to do so. Preventing arbitrary re-use * protects against the ABA problem and provides safe memory reclamation. * The implementation was derived from the Hazard Pointers implementation * from the Amino CBBS project. It has been heavily modified for Concurrency * Kit. */ #include #include #include #include #include #include #include #include #include CK_STACK_CONTAINER(struct ck_hp_record, global_entry, ck_hp_record_container) CK_STACK_CONTAINER(struct ck_hp_hazard, pending_entry, ck_hp_hazard_container) void ck_hp_init(struct ck_hp *state, unsigned int degree, unsigned int threshold, ck_hp_destructor_t destroy) { state->threshold = threshold; state->degree = degree; state->destroy = destroy; state->n_subscribers = 0; state->n_free = 0; ck_stack_init(&state->subscribers); ck_pr_fence_store(); return; } void ck_hp_set_threshold(struct ck_hp *state, unsigned int threshold) { ck_pr_store_uint(&state->threshold, threshold); return; } struct ck_hp_record * ck_hp_recycle(struct ck_hp *global) { struct ck_hp_record *record; ck_stack_entry_t *entry; int state; if (ck_pr_load_uint(&global->n_free) == 0) return NULL; CK_STACK_FOREACH(&global->subscribers, entry) { record = ck_hp_record_container(entry); if (ck_pr_load_int(&record->state) == CK_HP_FREE) { ck_pr_fence_load(); state = ck_pr_fas_int(&record->state, CK_HP_USED); if (state == CK_HP_FREE) { ck_pr_dec_uint(&global->n_free); return record; } } } return NULL; } void ck_hp_unregister(struct ck_hp_record *entry) { entry->n_pending = 0; entry->n_peak = 0; entry->n_reclamations = 0; ck_stack_init(&entry->pending); ck_pr_fence_store(); ck_pr_store_int(&entry->state, CK_HP_FREE); ck_pr_inc_uint(&entry->global->n_free); return; } void ck_hp_register(struct ck_hp *state, struct ck_hp_record *entry, void **pointers) { entry->state = CK_HP_USED; entry->global = state; entry->pointers = pointers; entry->n_pending = 0; entry->n_peak = 0; entry->n_reclamations = 0; memset(pointers, 0, state->degree * sizeof(void *)); ck_stack_init(&entry->pending); ck_pr_fence_store(); ck_stack_push_upmc(&state->subscribers, &entry->global_entry); ck_pr_inc_uint(&state->n_subscribers); return; } static int hazard_compare(const void *a, const void *b) { void * const *x; void * const *y; x = a; y = b; return ((*x > *y) - (*x < *y)); } CK_CC_INLINE static bool ck_hp_member_scan(ck_stack_entry_t *entry, unsigned int degree, void *pointer) { struct ck_hp_record *record; unsigned int i; void *hazard; do { record = ck_hp_record_container(entry); if (ck_pr_load_int(&record->state) == CK_HP_FREE) continue; if (ck_pr_load_ptr(&record->pointers) == NULL) continue; for (i = 0; i < degree; i++) { hazard = ck_pr_load_ptr(&record->pointers[i]); if (hazard == pointer) return (true); } } while ((entry = CK_STACK_NEXT(entry)) != NULL); return (false); } CK_CC_INLINE static void * ck_hp_member_cache(struct ck_hp *global, void **cache, unsigned int *n_hazards) { struct ck_hp_record *record; ck_stack_entry_t *entry; unsigned int hazards = 0; unsigned int i; void *pointer; CK_STACK_FOREACH(&global->subscribers, entry) { record = ck_hp_record_container(entry); if (ck_pr_load_int(&record->state) == CK_HP_FREE) continue; if (ck_pr_load_ptr(&record->pointers) == NULL) continue; for (i = 0; i < global->degree; i++) { if (hazards > CK_HP_CACHE) break; pointer = ck_pr_load_ptr(&record->pointers[i]); if (pointer != NULL) cache[hazards++] = pointer; } } *n_hazards = hazards; return (entry); } void ck_hp_reclaim(struct ck_hp_record *thread) { struct ck_hp_hazard *hazard; struct ck_hp *global = thread->global; unsigned int n_hazards; void **cache, *marker, *match; ck_stack_entry_t *previous, *entry, *next; /* Store as many entries as possible in local array. */ cache = thread->cache; marker = ck_hp_member_cache(global, cache, &n_hazards); /* * In theory, there is an n such that (n * (log n) ** 2) < np. */ qsort(cache, n_hazards, sizeof(void *), hazard_compare); previous = NULL; CK_STACK_FOREACH_SAFE(&thread->pending, entry, next) { hazard = ck_hp_hazard_container(entry); match = bsearch(&hazard->pointer, cache, n_hazards, sizeof(void *), hazard_compare); if (match != NULL) { previous = entry; continue; } if (marker != NULL && ck_hp_member_scan(marker, global->degree, hazard->pointer)) { previous = entry; continue; } thread->n_pending -= 1; /* Remove from the pending stack. */ if (previous) CK_STACK_NEXT(previous) = CK_STACK_NEXT(entry); else CK_STACK_FIRST(&thread->pending) = CK_STACK_NEXT(entry); /* The entry is now safe to destroy. */ global->destroy(hazard->data); thread->n_reclamations++; } return; } void ck_hp_retire(struct ck_hp_record *thread, struct ck_hp_hazard *hazard, void *data, void *pointer) { ck_pr_store_ptr(&hazard->pointer, pointer); ck_pr_store_ptr(&hazard->data, data); ck_stack_push_spnc(&thread->pending, &hazard->pending_entry); thread->n_pending += 1; if (thread->n_pending > thread->n_peak) thread->n_peak = thread->n_pending; return; } void ck_hp_free(struct ck_hp_record *thread, struct ck_hp_hazard *hazard, void *data, void *pointer) { struct ck_hp *global; global = ck_pr_load_ptr(&thread->global); ck_pr_store_ptr(&hazard->data, data); ck_pr_store_ptr(&hazard->pointer, pointer); ck_stack_push_spnc(&thread->pending, &hazard->pending_entry); thread->n_pending += 1; if (thread->n_pending > thread->n_peak) thread->n_peak = thread->n_pending; if (thread->n_pending >= global->threshold) ck_hp_reclaim(thread); return; } void ck_hp_purge(struct ck_hp_record *thread) { ck_backoff_t backoff = CK_BACKOFF_INITIALIZER; while (thread->n_pending > 0) { ck_hp_reclaim(thread); if (thread->n_pending > 0) ck_backoff_eb(&backoff); } return; } ================================================ FILE: third_party/concurrency_kit/ck/src/ck_hs.c ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "ck_internal.h" #ifndef CK_HS_PROBE_L1_SHIFT #define CK_HS_PROBE_L1_SHIFT 3ULL #endif /* CK_HS_PROBE_L1_SHIFT */ #define CK_HS_PROBE_L1 (1 << CK_HS_PROBE_L1_SHIFT) #define CK_HS_PROBE_L1_MASK (CK_HS_PROBE_L1 - 1) #ifndef CK_HS_PROBE_L1_DEFAULT #define CK_HS_PROBE_L1_DEFAULT CK_MD_CACHELINE #endif #define CK_HS_VMA_MASK ((uintptr_t)((1ULL << CK_MD_VMA_BITS) - 1)) #define CK_HS_VMA(x) \ ((void *)((uintptr_t)(x) & CK_HS_VMA_MASK)) #define CK_HS_EMPTY NULL #define CK_HS_TOMBSTONE ((void *)~(uintptr_t)0) #define CK_HS_G (2) #define CK_HS_G_MASK (CK_HS_G - 1) #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_STORE_8) #define CK_HS_WORD uint8_t #define CK_HS_WORD_MAX UINT8_MAX #define CK_HS_STORE(x, y) ck_pr_store_8(x, y) #define CK_HS_LOAD(x) ck_pr_load_8(x) #elif defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_STORE_16) #define CK_HS_WORD uint16_t #define CK_HS_WORD_MAX UINT16_MAX #define CK_HS_STORE(x, y) ck_pr_store_16(x, y) #define CK_HS_LOAD(x) ck_pr_load_16(x) #elif defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_STORE_32) #define CK_HS_WORD uint32_t #define CK_HS_WORD_MAX UINT32_MAX #define CK_HS_STORE(x, y) ck_pr_store_32(x, y) #define CK_HS_LOAD(x) ck_pr_load_32(x) #else #error "ck_hs is not supported on your platform." #endif enum ck_hs_probe_behavior { CK_HS_PROBE = 0, /* Default behavior. */ CK_HS_PROBE_TOMBSTONE, /* Short-circuit on tombstone. */ CK_HS_PROBE_INSERT /* Short-circuit on probe bound if tombstone found. */ }; struct ck_hs_map { unsigned int generation[CK_HS_G]; unsigned int probe_maximum; unsigned long mask; unsigned long step; unsigned int probe_limit; unsigned int tombstones; unsigned long n_entries; unsigned long capacity; unsigned long size; CK_HS_WORD *probe_bound; const void **entries; }; static inline void ck_hs_map_signal(struct ck_hs_map *map, unsigned long h) { h &= CK_HS_G_MASK; ck_pr_store_uint(&map->generation[h], map->generation[h] + 1); ck_pr_fence_store(); return; } static bool _ck_hs_next(struct ck_hs *hs, struct ck_hs_map *map, struct ck_hs_iterator *i, void **key) { void *value; if (i->offset >= map->capacity) return false; do { value = CK_CC_DECONST_PTR(map->entries[i->offset]); if (value != CK_HS_EMPTY && value != CK_HS_TOMBSTONE) { #ifdef CK_HS_PP if (hs->mode & CK_HS_MODE_OBJECT) value = CK_HS_VMA(value); #else (void)hs; /* Avoid unused parameter warning. */ #endif i->offset++; *key = value; return true; } } while (++i->offset < map->capacity); return false; } void ck_hs_iterator_init(struct ck_hs_iterator *iterator) { iterator->cursor = NULL; iterator->offset = 0; iterator->map = NULL; return; } bool ck_hs_next(struct ck_hs *hs, struct ck_hs_iterator *i, void **key) { return _ck_hs_next(hs, hs->map, i, key); } bool ck_hs_next_spmc(struct ck_hs *hs, struct ck_hs_iterator *i, void **key) { struct ck_hs_map *m = i->map; if (m == NULL) { m = i->map = ck_pr_load_ptr(&hs->map); } return _ck_hs_next(hs, m, i, key); } void ck_hs_stat(struct ck_hs *hs, struct ck_hs_stat *st) { struct ck_hs_map *map = hs->map; st->n_entries = map->n_entries; st->tombstones = map->tombstones; st->probe_maximum = map->probe_maximum; return; } unsigned long ck_hs_count(struct ck_hs *hs) { return hs->map->n_entries; } static void ck_hs_map_destroy(struct ck_malloc *m, struct ck_hs_map *map, bool defer) { m->free(map, map->size, defer); return; } void ck_hs_destroy(struct ck_hs *hs) { ck_hs_map_destroy(hs->m, hs->map, false); return; } static struct ck_hs_map * ck_hs_map_create(struct ck_hs *hs, unsigned long entries) { struct ck_hs_map *map; unsigned long size, n_entries, prefix, limit; n_entries = ck_internal_power_2(entries); if (n_entries < CK_HS_PROBE_L1) n_entries = CK_HS_PROBE_L1; size = sizeof(struct ck_hs_map) + (sizeof(void *) * n_entries + CK_MD_CACHELINE - 1); if (hs->mode & CK_HS_MODE_DELETE) { prefix = sizeof(CK_HS_WORD) * n_entries; size += prefix; } else { prefix = 0; } map = hs->m->malloc(size); if (map == NULL) return NULL; map->size = size; /* We should probably use a more intelligent heuristic for default probe length. */ limit = ck_internal_max(n_entries >> (CK_HS_PROBE_L1_SHIFT + 2), CK_HS_PROBE_L1_DEFAULT); if (limit > UINT_MAX) limit = UINT_MAX; map->probe_limit = (unsigned int)limit; map->probe_maximum = 0; map->capacity = n_entries; map->step = ck_internal_bsf(n_entries); map->mask = n_entries - 1; map->n_entries = 0; /* Align map allocation to cache line. */ map->entries = (void *)(((uintptr_t)&map[1] + prefix + CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1)); memset(map->entries, 0, sizeof(void *) * n_entries); memset(map->generation, 0, sizeof map->generation); if (hs->mode & CK_HS_MODE_DELETE) { map->probe_bound = (CK_HS_WORD *)&map[1]; memset(map->probe_bound, 0, prefix); } else { map->probe_bound = NULL; } /* Commit entries purge with respect to map publication. */ ck_pr_fence_store(); return map; } bool ck_hs_reset_size(struct ck_hs *hs, unsigned long capacity) { struct ck_hs_map *map, *previous; previous = hs->map; map = ck_hs_map_create(hs, capacity); if (map == NULL) return false; ck_pr_store_ptr(&hs->map, map); ck_hs_map_destroy(hs->m, previous, true); return true; } bool ck_hs_reset(struct ck_hs *hs) { struct ck_hs_map *previous; previous = hs->map; return ck_hs_reset_size(hs, previous->capacity); } static inline unsigned long ck_hs_map_probe_next(struct ck_hs_map *map, unsigned long offset, unsigned long h, unsigned long level, unsigned long probes) { unsigned long r, stride; r = (h >> map->step) >> level; stride = (r & ~CK_HS_PROBE_L1_MASK) << 1 | (r & CK_HS_PROBE_L1_MASK); return (offset + (probes >> CK_HS_PROBE_L1_SHIFT) + (stride | CK_HS_PROBE_L1)) & map->mask; } static inline void ck_hs_map_bound_set(struct ck_hs_map *m, unsigned long h, unsigned long n_probes) { unsigned long offset = h & m->mask; if (n_probes > m->probe_maximum) ck_pr_store_uint(&m->probe_maximum, n_probes); if (m->probe_bound != NULL && m->probe_bound[offset] < n_probes) { if (n_probes > CK_HS_WORD_MAX) n_probes = CK_HS_WORD_MAX; CK_HS_STORE(&m->probe_bound[offset], n_probes); ck_pr_fence_store(); } return; } static inline unsigned int ck_hs_map_bound_get(struct ck_hs_map *m, unsigned long h) { unsigned long offset = h & m->mask; unsigned int r = CK_HS_WORD_MAX; if (m->probe_bound != NULL) { r = CK_HS_LOAD(&m->probe_bound[offset]); if (r == CK_HS_WORD_MAX) r = ck_pr_load_uint(&m->probe_maximum); } else { r = ck_pr_load_uint(&m->probe_maximum); } return r; } bool ck_hs_grow(struct ck_hs *hs, unsigned long capacity) { struct ck_hs_map *map, *update; unsigned long k, i, j, offset, probes; const void *previous, **bucket; restart: map = hs->map; if (map->capacity > capacity) return false; update = ck_hs_map_create(hs, capacity); if (update == NULL) return false; for (k = 0; k < map->capacity; k++) { unsigned long h; previous = map->entries[k]; if (previous == CK_HS_EMPTY || previous == CK_HS_TOMBSTONE) continue; #ifdef CK_HS_PP if (hs->mode & CK_HS_MODE_OBJECT) previous = CK_HS_VMA(previous); #endif h = hs->hf(previous, hs->seed); offset = h & update->mask; i = probes = 0; for (;;) { bucket = (const void **)((uintptr_t)&update->entries[offset] & ~(CK_MD_CACHELINE - 1)); for (j = 0; j < CK_HS_PROBE_L1; j++) { const void **cursor = bucket + ((j + offset) & (CK_HS_PROBE_L1 - 1)); if (probes++ == update->probe_limit) break; if (CK_CC_LIKELY(*cursor == CK_HS_EMPTY)) { *cursor = map->entries[k]; update->n_entries++; ck_hs_map_bound_set(update, h, probes); break; } } if (j < CK_HS_PROBE_L1) break; offset = ck_hs_map_probe_next(update, offset, h, i++, probes); } if (probes > update->probe_limit) { /* * We have hit the probe limit, map needs to be even larger. */ ck_hs_map_destroy(hs->m, update, false); capacity <<= 1; goto restart; } } ck_pr_fence_store(); ck_pr_store_ptr(&hs->map, update); ck_hs_map_destroy(hs->m, map, true); return true; } static void ck_hs_map_postinsert(struct ck_hs *hs, struct ck_hs_map *map) { map->n_entries++; if ((map->n_entries << 1) > map->capacity) ck_hs_grow(hs, map->capacity << 1); return; } bool ck_hs_rebuild(struct ck_hs *hs) { return ck_hs_grow(hs, hs->map->capacity); } static const void ** ck_hs_map_probe(struct ck_hs *hs, struct ck_hs_map *map, unsigned long *n_probes, const void ***priority, unsigned long h, const void *key, const void **object, unsigned long probe_limit, enum ck_hs_probe_behavior behavior) { const void **bucket, **cursor, *k, *compare; const void **pr = NULL; unsigned long offset, j, i, probes, opl; #ifdef CK_HS_PP /* If we are storing object pointers, then we may leverage pointer packing. */ unsigned long hv = 0; if (hs->mode & CK_HS_MODE_OBJECT) { hv = (h >> 25) & CK_HS_KEY_MASK; compare = CK_HS_VMA(key); } else { compare = key; } #else compare = key; #endif offset = h & map->mask; *object = NULL; i = probes = 0; opl = probe_limit; if (behavior == CK_HS_PROBE_INSERT) probe_limit = ck_hs_map_bound_get(map, h); for (;;) { bucket = (const void **)((uintptr_t)&map->entries[offset] & ~(CK_MD_CACHELINE - 1)); for (j = 0; j < CK_HS_PROBE_L1; j++) { cursor = bucket + ((j + offset) & (CK_HS_PROBE_L1 - 1)); if (probes++ == probe_limit) { if (probe_limit == opl || pr != NULL) { k = CK_HS_EMPTY; goto leave; } /* * If no eligible slot has been found yet, continue probe * sequence with original probe limit. */ probe_limit = opl; } k = ck_pr_load_ptr(cursor); if (k == CK_HS_EMPTY) goto leave; if (k == CK_HS_TOMBSTONE) { if (pr == NULL) { pr = cursor; *n_probes = probes; if (behavior == CK_HS_PROBE_TOMBSTONE) { k = CK_HS_EMPTY; goto leave; } } continue; } #ifdef CK_HS_PP if (hs->mode & CK_HS_MODE_OBJECT) { if (((uintptr_t)k >> CK_MD_VMA_BITS) != hv) continue; k = CK_HS_VMA(k); } #endif if (k == compare) goto leave; if (hs->compare == NULL) continue; if (hs->compare(k, key) == true) goto leave; } offset = ck_hs_map_probe_next(map, offset, h, i++, probes); } leave: if (probes > probe_limit) { cursor = NULL; } else { *object = k; } if (pr == NULL) *n_probes = probes; *priority = pr; return cursor; } static inline const void * ck_hs_marshal(unsigned int mode, const void *key, unsigned long h) { #ifdef CK_HS_PP const void *insert; if (mode & CK_HS_MODE_OBJECT) { insert = (void *)((uintptr_t)CK_HS_VMA(key) | ((h >> 25) << CK_MD_VMA_BITS)); } else { insert = key; } return insert; #else (void)mode; (void)h; return key; #endif } bool ck_hs_gc(struct ck_hs *hs, unsigned long cycles, unsigned long seed) { unsigned long size = 0; unsigned long i; struct ck_hs_map *map = hs->map; unsigned int maximum; CK_HS_WORD *bounds = NULL; if (map->n_entries == 0) { ck_pr_store_uint(&map->probe_maximum, 0); if (map->probe_bound != NULL) memset(map->probe_bound, 0, sizeof(CK_HS_WORD) * map->capacity); return true; } if (cycles == 0) { maximum = 0; if (map->probe_bound != NULL) { size = sizeof(CK_HS_WORD) * map->capacity; bounds = hs->m->malloc(size); if (bounds == NULL) return false; memset(bounds, 0, size); } } else { maximum = map->probe_maximum; } for (i = 0; i < map->capacity; i++) { const void **first, *object, **slot, *entry; unsigned long n_probes, offset, h; entry = map->entries[(i + seed) & map->mask]; if (entry == CK_HS_EMPTY || entry == CK_HS_TOMBSTONE) continue; #ifdef CK_HS_PP if (hs->mode & CK_HS_MODE_OBJECT) entry = CK_HS_VMA(entry); #endif h = hs->hf(entry, hs->seed); offset = h & map->mask; slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, entry, &object, ck_hs_map_bound_get(map, h), CK_HS_PROBE); if (first != NULL) { const void *insert = ck_hs_marshal(hs->mode, entry, h); ck_pr_store_ptr(first, insert); ck_hs_map_signal(map, h); ck_pr_store_ptr(slot, CK_HS_TOMBSTONE); } if (cycles == 0) { if (n_probes > maximum) maximum = n_probes; if (n_probes > CK_HS_WORD_MAX) n_probes = CK_HS_WORD_MAX; if (bounds != NULL && n_probes > bounds[offset]) bounds[offset] = n_probes; } else if (--cycles == 0) break; } /* * The following only apply to garbage collection involving * a full scan of all entries. */ if (maximum != map->probe_maximum) ck_pr_store_uint(&map->probe_maximum, maximum); if (bounds != NULL) { for (i = 0; i < map->capacity; i++) CK_HS_STORE(&map->probe_bound[i], bounds[i]); hs->m->free(bounds, size, false); } return true; } bool ck_hs_fas(struct ck_hs *hs, unsigned long h, const void *key, void **previous) { const void **slot, **first, *object, *insert; struct ck_hs_map *map = hs->map; unsigned long n_probes; *previous = NULL; slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object, ck_hs_map_bound_get(map, h), CK_HS_PROBE); /* Replacement semantics presume existence. */ if (object == NULL) return false; insert = ck_hs_marshal(hs->mode, key, h); if (first != NULL) { ck_pr_store_ptr(first, insert); ck_hs_map_signal(map, h); ck_pr_store_ptr(slot, CK_HS_TOMBSTONE); } else { ck_pr_store_ptr(slot, insert); } *previous = CK_CC_DECONST_PTR(object); return true; } /* * An apply function takes two arguments. The first argument is a pointer to a * pre-existing object. The second argument is a pointer to the fifth argument * passed to ck_hs_apply. If a non-NULL pointer is passed to the first argument * and the return value of the apply function is NULL, then the pre-existing * value is deleted. If the return pointer is the same as the one passed to the * apply function then no changes are made to the hash table. If the first * argument is non-NULL and the return pointer is different than that passed to * the apply function, then the pre-existing value is replaced. For * replacement, it is required that the value itself is identical to the * previous value. */ bool ck_hs_apply(struct ck_hs *hs, unsigned long h, const void *key, ck_hs_apply_fn_t *fn, void *cl) { const void **slot, **first, *object, *delta, *insert; unsigned long n_probes; struct ck_hs_map *map; restart: map = hs->map; slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_HS_PROBE_INSERT); if (slot == NULL && first == NULL) { if (ck_hs_grow(hs, map->capacity << 1) == false) return false; goto restart; } delta = fn(CK_CC_DECONST_PTR(object), cl); if (delta == NULL) { /* * The apply function has requested deletion. If the object doesn't exist, * then exit early. */ if (CK_CC_UNLIKELY(object == NULL)) return true; /* Otherwise, mark slot as deleted. */ ck_pr_store_ptr(slot, CK_HS_TOMBSTONE); map->n_entries--; map->tombstones++; return true; } /* The apply function has not requested hash set modification so exit early. */ if (delta == object) return true; /* A modification or insertion has been requested. */ ck_hs_map_bound_set(map, h, n_probes); insert = ck_hs_marshal(hs->mode, delta, h); if (first != NULL) { /* * This follows the same semantics as ck_hs_set, please refer to that * function for documentation. */ ck_pr_store_ptr(first, insert); if (object != NULL) { ck_hs_map_signal(map, h); ck_pr_store_ptr(slot, CK_HS_TOMBSTONE); } } else { /* * If we are storing into same slot, then atomic store is sufficient * for replacement. */ ck_pr_store_ptr(slot, insert); } if (object == NULL) ck_hs_map_postinsert(hs, map); return true; } bool ck_hs_set(struct ck_hs *hs, unsigned long h, const void *key, void **previous) { const void **slot, **first, *object, *insert; unsigned long n_probes; struct ck_hs_map *map; *previous = NULL; restart: map = hs->map; slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_HS_PROBE_INSERT); if (slot == NULL && first == NULL) { if (ck_hs_grow(hs, map->capacity << 1) == false) return false; goto restart; } ck_hs_map_bound_set(map, h, n_probes); insert = ck_hs_marshal(hs->mode, key, h); if (first != NULL) { /* If an earlier bucket was found, then store entry there. */ ck_pr_store_ptr(first, insert); /* * If a duplicate key was found, then delete it after * signaling concurrent probes to restart. Optionally, * it is possible to install tombstone after grace * period if we can guarantee earlier position of * duplicate key. */ if (object != NULL) { ck_hs_map_signal(map, h); ck_pr_store_ptr(slot, CK_HS_TOMBSTONE); } } else { /* * If we are storing into same slot, then atomic store is sufficient * for replacement. */ ck_pr_store_ptr(slot, insert); } if (object == NULL) ck_hs_map_postinsert(hs, map); *previous = CK_CC_DECONST_PTR(object); return true; } CK_CC_INLINE static bool ck_hs_put_internal(struct ck_hs *hs, unsigned long h, const void *key, enum ck_hs_probe_behavior behavior) { const void **slot, **first, *object, *insert; unsigned long n_probes; struct ck_hs_map *map; restart: map = hs->map; slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, behavior); if (slot == NULL && first == NULL) { if (ck_hs_grow(hs, map->capacity << 1) == false) return false; goto restart; } /* Fail operation if a match was found. */ if (object != NULL) return false; ck_hs_map_bound_set(map, h, n_probes); insert = ck_hs_marshal(hs->mode, key, h); if (first != NULL) { /* Insert key into first bucket in probe sequence. */ ck_pr_store_ptr(first, insert); } else { /* An empty slot was found. */ ck_pr_store_ptr(slot, insert); } ck_hs_map_postinsert(hs, map); return true; } bool ck_hs_put(struct ck_hs *hs, unsigned long h, const void *key) { return ck_hs_put_internal(hs, h, key, CK_HS_PROBE_INSERT); } bool ck_hs_put_unique(struct ck_hs *hs, unsigned long h, const void *key) { return ck_hs_put_internal(hs, h, key, CK_HS_PROBE_TOMBSTONE); } void * ck_hs_get(struct ck_hs *hs, unsigned long h, const void *key) { const void **first, *object; struct ck_hs_map *map; unsigned long n_probes; unsigned int g, g_p, probe; unsigned int *generation; do { map = ck_pr_load_ptr(&hs->map); generation = &map->generation[h & CK_HS_G_MASK]; g = ck_pr_load_uint(generation); probe = ck_hs_map_bound_get(map, h); ck_pr_fence_load(); ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object, probe, CK_HS_PROBE); ck_pr_fence_load(); g_p = ck_pr_load_uint(generation); } while (g != g_p); return CK_CC_DECONST_PTR(object); } void * ck_hs_remove(struct ck_hs *hs, unsigned long h, const void *key) { const void **slot, **first, *object; struct ck_hs_map *map = hs->map; unsigned long n_probes; slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object, ck_hs_map_bound_get(map, h), CK_HS_PROBE); if (object == NULL) return NULL; ck_pr_store_ptr(slot, CK_HS_TOMBSTONE); map->n_entries--; map->tombstones++; return CK_CC_DECONST_PTR(object); } bool ck_hs_move(struct ck_hs *hs, struct ck_hs *source, ck_hs_hash_cb_t *hf, ck_hs_compare_cb_t *compare, struct ck_malloc *m) { if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL) return false; hs->mode = source->mode; hs->seed = source->seed; hs->map = source->map; hs->m = m; hs->hf = hf; hs->compare = compare; return true; } bool ck_hs_init(struct ck_hs *hs, unsigned int mode, ck_hs_hash_cb_t *hf, ck_hs_compare_cb_t *compare, struct ck_malloc *m, unsigned long n_entries, unsigned long seed) { if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL) return false; hs->m = m; hs->mode = mode; hs->seed = seed; hs->hf = hf; hs->compare = compare; hs->map = ck_hs_map_create(hs, n_entries); return hs->map != NULL; } ================================================ FILE: third_party/concurrency_kit/ck/src/ck_ht.c ================================================ /* * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define CK_HT_IM #include /* * This implementation borrows several techniques from Josh Dybnis's * nbds library which can be found at http://code.google.com/p/nbds * * This release currently only includes support for 64-bit platforms. * We can address 32-bit platforms in a future release. */ #include #include #include #include #include #include #include "ck_ht_hash.h" #include "ck_internal.h" #ifndef CK_HT_BUCKET_LENGTH #ifdef CK_HT_PP #define CK_HT_BUCKET_SHIFT 2ULL #else #define CK_HT_BUCKET_SHIFT 1ULL #endif #define CK_HT_BUCKET_LENGTH (1U << CK_HT_BUCKET_SHIFT) #define CK_HT_BUCKET_MASK (CK_HT_BUCKET_LENGTH - 1) #endif #ifndef CK_HT_PROBE_DEFAULT #define CK_HT_PROBE_DEFAULT 64ULL #endif #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_STORE_8) #define CK_HT_WORD uint8_t #define CK_HT_WORD_MAX UINT8_MAX #define CK_HT_STORE(x, y) ck_pr_store_8(x, y) #define CK_HT_LOAD(x) ck_pr_load_8(x) #elif defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_STORE_16) #define CK_HT_WORD uint16_t #define CK_HT_WORD_MAX UINT16_MAX #define CK_HT_STORE(x, y) ck_pr_store_16(x, y) #define CK_HT_LOAD(x) ck_pr_load_16(x) #elif defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_STORE_32) #define CK_HT_WORD uint32_t #define CK_HT_WORD_MAX UINT32_MAX #define CK_HT_STORE(x, y) ck_pr_store_32(x, y) #define CK_HT_LOAD(x) ck_pr_load_32(x) #else #error "ck_ht is not supported on your platform." #endif struct ck_ht_map { unsigned int mode; CK_HT_TYPE deletions; CK_HT_TYPE probe_maximum; CK_HT_TYPE probe_length; CK_HT_TYPE probe_limit; CK_HT_TYPE size; CK_HT_TYPE n_entries; CK_HT_TYPE mask; CK_HT_TYPE capacity; CK_HT_TYPE step; CK_HT_WORD *probe_bound; struct ck_ht_entry *entries; }; void ck_ht_stat(struct ck_ht *table, struct ck_ht_stat *st) { struct ck_ht_map *map = table->map; st->n_entries = map->n_entries; st->probe_maximum = map->probe_maximum; return; } void ck_ht_hash(struct ck_ht_hash *h, struct ck_ht *table, const void *key, uint16_t key_length) { table->h(h, key, key_length, table->seed); return; } void ck_ht_hash_direct(struct ck_ht_hash *h, struct ck_ht *table, uintptr_t key) { ck_ht_hash(h, table, &key, sizeof(key)); return; } static void ck_ht_hash_wrapper(struct ck_ht_hash *h, const void *key, size_t length, uint64_t seed) { h->value = (unsigned long)MurmurHash64A(key, length, seed); return; } static struct ck_ht_map * ck_ht_map_create(struct ck_ht *table, CK_HT_TYPE entries) { struct ck_ht_map *map; CK_HT_TYPE size; uintptr_t prefix; uint32_t n_entries; n_entries = ck_internal_power_2(entries); if (n_entries < CK_HT_BUCKET_LENGTH) n_entries = CK_HT_BUCKET_LENGTH; size = sizeof(struct ck_ht_map) + (sizeof(struct ck_ht_entry) * n_entries + CK_MD_CACHELINE - 1); if (table->mode & CK_HT_WORKLOAD_DELETE) { prefix = sizeof(CK_HT_WORD) * n_entries; size += prefix; } else { prefix = 0; } map = table->m->malloc(size); if (map == NULL) return NULL; map->mode = table->mode; map->size = size; map->probe_limit = ck_internal_max_64(n_entries >> (CK_HT_BUCKET_SHIFT + 2), CK_HT_PROBE_DEFAULT); map->deletions = 0; map->probe_maximum = 0; map->capacity = n_entries; map->step = ck_internal_bsf_64(map->capacity); map->mask = map->capacity - 1; map->n_entries = 0; map->entries = (struct ck_ht_entry *)(((uintptr_t)&map[1] + prefix + CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1)); if (table->mode & CK_HT_WORKLOAD_DELETE) { map->probe_bound = (CK_HT_WORD *)&map[1]; memset(map->probe_bound, 0, prefix); } else { map->probe_bound = NULL; } memset(map->entries, 0, sizeof(struct ck_ht_entry) * n_entries); ck_pr_fence_store(); return map; } static inline void ck_ht_map_bound_set(struct ck_ht_map *m, struct ck_ht_hash h, CK_HT_TYPE n_probes) { CK_HT_TYPE offset = h.value & m->mask; if (n_probes > m->probe_maximum) CK_HT_TYPE_STORE(&m->probe_maximum, n_probes); if (m->probe_bound != NULL && m->probe_bound[offset] < n_probes) { if (n_probes >= CK_HT_WORD_MAX) n_probes = CK_HT_WORD_MAX; CK_HT_STORE(&m->probe_bound[offset], n_probes); ck_pr_fence_store(); } return; } static inline CK_HT_TYPE ck_ht_map_bound_get(struct ck_ht_map *m, struct ck_ht_hash h) { CK_HT_TYPE offset = h.value & m->mask; CK_HT_TYPE r = CK_HT_WORD_MAX; if (m->probe_bound != NULL) { r = CK_HT_LOAD(&m->probe_bound[offset]); if (r == CK_HT_WORD_MAX) r = CK_HT_TYPE_LOAD(&m->probe_maximum); } else { r = CK_HT_TYPE_LOAD(&m->probe_maximum); } return r; } static void ck_ht_map_destroy(struct ck_malloc *m, struct ck_ht_map *map, bool defer) { m->free(map, map->size, defer); return; } static inline size_t ck_ht_map_probe_next(struct ck_ht_map *map, size_t offset, ck_ht_hash_t h, size_t probes) { ck_ht_hash_t r; size_t stride; unsigned long level = (unsigned long)probes >> CK_HT_BUCKET_SHIFT; r.value = (h.value >> map->step) >> level; stride = (r.value & ~CK_HT_BUCKET_MASK) << 1 | (r.value & CK_HT_BUCKET_MASK); return (offset + level + (stride | CK_HT_BUCKET_LENGTH)) & map->mask; } bool ck_ht_init(struct ck_ht *table, unsigned int mode, ck_ht_hash_cb_t *h, struct ck_malloc *m, CK_HT_TYPE entries, uint64_t seed) { if (m == NULL || m->malloc == NULL || m->free == NULL) return false; table->m = m; table->mode = mode; table->seed = seed; if (h == NULL) { table->h = ck_ht_hash_wrapper; } else { table->h = h; } table->map = ck_ht_map_create(table, entries); return table->map != NULL; } static struct ck_ht_entry * ck_ht_map_probe_wr(struct ck_ht_map *map, ck_ht_hash_t h, ck_ht_entry_t *snapshot, ck_ht_entry_t **available, const void *key, uint16_t key_length, CK_HT_TYPE *probe_limit, CK_HT_TYPE *probe_wr) { struct ck_ht_entry *bucket, *cursor; struct ck_ht_entry *first = NULL; size_t offset, i, j; CK_HT_TYPE probes = 0; CK_HT_TYPE limit; if (probe_limit == NULL) { limit = ck_ht_map_bound_get(map, h); } else { limit = CK_HT_TYPE_MAX; } offset = h.value & map->mask; for (i = 0; i < map->probe_limit; i++) { /* * Probe on a complete cache line first. Scan forward and wrap around to * the beginning of the cache line. Only when the complete cache line has * been scanned do we move on to the next row. */ bucket = (void *)((uintptr_t)(map->entries + offset) & ~(CK_MD_CACHELINE - 1)); for (j = 0; j < CK_HT_BUCKET_LENGTH; j++) { uint16_t k; if (probes++ > limit) break; cursor = bucket + ((j + offset) & (CK_HT_BUCKET_LENGTH - 1)); /* * It is probably worth it to encapsulate probe state * in order to prevent a complete reprobe sequence in * the case of intermittent writers. */ if (cursor->key == CK_HT_KEY_TOMBSTONE) { if (first == NULL) { first = cursor; *probe_wr = probes; } continue; } if (cursor->key == CK_HT_KEY_EMPTY) goto leave; if (cursor->key == (uintptr_t)key) goto leave; if (map->mode & CK_HT_MODE_BYTESTRING) { void *pointer; /* * Check memoized portion of hash value before * expensive full-length comparison. */ k = ck_ht_entry_key_length(cursor); if (k != key_length) continue; #ifdef CK_HT_PP if ((cursor->value >> CK_MD_VMA_BITS) != ((h.value >> 32) & CK_HT_KEY_MASK)) continue; #else if (cursor->hash != h.value) continue; #endif pointer = ck_ht_entry_key(cursor); if (memcmp(pointer, key, key_length) == 0) goto leave; } } offset = ck_ht_map_probe_next(map, offset, h, probes); } cursor = NULL; leave: if (probe_limit != NULL) { *probe_limit = probes; } else if (first == NULL) { *probe_wr = probes; } *available = first; if (cursor != NULL) { *snapshot = *cursor; } return cursor; } bool ck_ht_gc(struct ck_ht *ht, unsigned long cycles, unsigned long seed) { CK_HT_WORD *bounds = NULL; struct ck_ht_map *map = ht->map; CK_HT_TYPE maximum, i; CK_HT_TYPE size = 0; if (map->n_entries == 0) { CK_HT_TYPE_STORE(&map->probe_maximum, 0); if (map->probe_bound != NULL) memset(map->probe_bound, 0, sizeof(CK_HT_WORD) * map->capacity); return true; } if (cycles == 0) { maximum = 0; if (map->probe_bound != NULL) { size = sizeof(CK_HT_WORD) * map->capacity; bounds = ht->m->malloc(size); if (bounds == NULL) return false; memset(bounds, 0, size); } } else { maximum = map->probe_maximum; } for (i = 0; i < map->capacity; i++) { struct ck_ht_entry *entry, *priority, snapshot; struct ck_ht_hash h; CK_HT_TYPE probes_wr; CK_HT_TYPE offset; entry = &map->entries[(i + seed) & map->mask]; if (entry->key == CK_HT_KEY_EMPTY || entry->key == CK_HT_KEY_TOMBSTONE) { continue; } if (ht->mode & CK_HT_MODE_BYTESTRING) { #ifndef CK_HT_PP h.value = entry->hash; #else ht->h(&h, ck_ht_entry_key(entry), ck_ht_entry_key_length(entry), ht->seed); #endif entry = ck_ht_map_probe_wr(map, h, &snapshot, &priority, ck_ht_entry_key(entry), ck_ht_entry_key_length(entry), NULL, &probes_wr); } else { #ifndef CK_HT_PP h.value = entry->hash; #else ht->h(&h, &entry->key, sizeof(entry->key), ht->seed); #endif entry = ck_ht_map_probe_wr(map, h, &snapshot, &priority, (void *)entry->key, sizeof(entry->key), NULL, &probes_wr); } offset = h.value & map->mask; if (priority != NULL) { CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1); ck_pr_fence_store(); #ifndef CK_HT_PP CK_HT_TYPE_STORE(&priority->key_length, entry->key_length); CK_HT_TYPE_STORE(&priority->hash, entry->hash); #endif ck_pr_store_ptr_unsafe(&priority->value, (void *)entry->value); ck_pr_fence_store(); ck_pr_store_ptr_unsafe(&priority->key, (void *)entry->key); ck_pr_fence_store(); CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1); ck_pr_fence_store(); ck_pr_store_ptr_unsafe(&entry->key, (void *)CK_HT_KEY_TOMBSTONE); ck_pr_fence_store(); } if (cycles == 0) { if (probes_wr > maximum) maximum = probes_wr; if (probes_wr >= CK_HT_WORD_MAX) probes_wr = CK_HT_WORD_MAX; if (bounds != NULL && probes_wr > bounds[offset]) bounds[offset] = probes_wr; } else if (--cycles == 0) break; } if (maximum != map->probe_maximum) CK_HT_TYPE_STORE(&map->probe_maximum, maximum); if (bounds != NULL) { for (i = 0; i < map->capacity; i++) CK_HT_STORE(&map->probe_bound[i], bounds[i]); ht->m->free(bounds, size, false); } return true; } static struct ck_ht_entry * ck_ht_map_probe_rd(struct ck_ht_map *map, ck_ht_hash_t h, ck_ht_entry_t *snapshot, const void *key, uint16_t key_length) { struct ck_ht_entry *bucket, *cursor; size_t offset, i, j; CK_HT_TYPE probes = 0; CK_HT_TYPE probe_maximum; #ifndef CK_HT_PP CK_HT_TYPE d = 0; CK_HT_TYPE d_prime = 0; retry: #endif probe_maximum = ck_ht_map_bound_get(map, h); offset = h.value & map->mask; for (i = 0; i < map->probe_limit; i++) { /* * Probe on a complete cache line first. Scan forward and wrap around to * the beginning of the cache line. Only when the complete cache line has * been scanned do we move on to the next row. */ bucket = (void *)((uintptr_t)(map->entries + offset) & ~(CK_MD_CACHELINE - 1)); for (j = 0; j < CK_HT_BUCKET_LENGTH; j++) { uint16_t k; if (probes++ > probe_maximum) return NULL; cursor = bucket + ((j + offset) & (CK_HT_BUCKET_LENGTH - 1)); #ifdef CK_HT_PP snapshot->key = (uintptr_t)ck_pr_load_ptr(&cursor->key); ck_pr_fence_load(); snapshot->value = (uintptr_t)ck_pr_load_ptr(&cursor->value); #else d = CK_HT_TYPE_LOAD(&map->deletions); snapshot->key = (uintptr_t)ck_pr_load_ptr(&cursor->key); ck_pr_fence_load(); snapshot->key_length = CK_HT_TYPE_LOAD(&cursor->key_length); snapshot->hash = CK_HT_TYPE_LOAD(&cursor->hash); snapshot->value = (uintptr_t)ck_pr_load_ptr(&cursor->value); #endif /* * It is probably worth it to encapsulate probe state * in order to prevent a complete reprobe sequence in * the case of intermittent writers. */ if (snapshot->key == CK_HT_KEY_TOMBSTONE) continue; if (snapshot->key == CK_HT_KEY_EMPTY) goto leave; if (snapshot->key == (uintptr_t)key) goto leave; if (map->mode & CK_HT_MODE_BYTESTRING) { void *pointer; /* * Check memoized portion of hash value before * expensive full-length comparison. */ k = ck_ht_entry_key_length(snapshot); if (k != key_length) continue; #ifdef CK_HT_PP if ((snapshot->value >> CK_MD_VMA_BITS) != ((h.value >> 32) & CK_HT_KEY_MASK)) continue; #else if (snapshot->hash != h.value) continue; d_prime = CK_HT_TYPE_LOAD(&map->deletions); /* * It is possible that the slot was * replaced, initiate a re-probe. */ if (d != d_prime) goto retry; #endif pointer = ck_ht_entry_key(snapshot); if (memcmp(pointer, key, key_length) == 0) goto leave; } } offset = ck_ht_map_probe_next(map, offset, h, probes); } return NULL; leave: return cursor; } CK_HT_TYPE ck_ht_count(struct ck_ht *table) { struct ck_ht_map *map = ck_pr_load_ptr(&table->map); return CK_HT_TYPE_LOAD(&map->n_entries); } bool ck_ht_next(struct ck_ht *table, struct ck_ht_iterator *i, struct ck_ht_entry **entry) { struct ck_ht_map *map = table->map; uintptr_t key; if (i->offset >= map->capacity) return false; do { key = map->entries[i->offset].key; if (key != CK_HT_KEY_EMPTY && key != CK_HT_KEY_TOMBSTONE) break; } while (++i->offset < map->capacity); if (i->offset >= map->capacity) return false; *entry = map->entries + i->offset++; return true; } bool ck_ht_reset_size_spmc(struct ck_ht *table, CK_HT_TYPE size) { struct ck_ht_map *map, *update; map = table->map; update = ck_ht_map_create(table, size); if (update == NULL) return false; ck_pr_store_ptr_unsafe(&table->map, update); ck_ht_map_destroy(table->m, map, true); return true; } bool ck_ht_reset_spmc(struct ck_ht *table) { struct ck_ht_map *map = table->map; return ck_ht_reset_size_spmc(table, map->capacity); } bool ck_ht_grow_spmc(struct ck_ht *table, CK_HT_TYPE capacity) { struct ck_ht_map *map, *update; struct ck_ht_entry *bucket, *previous; struct ck_ht_hash h; size_t k, i, j, offset; CK_HT_TYPE probes; restart: map = table->map; if (map->capacity >= capacity) return false; update = ck_ht_map_create(table, capacity); if (update == NULL) return false; for (k = 0; k < map->capacity; k++) { previous = &map->entries[k]; if (previous->key == CK_HT_KEY_EMPTY || previous->key == CK_HT_KEY_TOMBSTONE) continue; if (table->mode & CK_HT_MODE_BYTESTRING) { #ifdef CK_HT_PP void *key; uint16_t key_length; key = ck_ht_entry_key(previous); key_length = ck_ht_entry_key_length(previous); #endif #ifndef CK_HT_PP h.value = previous->hash; #else table->h(&h, key, key_length, table->seed); #endif } else { #ifndef CK_HT_PP h.value = previous->hash; #else table->h(&h, &previous->key, sizeof(previous->key), table->seed); #endif } offset = h.value & update->mask; probes = 0; for (i = 0; i < update->probe_limit; i++) { bucket = (void *)((uintptr_t)(update->entries + offset) & ~(CK_MD_CACHELINE - 1)); for (j = 0; j < CK_HT_BUCKET_LENGTH; j++) { struct ck_ht_entry *cursor = bucket + ((j + offset) & (CK_HT_BUCKET_LENGTH - 1)); probes++; if (CK_CC_LIKELY(cursor->key == CK_HT_KEY_EMPTY)) { *cursor = *previous; update->n_entries++; ck_ht_map_bound_set(update, h, probes); break; } } if (j < CK_HT_BUCKET_LENGTH) break; offset = ck_ht_map_probe_next(update, offset, h, probes); } if (i == update->probe_limit) { /* * We have hit the probe limit, the map needs to be even * larger. */ ck_ht_map_destroy(table->m, update, false); capacity <<= 1; goto restart; } } ck_pr_fence_store(); ck_pr_store_ptr_unsafe(&table->map, update); ck_ht_map_destroy(table->m, map, true); return true; } bool ck_ht_remove_spmc(struct ck_ht *table, ck_ht_hash_t h, ck_ht_entry_t *entry) { struct ck_ht_map *map; struct ck_ht_entry *candidate, snapshot; map = table->map; if (table->mode & CK_HT_MODE_BYTESTRING) { candidate = ck_ht_map_probe_rd(map, h, &snapshot, ck_ht_entry_key(entry), ck_ht_entry_key_length(entry)); } else { candidate = ck_ht_map_probe_rd(map, h, &snapshot, (void *)entry->key, sizeof(entry->key)); } /* No matching entry was found. */ if (candidate == NULL || snapshot.key == CK_HT_KEY_EMPTY) return false; *entry = snapshot; ck_pr_store_ptr_unsafe(&candidate->key, (void *)CK_HT_KEY_TOMBSTONE); ck_pr_fence_store(); CK_HT_TYPE_STORE(&map->n_entries, map->n_entries - 1); return true; } bool ck_ht_get_spmc(struct ck_ht *table, ck_ht_hash_t h, ck_ht_entry_t *entry) { struct ck_ht_entry *candidate, snapshot; struct ck_ht_map *map; CK_HT_TYPE d, d_prime; restart: map = ck_pr_load_ptr(&table->map); /* * Platforms that cannot read key and key_length atomically must reprobe * on the scan of any single entry. */ d = CK_HT_TYPE_LOAD(&map->deletions); if (table->mode & CK_HT_MODE_BYTESTRING) { candidate = ck_ht_map_probe_rd(map, h, &snapshot, ck_ht_entry_key(entry), ck_ht_entry_key_length(entry)); } else { candidate = ck_ht_map_probe_rd(map, h, &snapshot, (void *)entry->key, sizeof(entry->key)); } d_prime = CK_HT_TYPE_LOAD(&map->deletions); if (d != d_prime) { /* * It is possible we have read (K, V'). Only valid states are * (K, V), (K', V') and (T, V). Restart load operation in face * of concurrent deletions or replacements. */ goto restart; } if (candidate == NULL || snapshot.key == CK_HT_KEY_EMPTY) return false; *entry = snapshot; return true; } bool ck_ht_set_spmc(struct ck_ht *table, ck_ht_hash_t h, ck_ht_entry_t *entry) { struct ck_ht_entry snapshot, *candidate, *priority; struct ck_ht_map *map; CK_HT_TYPE probes, probes_wr; bool empty = false; for (;;) { map = table->map; if (table->mode & CK_HT_MODE_BYTESTRING) { candidate = ck_ht_map_probe_wr(map, h, &snapshot, &priority, ck_ht_entry_key(entry), ck_ht_entry_key_length(entry), &probes, &probes_wr); } else { candidate = ck_ht_map_probe_wr(map, h, &snapshot, &priority, (void *)entry->key, sizeof(entry->key), &probes, &probes_wr); } if (priority != NULL) { probes = probes_wr; break; } if (candidate != NULL) break; if (ck_ht_grow_spmc(table, map->capacity << 1) == false) return false; } if (candidate == NULL) { candidate = priority; empty = true; } if (candidate->key != CK_HT_KEY_EMPTY && priority != NULL && candidate != priority) { /* * Entry is moved into another position in probe sequence. * We avoid a state of (K, B) (where [K, B] -> [K', B]) by * guaranteeing a forced reprobe before transitioning from K to * T. (K, B) implies (K, B, D') so we will reprobe successfully * from this transient state. */ probes = probes_wr; #ifndef CK_HT_PP CK_HT_TYPE_STORE(&priority->key_length, entry->key_length); CK_HT_TYPE_STORE(&priority->hash, entry->hash); #endif /* * Readers must observe version counter change before they * observe re-use. If they observe re-use, it is at most * a tombstone. */ if (priority->value == CK_HT_KEY_TOMBSTONE) { CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1); ck_pr_fence_store(); } ck_pr_store_ptr_unsafe(&priority->value, (void *)entry->value); ck_pr_fence_store(); ck_pr_store_ptr_unsafe(&priority->key, (void *)entry->key); ck_pr_fence_store(); /* * Make sure that readers who observe the tombstone would * also observe counter change. */ CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1); ck_pr_fence_store(); ck_pr_store_ptr_unsafe(&candidate->key, (void *)CK_HT_KEY_TOMBSTONE); ck_pr_fence_store(); } else { /* * In this case we are inserting a new entry or replacing * an existing entry. Yes, this can be combined into above branch, * but isn't because you are actually looking at dying code * (ck_ht is effectively deprecated and is being replaced soon). */ bool replace = candidate->key != CK_HT_KEY_EMPTY && candidate->key != CK_HT_KEY_TOMBSTONE; if (priority != NULL) { if (priority->key == CK_HT_KEY_TOMBSTONE) { CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1); ck_pr_fence_store(); } candidate = priority; probes = probes_wr; } #ifdef CK_HT_PP ck_pr_store_ptr_unsafe(&candidate->value, (void *)entry->value); ck_pr_fence_store(); ck_pr_store_ptr_unsafe(&candidate->key, (void *)entry->key); #else CK_HT_TYPE_STORE(&candidate->key_length, entry->key_length); CK_HT_TYPE_STORE(&candidate->hash, entry->hash); ck_pr_store_ptr_unsafe(&candidate->value, (void *)entry->value); ck_pr_fence_store(); ck_pr_store_ptr_unsafe(&candidate->key, (void *)entry->key); #endif /* * If we are insert a new entry then increment number * of entries associated with map. */ if (replace == false) CK_HT_TYPE_STORE(&map->n_entries, map->n_entries + 1); } ck_ht_map_bound_set(map, h, probes); /* Enforce a load factor of 0.5. */ if (map->n_entries * 2 > map->capacity) ck_ht_grow_spmc(table, map->capacity << 1); if (empty == true) { entry->key = CK_HT_KEY_EMPTY; } else { *entry = snapshot; } return true; } bool ck_ht_put_spmc(struct ck_ht *table, ck_ht_hash_t h, ck_ht_entry_t *entry) { struct ck_ht_entry snapshot, *candidate, *priority; struct ck_ht_map *map; CK_HT_TYPE probes, probes_wr; for (;;) { map = table->map; if (table->mode & CK_HT_MODE_BYTESTRING) { candidate = ck_ht_map_probe_wr(map, h, &snapshot, &priority, ck_ht_entry_key(entry), ck_ht_entry_key_length(entry), &probes, &probes_wr); } else { candidate = ck_ht_map_probe_wr(map, h, &snapshot, &priority, (void *)entry->key, sizeof(entry->key), &probes, &probes_wr); } if (candidate != NULL || priority != NULL) break; if (ck_ht_grow_spmc(table, map->capacity << 1) == false) return false; } if (priority != NULL) { /* Version counter is updated before re-use. */ CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1); ck_pr_fence_store(); /* Re-use tombstone if one was found. */ candidate = priority; probes = probes_wr; } else if (candidate->key != CK_HT_KEY_EMPTY && candidate->key != CK_HT_KEY_TOMBSTONE) { /* * If the snapshot key is non-empty and the value field is not * a tombstone then an identical key was found. As store does * not implement replacement, we will fail. */ return false; } ck_ht_map_bound_set(map, h, probes); #ifdef CK_HT_PP ck_pr_store_ptr_unsafe(&candidate->value, (void *)entry->value); ck_pr_fence_store(); ck_pr_store_ptr_unsafe(&candidate->key, (void *)entry->key); #else CK_HT_TYPE_STORE(&candidate->key_length, entry->key_length); CK_HT_TYPE_STORE(&candidate->hash, entry->hash); ck_pr_store_ptr_unsafe(&candidate->value, (void *)entry->value); ck_pr_fence_store(); ck_pr_store_ptr_unsafe(&candidate->key, (void *)entry->key); #endif CK_HT_TYPE_STORE(&map->n_entries, map->n_entries + 1); /* Enforce a load factor of 0.5. */ if (map->n_entries * 2 > map->capacity) ck_ht_grow_spmc(table, map->capacity << 1); return true; } void ck_ht_destroy(struct ck_ht *table) { ck_ht_map_destroy(table->m, table->map, false); return; } ================================================ FILE: third_party/concurrency_kit/ck/src/ck_ht_hash.h ================================================ /* * Copyright 2012-2015 Samy Al Bahra * Copyright 2011-2014 AppNexus, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CK_HT_HASH_H #define CK_HT_HASH_H /* * This is the Murmur hash written by Austin Appleby. */ #include #include //----------------------------------------------------------------------------- // MurmurHash3 was written by Austin Appleby, and is placed in the public // domain. The author hereby disclaims copyright to this source code. // Note - The x86 and x64 versions do _not_ produce the same results, as the // algorithms are optimized for their respective platforms. You can still // compile and run any of them on any platform, but your performance with the // non-native version will be less than optimal. //----------------------------------------------------------------------------- // Platform-specific functions and macros // Microsoft Visual Studio #if defined(_MSC_VER) #define FORCE_INLINE __forceinline #include #define ROTL32(x,y) _rotl(x,y) #define ROTL64(x,y) _rotl64(x,y) #define BIG_CONSTANT(x) (x) // Other compilers #else // defined(_MSC_VER) #define FORCE_INLINE inline __attribute__((always_inline)) static inline uint32_t rotl32 ( uint32_t x, int8_t r ) { return (x << r) | (x >> (32 - r)); } static inline uint64_t rotl64 ( uint64_t x, int8_t r ) { return (x << r) | (x >> (64 - r)); } #define ROTL32(x,y) rotl32(x,y) #define ROTL64(x,y) rotl64(x,y) #define BIG_CONSTANT(x) (x##LLU) #endif // !defined(_MSC_VER) //----------------------------------------------------------------------------- // Block read - if your platform needs to do endian-swapping or can only // handle aligned reads, do the conversion here FORCE_INLINE static uint32_t getblock ( const uint32_t * p, int i ) { #ifdef __s390x__ uint32_t res; __asm__ (" lrv %0,%1\n" : "=r" (res) : "Q" (p[i]) : "cc", "mem"); return res; #else return p[i]; #endif /* !__s390x__ */ } //----------------------------------------------------------------------------- // Finalization mix - force all bits of a hash block to avalanche FORCE_INLINE static uint32_t fmix ( uint32_t h ) { h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; h *= 0xc2b2ae35; h ^= h >> 16; return h; } //----------------------------------------------------------------------------- static inline void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, uint32_t * out ) { const uint8_t * data = (const uint8_t*)key; const int nblocks = len / 4; int i; uint32_t h1 = seed; uint32_t c1 = 0xcc9e2d51; uint32_t c2 = 0x1b873593; //---------- // body const uint32_t * blocks = (const uint32_t *)(const void *)(data + nblocks*4); for(i = -nblocks; i; i++) { uint32_t k1 = getblock(blocks,i); k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; h1 = ROTL32(h1,13); h1 = h1*5+0xe6546b64; } //---------- // tail const uint8_t * tail = (const uint8_t*)(data + nblocks*4); uint32_t k1 = 0; switch(len & 3) { case 3: k1 ^= tail[2] << 16; /* fall through */ case 2: k1 ^= tail[1] << 8; /* fall through */ case 1: k1 ^= tail[0]; k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; }; //---------- // finalization h1 ^= len; h1 = fmix(h1); *(uint32_t *)out = h1; } static inline uint64_t MurmurHash64A ( const void * key, int len, uint64_t seed ) { const uint64_t m = BIG_CONSTANT(0xc6a4a7935bd1e995); const int r = 47; uint64_t h = seed ^ (len * m); const uint64_t * data = (const uint64_t *)key; const uint64_t * end = data + (len/8); while(data != end) { uint64_t k; if (!((uintptr_t)data & 0x7)) k = *data++; else { memcpy(&k, data, sizeof(k)); data++; } k *= m; k ^= k >> r; k *= m; h ^= k; h *= m; } const unsigned char * data2 = (const unsigned char*)data; switch(len & 7) { case 7: h ^= (uint64_t)(data2[6]) << 48; /* fall through */ case 6: h ^= (uint64_t)(data2[5]) << 40; /* fall through */ case 5: h ^= (uint64_t)(data2[4]) << 32; /* fall through */ case 4: h ^= (uint64_t)(data2[3]) << 24; /* fall through */ case 3: h ^= (uint64_t)(data2[2]) << 16; /* fall through */ case 2: h ^= (uint64_t)(data2[1]) << 8; /* fall through */ case 1: h ^= (uint64_t)(data2[0]); h *= m; }; h ^= h >> r; h *= m; h ^= h >> r; return h; } // 64-bit hash for 32-bit platforms static inline uint64_t MurmurHash64B ( const void * key, int len, uint64_t seed ) { const uint32_t m = 0x5bd1e995; const int r = 24; uint32_t h1 = (uint32_t)(seed) ^ len; uint32_t h2 = (uint32_t)(seed >> 32); const uint32_t * data = (const uint32_t *)key; while(len >= 8) { uint32_t k1 = *data++; k1 *= m; k1 ^= k1 >> r; k1 *= m; h1 *= m; h1 ^= k1; len -= 4; uint32_t k2 = *data++; k2 *= m; k2 ^= k2 >> r; k2 *= m; h2 *= m; h2 ^= k2; len -= 4; } if(len >= 4) { uint32_t k1 = *data++; k1 *= m; k1 ^= k1 >> r; k1 *= m; h1 *= m; h1 ^= k1; len -= 4; } switch(len) { case 3: h2 ^= ((const unsigned char*)data)[2] << 16; /* fall through */ case 2: h2 ^= ((const unsigned char*)data)[1] << 8; /* fall through */ case 1: h2 ^= ((const unsigned char*)data)[0]; h2 *= m; }; h1 ^= h2 >> 18; h1 *= m; h2 ^= h1 >> 22; h2 *= m; h1 ^= h2 >> 17; h1 *= m; h2 ^= h1 >> 19; h2 *= m; uint64_t h = h1; h = (h << 32) | h2; return h; } #endif /* CK_HT_HASH_H */ ================================================ FILE: third_party/concurrency_kit/ck/src/ck_internal.h ================================================ /* * Copyright 2011-2015 Samy Al Bahra. * Copyright 2011 David Joseph. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Several of these are from: http://graphics.stanford.edu/~seander/bithacks.html */ #define CK_INTERNAL_LOG_0 (0xAAAAAAAA) #define CK_INTERNAL_LOG_1 (0xCCCCCCCC) #define CK_INTERNAL_LOG_2 (0xF0F0F0F0) #define CK_INTERNAL_LOG_3 (0xFF00FF00) #define CK_INTERNAL_LOG_4 (0xFFFF0000) CK_CC_INLINE static uint32_t ck_internal_log(uint32_t v) { uint32_t r = (v & CK_INTERNAL_LOG_0) != 0; r |= ((v & CK_INTERNAL_LOG_4) != 0) << 4; r |= ((v & CK_INTERNAL_LOG_3) != 0) << 3; r |= ((v & CK_INTERNAL_LOG_2) != 0) << 2; r |= ((v & CK_INTERNAL_LOG_1) != 0) << 1; return (r); } CK_CC_INLINE static uint32_t ck_internal_power_2(uint32_t v) { --v; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return (++v); } CK_CC_INLINE static unsigned long ck_internal_max(unsigned long x, unsigned long y) { return x ^ ((x ^ y) & -(x < y)); } CK_CC_INLINE static uint64_t ck_internal_max_64(uint64_t x, uint64_t y) { return x ^ ((x ^ y) & -(x < y)); } CK_CC_INLINE static uint32_t ck_internal_max_32(uint32_t x, uint32_t y) { return x ^ ((x ^ y) & -(x < y)); } CK_CC_INLINE static unsigned long ck_internal_bsf(unsigned long v) { #if defined(__GNUC__) return __builtin_ffs(v); #else unsigned int i; const unsigned int s = sizeof(unsigned long) * 8 - 1; for (i = 0; i < s; i++) { if (v & (1UL << (s - i))) return sizeof(unsigned long) * 8 - i; } return 1; #endif /* !__GNUC__ */ } CK_CC_INLINE static uint64_t ck_internal_bsf_64(uint64_t v) { #if defined(__GNUC__) return __builtin_ffs(v); #else unsigned int i; const unsigned int s = sizeof(unsigned long) * 8 - 1; for (i = 0; i < s; i++) { if (v & (1ULL << (63U - i))) return i; } #endif /* !__GNUC__ */ return 1; } ================================================ FILE: third_party/concurrency_kit/ck/src/ck_rhs.c ================================================ /* * Copyright 2014-2015 Olivier Houchard. * Copyright 2012-2015 Samy Al Bahra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "ck_internal.h" #ifndef CK_RHS_PROBE_L1_SHIFT #define CK_RHS_PROBE_L1_SHIFT 3ULL #endif /* CK_RHS_PROBE_L1_SHIFT */ #define CK_RHS_PROBE_L1 (1 << CK_RHS_PROBE_L1_SHIFT) #define CK_RHS_PROBE_L1_MASK (CK_RHS_PROBE_L1 - 1) #ifndef CK_RHS_PROBE_L1_DEFAULT #define CK_RHS_PROBE_L1_DEFAULT CK_MD_CACHELINE #endif #define CK_RHS_VMA_MASK ((uintptr_t)((1ULL << CK_MD_VMA_BITS) - 1)) #define CK_RHS_VMA(x) \ ((void *)((uintptr_t)(x) & CK_RHS_VMA_MASK)) #define CK_RHS_EMPTY NULL #define CK_RHS_G (1024) #define CK_RHS_G_MASK (CK_RHS_G - 1) #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_STORE_8) #define CK_RHS_WORD uint8_t #define CK_RHS_WORD_MAX UINT8_MAX #define CK_RHS_STORE(x, y) ck_pr_store_8(x, y) #define CK_RHS_LOAD(x) ck_pr_load_8(x) #elif defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_STORE_16) #define CK_RHS_WORD uint16_t #define CK_RHS_WORD_MAX UINT16_MAX #define CK_RHS_STORE(x, y) ck_pr_store_16(x, y) #define CK_RHS_LOAD(x) ck_pr_load_16(x) #elif defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_STORE_32) #define CK_RHS_WORD uint32_t #define CK_RHS_WORD_MAX UINT32_MAX #define CK_RHS_STORE(x, y) ck_pr_store_32(x, y) #define CK_RHS_LOAD(x) ck_pr_load_32(x) #else #error "ck_rhs is not supported on your platform." #endif #define CK_RHS_MAX_WANTED 0xffff enum ck_rhs_probe_behavior { CK_RHS_PROBE = 0, /* Default behavior. */ CK_RHS_PROBE_RH, /* Short-circuit if RH slot found. */ CK_RHS_PROBE_INSERT, /* Short-circuit on probe bound if tombstone found. */ CK_RHS_PROBE_ROBIN_HOOD,/* Look for the first slot available for the entry we are about to replace, only used to internally implement Robin Hood */ CK_RHS_PROBE_NO_RH, /* Don't do the RH dance */ }; struct ck_rhs_entry_desc { unsigned int probes; unsigned short wanted; CK_RHS_WORD probe_bound; bool in_rh; const void *entry; } CK_CC_ALIGN(16); struct ck_rhs_no_entry_desc { unsigned int probes; unsigned short wanted; CK_RHS_WORD probe_bound; bool in_rh; } CK_CC_ALIGN(8); typedef long ck_rhs_probe_cb_t(struct ck_rhs *hs, struct ck_rhs_map *map, unsigned long *n_probes, long *priority, unsigned long h, const void *key, const void **object, unsigned long probe_limit, enum ck_rhs_probe_behavior behavior); struct ck_rhs_map { unsigned int generation[CK_RHS_G]; unsigned int probe_maximum; unsigned long mask; unsigned long step; unsigned int probe_limit; unsigned long n_entries; unsigned long capacity; unsigned long size; unsigned long max_entries; char offset_mask; union { struct ck_rhs_entry_desc *descs; struct ck_rhs_no_entry { const void **entries; struct ck_rhs_no_entry_desc *descs; } no_entries; } entries; bool read_mostly; ck_rhs_probe_cb_t *probe_func; }; static CK_CC_INLINE const void * ck_rhs_entry(struct ck_rhs_map *map, long offset) { if (map->read_mostly) return (map->entries.no_entries.entries[offset]); else return (map->entries.descs[offset].entry); } static CK_CC_INLINE const void ** ck_rhs_entry_addr(struct ck_rhs_map *map, long offset) { if (map->read_mostly) return (&map->entries.no_entries.entries[offset]); else return (&map->entries.descs[offset].entry); } static CK_CC_INLINE struct ck_rhs_entry_desc * ck_rhs_desc(struct ck_rhs_map *map, long offset) { if (CK_CC_UNLIKELY(map->read_mostly)) return ((struct ck_rhs_entry_desc *)(void *)&map->entries.no_entries.descs[offset]); else return (&map->entries.descs[offset]); } static CK_CC_INLINE void ck_rhs_wanted_inc(struct ck_rhs_map *map, long offset) { if (CK_CC_UNLIKELY(map->read_mostly)) map->entries.no_entries.descs[offset].wanted++; else map->entries.descs[offset].wanted++; } static CK_CC_INLINE unsigned int ck_rhs_probes(struct ck_rhs_map *map, long offset) { if (CK_CC_UNLIKELY(map->read_mostly)) return (map->entries.no_entries.descs[offset].probes); else return (map->entries.descs[offset].probes); } static CK_CC_INLINE void ck_rhs_set_probes(struct ck_rhs_map *map, long offset, unsigned int value) { if (CK_CC_UNLIKELY(map->read_mostly)) map->entries.no_entries.descs[offset].probes = value; else map->entries.descs[offset].probes = value; } static CK_CC_INLINE CK_RHS_WORD ck_rhs_probe_bound(struct ck_rhs_map *map, long offset) { if (CK_CC_UNLIKELY(map->read_mostly)) return (map->entries.no_entries.descs[offset].probe_bound); else return (map->entries.descs[offset].probe_bound); } static CK_CC_INLINE CK_RHS_WORD * ck_rhs_probe_bound_addr(struct ck_rhs_map *map, long offset) { if (CK_CC_UNLIKELY(map->read_mostly)) return (&map->entries.no_entries.descs[offset].probe_bound); else return (&map->entries.descs[offset].probe_bound); } static CK_CC_INLINE bool ck_rhs_in_rh(struct ck_rhs_map *map, long offset) { if (CK_CC_UNLIKELY(map->read_mostly)) return (map->entries.no_entries.descs[offset].in_rh); else return (map->entries.descs[offset].in_rh); } static CK_CC_INLINE void ck_rhs_set_rh(struct ck_rhs_map *map, long offset) { if (CK_CC_UNLIKELY(map->read_mostly)) map->entries.no_entries.descs[offset].in_rh = true; else map->entries.descs[offset].in_rh = true; } static CK_CC_INLINE void ck_rhs_unset_rh(struct ck_rhs_map *map, long offset) { if (CK_CC_UNLIKELY(map->read_mostly)) map->entries.no_entries.descs[offset].in_rh = false; else map->entries.descs[offset].in_rh = false; } #define CK_RHS_DEFAULT_LOAD_FACTOR 50 static ck_rhs_probe_cb_t ck_rhs_map_probe; static ck_rhs_probe_cb_t ck_rhs_map_probe_rm; bool ck_rhs_set_load_factor(struct ck_rhs *hs, unsigned int load_factor) { struct ck_rhs_map *map = hs->map; if (load_factor == 0 || load_factor > 100) return false; hs->load_factor = load_factor; map->max_entries = (map->capacity * (unsigned long)hs->load_factor) / 100; while (map->n_entries > map->max_entries) { if (ck_rhs_grow(hs, map->capacity << 1) == false) return false; map = hs->map; } return true; } void ck_rhs_iterator_init(struct ck_rhs_iterator *iterator) { iterator->cursor = NULL; iterator->offset = 0; return; } bool ck_rhs_next(struct ck_rhs *hs, struct ck_rhs_iterator *i, void **key) { struct ck_rhs_map *map = hs->map; void *value; if (i->offset >= map->capacity) return false; do { value = CK_CC_DECONST_PTR(ck_rhs_entry(map, i->offset)); if (value != CK_RHS_EMPTY) { #ifdef CK_RHS_PP if (hs->mode & CK_RHS_MODE_OBJECT) value = CK_RHS_VMA(value); #endif i->offset++; *key = value; return true; } } while (++i->offset < map->capacity); return false; } void ck_rhs_stat(struct ck_rhs *hs, struct ck_rhs_stat *st) { struct ck_rhs_map *map = hs->map; st->n_entries = map->n_entries; st->probe_maximum = map->probe_maximum; return; } unsigned long ck_rhs_count(struct ck_rhs *hs) { return hs->map->n_entries; } static void ck_rhs_map_destroy(struct ck_malloc *m, struct ck_rhs_map *map, bool defer) { m->free(map, map->size, defer); return; } void ck_rhs_destroy(struct ck_rhs *hs) { ck_rhs_map_destroy(hs->m, hs->map, false); return; } static struct ck_rhs_map * ck_rhs_map_create(struct ck_rhs *hs, unsigned long entries) { struct ck_rhs_map *map; unsigned long size, n_entries, limit; n_entries = ck_internal_power_2(entries); if (n_entries < CK_RHS_PROBE_L1) n_entries = CK_RHS_PROBE_L1; if (hs->mode & CK_RHS_MODE_READ_MOSTLY) size = sizeof(struct ck_rhs_map) + (sizeof(void *) * n_entries + sizeof(struct ck_rhs_no_entry_desc) * n_entries + 2 * CK_MD_CACHELINE - 1); else size = sizeof(struct ck_rhs_map) + (sizeof(struct ck_rhs_entry_desc) * n_entries + CK_MD_CACHELINE - 1); map = hs->m->malloc(size); if (map == NULL) return NULL; map->read_mostly = !!(hs->mode & CK_RHS_MODE_READ_MOSTLY); map->size = size; /* We should probably use a more intelligent heuristic for default probe length. */ limit = ck_internal_max(n_entries >> (CK_RHS_PROBE_L1_SHIFT + 2), CK_RHS_PROBE_L1_DEFAULT); if (limit > UINT_MAX) limit = UINT_MAX; map->probe_limit = (unsigned int)limit; map->probe_maximum = 0; map->capacity = n_entries; map->step = ck_internal_bsf(n_entries); map->mask = n_entries - 1; map->n_entries = 0; map->max_entries = (map->capacity * (unsigned long)hs->load_factor) / 100; /* Align map allocation to cache line. */ if (map->read_mostly) { map->entries.no_entries.entries = (void *)(((uintptr_t)&map[1] + CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1)); map->entries.no_entries.descs = (void *)(((uintptr_t)map->entries.no_entries.entries + (sizeof(void *) * n_entries) + CK_MD_CACHELINE - 1) &~ (CK_MD_CACHELINE - 1)); memset(map->entries.no_entries.entries, 0, sizeof(void *) * n_entries); memset(map->entries.no_entries.descs, 0, sizeof(struct ck_rhs_no_entry_desc) * n_entries); map->offset_mask = (CK_MD_CACHELINE / sizeof(void *)) - 1; map->probe_func = ck_rhs_map_probe_rm; } else { map->entries.descs = (void *)(((uintptr_t)&map[1] + CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1)); memset(map->entries.descs, 0, sizeof(struct ck_rhs_entry_desc) * n_entries); map->offset_mask = (CK_MD_CACHELINE / sizeof(struct ck_rhs_entry_desc)) - 1; map->probe_func = ck_rhs_map_probe; } memset(map->generation, 0, sizeof map->generation); /* Commit entries purge with respect to map publication. */ ck_pr_fence_store(); return map; } bool ck_rhs_reset_size(struct ck_rhs *hs, unsigned long capacity) { struct ck_rhs_map *map, *previous; previous = hs->map; map = ck_rhs_map_create(hs, capacity); if (map == NULL) return false; ck_pr_store_ptr(&hs->map, map); ck_rhs_map_destroy(hs->m, previous, true); return true; } bool ck_rhs_reset(struct ck_rhs *hs) { struct ck_rhs_map *previous; previous = hs->map; return ck_rhs_reset_size(hs, previous->capacity); } static inline unsigned long ck_rhs_map_probe_next(struct ck_rhs_map *map, unsigned long offset, unsigned long probes) { if (probes & map->offset_mask) { offset = (offset &~ map->offset_mask) + ((offset + 1) & map->offset_mask); return offset; } else return (offset + probes) & map->mask; } static inline unsigned long ck_rhs_map_probe_prev(struct ck_rhs_map *map, unsigned long offset, unsigned long probes) { if (probes & map->offset_mask) { offset = (offset &~ map->offset_mask) + ((offset - 1) & map->offset_mask); return offset; } else return ((offset - probes) & map->mask); } static inline void ck_rhs_map_bound_set(struct ck_rhs_map *m, unsigned long h, unsigned long n_probes) { unsigned long offset = h & m->mask; struct ck_rhs_entry_desc *desc; if (n_probes > m->probe_maximum) ck_pr_store_uint(&m->probe_maximum, n_probes); if (!(m->read_mostly)) { desc = &m->entries.descs[offset]; if (desc->probe_bound < n_probes) { if (n_probes > CK_RHS_WORD_MAX) n_probes = CK_RHS_WORD_MAX; CK_RHS_STORE(&desc->probe_bound, n_probes); ck_pr_fence_store(); } } return; } static inline unsigned int ck_rhs_map_bound_get(struct ck_rhs_map *m, unsigned long h) { unsigned long offset = h & m->mask; unsigned int r = CK_RHS_WORD_MAX; if (m->read_mostly) r = ck_pr_load_uint(&m->probe_maximum); else { r = CK_RHS_LOAD(&m->entries.descs[offset].probe_bound); if (r == CK_RHS_WORD_MAX) r = ck_pr_load_uint(&m->probe_maximum); } return r; } bool ck_rhs_grow(struct ck_rhs *hs, unsigned long capacity) { struct ck_rhs_map *map, *update; const void *previous, *prev_saved; unsigned long k, offset, probes; restart: map = hs->map; if (map->capacity > capacity) return false; update = ck_rhs_map_create(hs, capacity); if (update == NULL) return false; for (k = 0; k < map->capacity; k++) { unsigned long h; prev_saved = previous = ck_rhs_entry(map, k); if (previous == CK_RHS_EMPTY) continue; #ifdef CK_RHS_PP if (hs->mode & CK_RHS_MODE_OBJECT) previous = CK_RHS_VMA(previous); #endif h = hs->hf(previous, hs->seed); offset = h & update->mask; probes = 0; for (;;) { const void **cursor = ck_rhs_entry_addr(update, offset); if (probes++ == update->probe_limit) { /* * We have hit the probe limit, map needs to be even larger. */ ck_rhs_map_destroy(hs->m, update, false); capacity <<= 1; goto restart; } if (CK_CC_LIKELY(*cursor == CK_RHS_EMPTY)) { *cursor = prev_saved; update->n_entries++; ck_rhs_set_probes(update, offset, probes); ck_rhs_map_bound_set(update, h, probes); break; } else if (ck_rhs_probes(update, offset) < probes) { const void *tmp = prev_saved; unsigned int old_probes; prev_saved = previous = *cursor; #ifdef CK_RHS_PP if (hs->mode & CK_RHS_MODE_OBJECT) previous = CK_RHS_VMA(previous); #endif *cursor = tmp; ck_rhs_map_bound_set(update, h, probes); h = hs->hf(previous, hs->seed); old_probes = ck_rhs_probes(update, offset); ck_rhs_set_probes(update, offset, probes); probes = old_probes - 1; continue; } ck_rhs_wanted_inc(update, offset); offset = ck_rhs_map_probe_next(update, offset, probes); } } ck_pr_fence_store(); ck_pr_store_ptr(&hs->map, update); ck_rhs_map_destroy(hs->m, map, true); return true; } bool ck_rhs_rebuild(struct ck_rhs *hs) { return ck_rhs_grow(hs, hs->map->capacity); } static long ck_rhs_map_probe_rm(struct ck_rhs *hs, struct ck_rhs_map *map, unsigned long *n_probes, long *priority, unsigned long h, const void *key, const void **object, unsigned long probe_limit, enum ck_rhs_probe_behavior behavior) { const void *k; const void *compare; long pr = -1; unsigned long offset, probes, opl; #ifdef CK_RHS_PP /* If we are storing object pointers, then we may leverage pointer packing. */ unsigned long hv = 0; if (hs->mode & CK_RHS_MODE_OBJECT) { hv = (h >> 25) & CK_RHS_KEY_MASK; compare = CK_RHS_VMA(key); } else { compare = key; } #else compare = key; #endif *object = NULL; if (behavior != CK_RHS_PROBE_ROBIN_HOOD) { probes = 0; offset = h & map->mask; } else { /* Restart from the bucket we were previously in */ probes = *n_probes; offset = ck_rhs_map_probe_next(map, *priority, probes); } opl = probe_limit; for (;;) { if (probes++ == probe_limit) { if (probe_limit == opl || pr != -1) { k = CK_RHS_EMPTY; goto leave; } /* * If no eligible slot has been found yet, continue probe * sequence with original probe limit. */ probe_limit = opl; } k = ck_pr_load_ptr(&map->entries.no_entries.entries[offset]); if (k == CK_RHS_EMPTY) goto leave; if (behavior != CK_RHS_PROBE_NO_RH) { struct ck_rhs_entry_desc *desc = (void *)&map->entries.no_entries.descs[offset]; if (pr == -1 && desc->in_rh == false && desc->probes < probes) { pr = offset; *n_probes = probes; if (behavior == CK_RHS_PROBE_RH || behavior == CK_RHS_PROBE_ROBIN_HOOD) { k = CK_RHS_EMPTY; goto leave; } } } if (behavior != CK_RHS_PROBE_ROBIN_HOOD) { #ifdef CK_RHS_PP if (hs->mode & CK_RHS_MODE_OBJECT) { if (((uintptr_t)k >> CK_MD_VMA_BITS) != hv) { offset = ck_rhs_map_probe_next(map, offset, probes); continue; } k = CK_RHS_VMA(k); } #endif if (k == compare) goto leave; if (hs->compare == NULL) { offset = ck_rhs_map_probe_next(map, offset, probes); continue; } if (hs->compare(k, key) == true) goto leave; } offset = ck_rhs_map_probe_next(map, offset, probes); } leave: if (probes > probe_limit) { offset = -1; } else { *object = k; } if (pr == -1) *n_probes = probes; *priority = pr; return offset; } static long ck_rhs_map_probe(struct ck_rhs *hs, struct ck_rhs_map *map, unsigned long *n_probes, long *priority, unsigned long h, const void *key, const void **object, unsigned long probe_limit, enum ck_rhs_probe_behavior behavior) { const void *k; const void *compare; long pr = -1; unsigned long offset, probes, opl; #ifdef CK_RHS_PP /* If we are storing object pointers, then we may leverage pointer packing. */ unsigned long hv = 0; if (hs->mode & CK_RHS_MODE_OBJECT) { hv = (h >> 25) & CK_RHS_KEY_MASK; compare = CK_RHS_VMA(key); } else { compare = key; } #else compare = key; #endif *object = NULL; if (behavior != CK_RHS_PROBE_ROBIN_HOOD) { probes = 0; offset = h & map->mask; } else { /* Restart from the bucket we were previously in */ probes = *n_probes; offset = ck_rhs_map_probe_next(map, *priority, probes); } opl = probe_limit; if (behavior == CK_RHS_PROBE_INSERT) probe_limit = ck_rhs_map_bound_get(map, h); for (;;) { if (probes++ == probe_limit) { if (probe_limit == opl || pr != -1) { k = CK_RHS_EMPTY; goto leave; } /* * If no eligible slot has been found yet, continue probe * sequence with original probe limit. */ probe_limit = opl; } k = ck_pr_load_ptr(&map->entries.descs[offset].entry); if (k == CK_RHS_EMPTY) goto leave; if ((behavior != CK_RHS_PROBE_NO_RH)) { struct ck_rhs_entry_desc *desc = &map->entries.descs[offset]; if (pr == -1 && desc->in_rh == false && desc->probes < probes) { pr = offset; *n_probes = probes; if (behavior == CK_RHS_PROBE_RH || behavior == CK_RHS_PROBE_ROBIN_HOOD) { k = CK_RHS_EMPTY; goto leave; } } } if (behavior != CK_RHS_PROBE_ROBIN_HOOD) { #ifdef CK_RHS_PP if (hs->mode & CK_RHS_MODE_OBJECT) { if (((uintptr_t)k >> CK_MD_VMA_BITS) != hv) { offset = ck_rhs_map_probe_next(map, offset, probes); continue; } k = CK_RHS_VMA(k); } #endif if (k == compare) goto leave; if (hs->compare == NULL) { offset = ck_rhs_map_probe_next(map, offset, probes); continue; } if (hs->compare(k, key) == true) goto leave; } offset = ck_rhs_map_probe_next(map, offset, probes); } leave: if (probes > probe_limit) { offset = -1; } else { *object = k; } if (pr == -1) *n_probes = probes; *priority = pr; return offset; } static inline const void * ck_rhs_marshal(unsigned int mode, const void *key, unsigned long h) { #ifdef CK_RHS_PP const void *insert; if (mode & CK_RHS_MODE_OBJECT) { insert = (void *)((uintptr_t)CK_RHS_VMA(key) | ((h >> 25) << CK_MD_VMA_BITS)); } else { insert = key; } return insert; #else (void)mode; (void)h; return key; #endif } bool ck_rhs_gc(struct ck_rhs *hs) { unsigned long i; struct ck_rhs_map *map = hs->map; unsigned int max_probes = 0; for (i = 0; i < map->capacity; i++) { if (ck_rhs_probes(map, i) > max_probes) max_probes = ck_rhs_probes(map, i); } map->probe_maximum = max_probes; return true; } static void ck_rhs_add_wanted(struct ck_rhs *hs, long end_offset, long old_slot, unsigned long h) { struct ck_rhs_map *map = hs->map; long offset; unsigned int probes = 1; bool found_slot = false; struct ck_rhs_entry_desc *desc; offset = h & map->mask; if (old_slot == -1) found_slot = true; while (offset != end_offset) { if (offset == old_slot) found_slot = true; if (found_slot) { desc = ck_rhs_desc(map, offset); if (desc->wanted < CK_RHS_MAX_WANTED) desc->wanted++; } offset = ck_rhs_map_probe_next(map, offset, probes); probes++; } } static unsigned long ck_rhs_remove_wanted(struct ck_rhs *hs, long offset, long limit) { struct ck_rhs_map *map = hs->map; int probes = ck_rhs_probes(map, offset); bool do_remove = true; struct ck_rhs_entry_desc *desc; while (probes > 1) { probes--; offset = ck_rhs_map_probe_prev(map, offset, probes); if (offset == limit) do_remove = false; if (do_remove) { desc = ck_rhs_desc(map, offset); if (desc->wanted != CK_RHS_MAX_WANTED) desc->wanted--; } } return offset; } static long ck_rhs_get_first_offset(struct ck_rhs_map *map, unsigned long offset, unsigned int probes) { while (probes > (unsigned long)map->offset_mask + 1) { offset -= ((probes - 1) &~ map->offset_mask); offset &= map->mask; offset = (offset &~ map->offset_mask) + ((offset - map->offset_mask) & map->offset_mask); probes -= map->offset_mask + 1; } return ((offset &~ map->offset_mask) + ((offset - (probes - 1)) & map->offset_mask)); } #define CK_RHS_MAX_RH 512 static int ck_rhs_put_robin_hood(struct ck_rhs *hs, long orig_slot, struct ck_rhs_entry_desc *desc) { long slot, first; const void *object, *insert; unsigned long n_probes; struct ck_rhs_map *map; unsigned long h = 0; long prev; void *key; long prevs[CK_RHS_MAX_RH]; unsigned int prevs_nb = 0; unsigned int i; map = hs->map; first = orig_slot; n_probes = desc->probes; restart: key = CK_CC_DECONST_PTR(ck_rhs_entry(map, first)); insert = key; #ifdef CK_RHS_PP if (hs->mode & CK_RHS_MODE_OBJECT) key = CK_RHS_VMA(key); #endif orig_slot = first; ck_rhs_set_rh(map, orig_slot); slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, prevs_nb == CK_RHS_MAX_RH ? CK_RHS_PROBE_NO_RH : CK_RHS_PROBE_ROBIN_HOOD); if (slot == -1 && first == -1) { if (ck_rhs_grow(hs, map->capacity << 1) == false) { desc->in_rh = false; for (i = 0; i < prevs_nb; i++) ck_rhs_unset_rh(map, prevs[i]); return -1; } return 1; } if (first != -1) { desc = ck_rhs_desc(map, first); int old_probes = desc->probes; desc->probes = n_probes; h = ck_rhs_get_first_offset(map, first, n_probes); ck_rhs_map_bound_set(map, h, n_probes); prev = orig_slot; prevs[prevs_nb++] = prev; n_probes = old_probes; goto restart; } else { /* An empty slot was found. */ h = ck_rhs_get_first_offset(map, slot, n_probes); ck_rhs_map_bound_set(map, h, n_probes); ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert); ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); ck_pr_fence_atomic_store(); ck_rhs_set_probes(map, slot, n_probes); desc->in_rh = 0; ck_rhs_add_wanted(hs, slot, orig_slot, h); } while (prevs_nb > 0) { prev = prevs[--prevs_nb]; ck_pr_store_ptr(ck_rhs_entry_addr(map, orig_slot), ck_rhs_entry(map, prev)); h = ck_rhs_get_first_offset(map, orig_slot, desc->probes); ck_rhs_add_wanted(hs, orig_slot, prev, h); ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); ck_pr_fence_atomic_store(); orig_slot = prev; desc->in_rh = false; desc = ck_rhs_desc(map, orig_slot); } return 0; } static void ck_rhs_do_backward_shift_delete(struct ck_rhs *hs, long slot) { struct ck_rhs_map *map = hs->map; struct ck_rhs_entry_desc *desc, *new_desc = NULL; unsigned long h; desc = ck_rhs_desc(map, slot); h = ck_rhs_remove_wanted(hs, slot, -1); while (desc->wanted > 0) { unsigned long offset = 0, tmp_offset; unsigned long wanted_probes = 1; unsigned int probe = 0; unsigned int max_probes; /* Find a successor */ while (wanted_probes < map->probe_maximum) { probe = wanted_probes; offset = ck_rhs_map_probe_next(map, slot, probe); while (probe < map->probe_maximum) { new_desc = ck_rhs_desc(map, offset); if (new_desc->probes == probe + 1) break; probe++; offset = ck_rhs_map_probe_next(map, offset, probe); } if (probe < map->probe_maximum) break; wanted_probes++; } if (!(wanted_probes < map->probe_maximum)) { desc->wanted = 0; break; } desc->probes = wanted_probes; h = ck_rhs_remove_wanted(hs, offset, slot); ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), ck_rhs_entry(map, offset)); ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); ck_pr_fence_atomic_store(); if (wanted_probes < CK_RHS_WORD_MAX) { struct ck_rhs_entry_desc *hdesc = ck_rhs_desc(map, h); if (hdesc->wanted == 1) CK_RHS_STORE(&hdesc->probe_bound, wanted_probes); else if (hdesc->probe_bound == CK_RHS_WORD_MAX || hdesc->probe_bound == new_desc->probes) { probe++; if (hdesc->probe_bound == CK_RHS_WORD_MAX) max_probes = map->probe_maximum; else { max_probes = hdesc->probe_bound; max_probes--; } tmp_offset = ck_rhs_map_probe_next(map, offset, probe); while (probe < max_probes) { if (h == (unsigned long)ck_rhs_get_first_offset(map, tmp_offset, probe)) break; probe++; tmp_offset = ck_rhs_map_probe_next(map, tmp_offset, probe); } if (probe == max_probes) CK_RHS_STORE(&hdesc->probe_bound, wanted_probes); } } if (desc->wanted < CK_RHS_MAX_WANTED) desc->wanted--; slot = offset; desc = new_desc; } ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), CK_RHS_EMPTY); if ((desc->probes - 1) < CK_RHS_WORD_MAX) CK_RHS_STORE(ck_rhs_probe_bound_addr(map, h), desc->probes - 1); desc->probes = 0; } bool ck_rhs_fas(struct ck_rhs *hs, unsigned long h, const void *key, void **previous) { long slot, first; const void *object; const void *insert; unsigned long n_probes; struct ck_rhs_map *map = hs->map; struct ck_rhs_entry_desc *desc, *desc2; *previous = NULL; restart: slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, ck_rhs_map_bound_get(map, h), CK_RHS_PROBE); /* Replacement semantics presume existence. */ if (object == NULL) return false; insert = ck_rhs_marshal(hs->mode, key, h); if (first != -1) { int ret; desc = ck_rhs_desc(map, slot); desc2 = ck_rhs_desc(map, first); desc->in_rh = true; ret = ck_rhs_put_robin_hood(hs, first, desc2); desc->in_rh = false; if (CK_CC_UNLIKELY(ret == 1)) goto restart; else if (CK_CC_UNLIKELY(ret != 0)) return false; ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert); ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); ck_pr_fence_atomic_store(); desc2->probes = n_probes; ck_rhs_add_wanted(hs, first, -1, h); ck_rhs_do_backward_shift_delete(hs, slot); } else { ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert); ck_rhs_set_probes(map, slot, n_probes); } *previous = CK_CC_DECONST_PTR(object); return true; } /* * An apply function takes two arguments. The first argument is a pointer to a * pre-existing object. The second argument is a pointer to the fifth argument * passed to ck_hs_apply. If a non-NULL pointer is passed to the first argument * and the return value of the apply function is NULL, then the pre-existing * value is deleted. If the return pointer is the same as the one passed to the * apply function then no changes are made to the hash table. If the first * argument is non-NULL and the return pointer is different than that passed to * the apply function, then the pre-existing value is replaced. For * replacement, it is required that the value itself is identical to the * previous value. */ bool ck_rhs_apply(struct ck_rhs *hs, unsigned long h, const void *key, ck_rhs_apply_fn_t *fn, void *cl) { const void *insert; const void *object, *delta = false; unsigned long n_probes; long slot, first; struct ck_rhs_map *map; bool delta_set = false; restart: map = hs->map; slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_RHS_PROBE_INSERT); if (slot == -1 && first == -1) { if (ck_rhs_grow(hs, map->capacity << 1) == false) return false; goto restart; } if (!delta_set) { delta = fn(CK_CC_DECONST_PTR(object), cl); delta_set = true; } if (delta == NULL) { /* * The apply function has requested deletion. If the object doesn't exist, * then exit early. */ if (CK_CC_UNLIKELY(object == NULL)) return true; /* Otherwise, delete it. */ ck_rhs_do_backward_shift_delete(hs, slot); return true; } /* The apply function has not requested hash set modification so exit early. */ if (delta == object) return true; /* A modification or insertion has been requested. */ ck_rhs_map_bound_set(map, h, n_probes); insert = ck_rhs_marshal(hs->mode, delta, h); if (first != -1) { /* * This follows the same semantics as ck_hs_set, please refer to that * function for documentation. */ struct ck_rhs_entry_desc *desc = NULL, *desc2; if (slot != -1) { desc = ck_rhs_desc(map, slot); desc->in_rh = true; } desc2 = ck_rhs_desc(map, first); int ret = ck_rhs_put_robin_hood(hs, first, desc2); if (slot != -1) desc->in_rh = false; if (CK_CC_UNLIKELY(ret == 1)) goto restart; if (CK_CC_UNLIKELY(ret == -1)) return false; /* If an earlier bucket was found, then store entry there. */ ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert); desc2->probes = n_probes; /* * If a duplicate key was found, then delete it after * signaling concurrent probes to restart. Optionally, * it is possible to install tombstone after grace * period if we can guarantee earlier position of * duplicate key. */ ck_rhs_add_wanted(hs, first, -1, h); if (object != NULL) { ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); ck_pr_fence_atomic_store(); ck_rhs_do_backward_shift_delete(hs, slot); } } else { /* * If we are storing into same slot, then atomic store is sufficient * for replacement. */ ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert); ck_rhs_set_probes(map, slot, n_probes); if (object == NULL) ck_rhs_add_wanted(hs, slot, -1, h); } if (object == NULL) { map->n_entries++; if ((map->n_entries ) > map->max_entries) ck_rhs_grow(hs, map->capacity << 1); } return true; } bool ck_rhs_set(struct ck_rhs *hs, unsigned long h, const void *key, void **previous) { long slot, first; const void *object; const void *insert; unsigned long n_probes; struct ck_rhs_map *map; *previous = NULL; restart: map = hs->map; slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_RHS_PROBE_INSERT); if (slot == -1 && first == -1) { if (ck_rhs_grow(hs, map->capacity << 1) == false) return false; goto restart; } ck_rhs_map_bound_set(map, h, n_probes); insert = ck_rhs_marshal(hs->mode, key, h); if (first != -1) { struct ck_rhs_entry_desc *desc = NULL, *desc2; if (slot != -1) { desc = ck_rhs_desc(map, slot); desc->in_rh = true; } desc2 = ck_rhs_desc(map, first); int ret = ck_rhs_put_robin_hood(hs, first, desc2); if (slot != -1) desc->in_rh = false; if (CK_CC_UNLIKELY(ret == 1)) goto restart; if (CK_CC_UNLIKELY(ret == -1)) return false; /* If an earlier bucket was found, then store entry there. */ ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert); desc2->probes = n_probes; /* * If a duplicate key was found, then delete it after * signaling concurrent probes to restart. Optionally, * it is possible to install tombstone after grace * period if we can guarantee earlier position of * duplicate key. */ ck_rhs_add_wanted(hs, first, -1, h); if (object != NULL) { ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]); ck_pr_fence_atomic_store(); ck_rhs_do_backward_shift_delete(hs, slot); } } else { /* * If we are storing into same slot, then atomic store is sufficient * for replacement. */ ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert); ck_rhs_set_probes(map, slot, n_probes); if (object == NULL) ck_rhs_add_wanted(hs, slot, -1, h); } if (object == NULL) { map->n_entries++; if ((map->n_entries ) > map->max_entries) ck_rhs_grow(hs, map->capacity << 1); } *previous = CK_CC_DECONST_PTR(object); return true; } static bool ck_rhs_put_internal(struct ck_rhs *hs, unsigned long h, const void *key, enum ck_rhs_probe_behavior behavior) { long slot, first; const void *object; const void *insert; unsigned long n_probes; struct ck_rhs_map *map; restart: map = hs->map; slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, behavior); if (slot == -1 && first == -1) { if (ck_rhs_grow(hs, map->capacity << 1) == false) return false; goto restart; } /* Fail operation if a match was found. */ if (object != NULL) return false; ck_rhs_map_bound_set(map, h, n_probes); insert = ck_rhs_marshal(hs->mode, key, h); if (first != -1) { struct ck_rhs_entry_desc *desc = ck_rhs_desc(map, first); int ret = ck_rhs_put_robin_hood(hs, first, desc); if (CK_CC_UNLIKELY(ret == 1)) return ck_rhs_put_internal(hs, h, key, behavior); else if (CK_CC_UNLIKELY(ret == -1)) return false; /* Insert key into first bucket in probe sequence. */ ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert); desc->probes = n_probes; ck_rhs_add_wanted(hs, first, -1, h); } else { /* An empty slot was found. */ ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert); ck_rhs_set_probes(map, slot, n_probes); ck_rhs_add_wanted(hs, slot, -1, h); } map->n_entries++; if ((map->n_entries ) > map->max_entries) ck_rhs_grow(hs, map->capacity << 1); return true; } bool ck_rhs_put(struct ck_rhs *hs, unsigned long h, const void *key) { return ck_rhs_put_internal(hs, h, key, CK_RHS_PROBE_INSERT); } bool ck_rhs_put_unique(struct ck_rhs *hs, unsigned long h, const void *key) { return ck_rhs_put_internal(hs, h, key, CK_RHS_PROBE_RH); } void * ck_rhs_get(struct ck_rhs *hs, unsigned long h, const void *key) { long first; const void *object; struct ck_rhs_map *map; unsigned long n_probes; unsigned int g, g_p, probe; unsigned int *generation; do { map = ck_pr_load_ptr(&hs->map); generation = &map->generation[h & CK_RHS_G_MASK]; g = ck_pr_load_uint(generation); probe = ck_rhs_map_bound_get(map, h); ck_pr_fence_load(); first = -1; map->probe_func(hs, map, &n_probes, &first, h, key, &object, probe, CK_RHS_PROBE_NO_RH); ck_pr_fence_load(); g_p = ck_pr_load_uint(generation); } while (g != g_p); return CK_CC_DECONST_PTR(object); } void * ck_rhs_remove(struct ck_rhs *hs, unsigned long h, const void *key) { long slot, first; const void *object; struct ck_rhs_map *map = hs->map; unsigned long n_probes; slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, ck_rhs_map_bound_get(map, h), CK_RHS_PROBE_NO_RH); if (object == NULL) return NULL; map->n_entries--; ck_rhs_do_backward_shift_delete(hs, slot); return CK_CC_DECONST_PTR(object); } bool ck_rhs_move(struct ck_rhs *hs, struct ck_rhs *source, ck_rhs_hash_cb_t *hf, ck_rhs_compare_cb_t *compare, struct ck_malloc *m) { if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL) return false; hs->mode = source->mode; hs->seed = source->seed; hs->map = source->map; hs->load_factor = source->load_factor; hs->m = m; hs->hf = hf; hs->compare = compare; return true; } bool ck_rhs_init(struct ck_rhs *hs, unsigned int mode, ck_rhs_hash_cb_t *hf, ck_rhs_compare_cb_t *compare, struct ck_malloc *m, unsigned long n_entries, unsigned long seed) { if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL) return false; hs->m = m; hs->mode = mode; hs->seed = seed; hs->hf = hf; hs->compare = compare; hs->load_factor = CK_RHS_DEFAULT_LOAD_FACTOR; hs->map = ck_rhs_map_create(hs, n_entries); return hs->map != NULL; } ================================================ FILE: third_party/concurrency_kit/ck/tools/feature.sh ================================================ #!/bin/sh # This will generate the list of feature flags for implemented symbols. echo '/* DO NOT EDIT. This is auto-generated from feature.sh */' nm ../regressions/ck_pr/validate/ck_pr_cas|cut -d ' ' -f 3|sed s/ck_pr/ck_f_pr/|awk '/^ck_f_pr/ {print "#define " toupper($1);}'|sort ================================================ FILE: third_party/cram/.coveragerc ================================================ [run] omit = cram/__main__.py cram/_encoding.py scripts/cram source = cram ================================================ FILE: third_party/cram/.gitignore ================================================ *.orig *.rej *~ *.mergebackup *.o *.so *.dll *.py[cdo] *$py.class __pycache__ *.swp *.prof \#*\# .\#* .coverage *,cover htmlcov tests/*.err examples/*.err build dist MANIFEST cram.egg-info .DS_Store tags cscope.* .idea ================================================ FILE: third_party/cram/.hgignore ================================================ syntax: glob *.orig *.rej *~ *.mergebackup *.o *.so *.dll *.py[cdo] *$py.class __pycache__ *.swp *.prof \#*\# .\#* .coverage *,cover htmlcov tests/*.err examples/*.err build dist MANIFEST cram.egg-info .DS_Store tags cscope.* .idea syntax: regexp ^\.pc/ ^\.(pydev)?project ================================================ FILE: third_party/cram/.hgtags ================================================ 931859fdd3e0d5af442a3e9b5fe6ac0dbfed2309 0.1 3c471f7a16b435095b98525e7b851b17e871a2ce 0.2 3c471f7a16b435095b98525e7b851b17e871a2ce 0.2 995a287114b0a2a0bcd79b9c5ce8ff98765e7c8a 0.2 924d14e0636a7ff5815c2412409115a69dfc63f0 0.3 3ba61fadf306c63ec4bc3254522f286a27ac974a 0.4 112e96e43892344954a98b0f05a32819f2b6c20d 0.5 05669fd0420dc0cd52f48bc2f2379a61732d14e0 0.6 e230eb00d4668508766fc32da154ba46c358ff5f 0.7 ================================================ FILE: third_party/cram/.pylintrc ================================================ [MESSAGES CONTROL] # C0330: bad continuation # The design check gives mostly useless advice. # R0201: method could be a function # W0123: eval used # W0141: used range # W0142: * or ** arguments # W0201: attribute defined outside of __init__ # W0640: unreliable closure/loop variable checking disable=C0330,design,R0201,W0123,W0141,W0142,W0201,W0640 [REPORTS] reports=no [TYPECHECK] ignored-classes= generated-members= [BASIC] const-rgx=(([a-zA-Z_][a-zA-Z0-9_]{2,30})|(__[a-z0-9_]{2,30}__))$ class-rgx=[a-zA-Z_][a-zA-Z0-9]{2,30}$ function-rgx=[a-z_][a-z0-9_]{2,30}$ method-rgx=[a-z_][a-z0-9_]{2,30}$ attr-rgx=[a-z_][a-z0-9_]{0,30}$ argument-rgx=[a-z_][a-z0-9_]{0,30}$ variable-rgx=[a-z_][a-z0-9_]{0,30}$ inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ [CLASSES] ignore-iface-methods= defining-attr-methods=__init__,__new__ [IMPORTS] deprecated-modules=regsub,TERMIOS,Bastion,rexec [FORMAT] max-line-length=79 max-module-lines=5000 [MISCELLANEOUS] notes=FIXME,XXX,TODO ================================================ FILE: third_party/cram/.travis.yml ================================================ language: python matrix: allow_failures: - python: nightly env: TESTOPTS=--shell=dash - python: pypy env: TESTOPTS=--shell=dash - python: pypy3 env: TESTOPTS=--shell=dash include: - python: "3.5" env: TESTOPTS=--shell=dash - python: "3.5" env: TESTOPTS=--shell=bash - python: "3.5" env: TESTOPTS=--shell=zsh addons: apt: packages: - zsh - python: "3.4" env: TESTOPTS=--shell=dash - python: "3.3" env: TESTOPTS=--shell=dash - python: "3.2" env: TESTOPTS=--shell=dash - python: "2.7" env: TESTOPTS=--shell=dash - python: "2.6" env: TESTOPTS=--shell=dash - env: PYTHON=2.5 TESTOPTS=--shell=dash addons: apt: sources: - deadsnakes packages: - python2.5 - env: PYTHON=2.4 TESTOPTS=--shell=dash addons: apt: sources: - deadsnakes packages: - python2.4 - python: nightly env: TESTOPTS=--shell=dash - python: pypy env: TESTOPTS=--shell=dash - python: pypy3 env: TESTOPTS=--shell=dash fast_finish: true install: | if [ -z "$PYTHON" ] then [ "$TRAVIS_PYTHON_VERSION" = "3.2" ] && pip install coverage==3.7.1 pip install -r requirements.txt fi script: | if [ -z "$PYTHON" ] then make test TESTOPTS="$TESTOPTS" else make quicktest PYTHON="python$PYTHON" fi ================================================ FILE: third_party/cram/COPYING.txt ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: third_party/cram/MANIFEST.in ================================================ include .coveragerc .pylintrc .travis.yml Makefile MANIFEST.in include *.md *.rst *.txt contrib/* scripts/* exclude contrib/PKGBUILD recursive-include examples *.t recursive-include tests *.py *.sh *.t ================================================ FILE: third_party/cram/NEWS.rst ================================================ ====== News ====== Version 0.7 (Feb. 24, 2016) --------------------------- * Added the ``-d``/``--debug`` flag that disables diffing of expected/actual output and instead passes through script output to ``stdout``/``stderr``. * Added the ``--shell-opts`` flag for specifying flags to invoke the shell with. By setting ``--shell-opts='-x'`` and ``--debug`` together, this can be used to see shell commands as they're run and their output in real time which can be useful for debugging slow or hanging tests. * Added xUnit XML output support (for better integration of test results with Bamboo and other continuous integration tools). * Added support for using (esc) on expected out lines that aren't automatically escaped in actual output. * Added the ``$TESTSHELL`` environment variable. This allows a test to portably check what shell it was invoked with. * Added an error message for when no tests are found in a directory. * Changed ``Makefile`` to install into ``/usr/local`` by default. * Simplified the ``Makefile``'s targets. The targets available now are ``all``, ``build``, ``check``/``test``, ``clean``, ``dist``, ``install``, and ``quicktest`` (for running the test suite without checking test coverage). * Fixed non-ASCII strings not being escaped with ``(esc)`` on Python 3. * Fixed a crash on tests that don't have a trailing newline. * Fixed a crash when using ``set -x`` with zsh. Version 0.6 (Aug. 1, 2013) -------------------------- * Added the long option ``--preserve-env`` for ``-E``. * Added support for specifying options in ``.cramrc`` (configurable with the ``CRAMRC`` environment variable). * Added a ``--shell`` option to change the shell tests are run with. Contributed by `Kamil Kisiel`_. * Added Arch Linux package metadata (in ``contrib/``). Contributed by `Andrey Vlasovskikh`_. * Fixed shell commands unintentionally inheriting Python's ``SIGPIPE`` handler (causing commands that close pipes to print ``broken pipe`` messages). * Fixed ``EPIPE`` under PyPy when applying patches in ``--interactive`` mode. * Added ``TESTFILE`` test environment variable (set to the name of the current test). * Fixed GNU patch 2.7 compatibility by using relative paths instead of absolute paths. Contributed by `Douglas Creager`_. * Fixed name clashes in temporary test directories (e.g., when running two tests with the same name in different folders). * **Backwards compatibility:** Fixed improper usage of the subprocess library under Python 3. This fixes Python 3.3 support, but breaks support for Python 3.1-3.2.3 due to a bug in Python. If you're using Python 3.0-3.2, you must upgrade to Python 3.2.4 or newer. .. _Kamil Kisiel: http://kamilkisiel.net/ .. _Andrey Vlasovskikh: https://twitter.com/vlasovskikh .. _Douglas Creager: http://dcreager.net/ Version 0.5 (Jan. 8, 2011) -------------------------- * **The test format has changed:** Matching output not ending in a newline now requires the ``(no-eol)`` keyword instead of ending the line in ``%``. * Matching output containing unprintable characters now requires the ``(esc)`` keyword. Real output containing unprintable characters will automatically receive ``(esc)``. * If an expected line matches its real output line exactly, special matching like ``(re)`` or ``(glob)`` will be ignored. * Regular expressions ending in a trailing backslash are now considered invalid. * Added an ``--indent`` option for changing the default amount of indentation required to specify commands and output. * Added support for specifying command line options in the ``CRAM`` environment variable. * The ``--quiet`` and ``--verbose`` options can now be used together. * When running Cram under Python 3, Unicode-specific line break characters will no longer be parsed as newlines. * Tests are no longer required to end in a trailing newline. Version 0.4 (Sep. 28, 2010) --------------------------- * **The test format has changed:** Output lines containing regular expressions must now end in ``(re)`` or they'll be matched literally. Lines ending with keywords are matched literally first, however. * Regular expressions are now matched from beginning to end. In other words ``\d (re)`` is matched as ``^\d$``. * In addition to ``(re)``, ``(glob)`` has been added. It supports ``*``, ``?``, and escaping both characters (and backslashes) using ``\``. * **Environment settings have changed:** The ``-D`` flag has been removed, ``$TESTDIR`` is now set to the directory containing the ``.t`` file, and ``$CRAMTMP`` is set to the test runner's temporary directory. * ``-i``/``--interactive`` now requires ``patch(1)``. Instead of ``.err`` files replacing ``.t`` files during merges, diffs are applied using ``patch(1)``. This prevents matching regular expressions and globs from getting clobbered. * Previous ``.err`` files are now removed when tests pass. * Cram now exits with return code ``1`` if any tests failed. * If a test exits with return code ``80``, it's considered a skipped a test. This is useful for intentionally disabling tests when they only work on certain platforms or in certain settings. * The number of tests, the number of skipped tests, and the number of failed tests are now printed after all tests are finished. * Added ``-q``/``--quiet`` to suppress diff output. * Added `contrib/cram.vim`_ syntax file for Vim. Contributed by `Steve Losh`_. .. _contrib/cram.vim: https://bitbucket.org/brodie/cram/src/default/contrib/cram.vim .. _Steve Losh: http://stevelosh.com/ Version 0.3 (Sep. 20, 2010) --------------------------- * Implemented resetting of common environment variables. This behavior can be disabled using the ``-E`` flag. * Changed the test runner to first make its own overall random temporary directory, make ``tmp`` inside of it and set ``TMPDIR``, etc. to its path, and run each test with a random temporary working directory inside of that. * Added ``--keep-tmpdir``. Temporary directories are named by test filename (along with a random string). * Added ``-i``/``--interactive`` to merge actual output back to into tests interactively. * Added ability to match command output not ending in a newline by suffixing output in the test with ``%``. Version 0.2 (Sep. 19, 2010) --------------------------- * Changed the test runner to run tests with a random temporary working directory. Version 0.1 (Sep. 19, 2010) --------------------------- * Initial release. ================================================ FILE: third_party/cram/README.rst ================================================ ====================== Cram: It's test time ====================== Cram is a functional testing framework for command line applications. Cram tests look like snippets of interactive shell sessions. Cram runs each command and compares the command output in the test with the command's actual output. Here's a snippet from `Cram's own test suite`_:: The $PYTHON environment variable should be set when running this test from Python. $ [ -n "$PYTHON" ] || PYTHON="`which python`" $ [ -n "$PYTHONPATH" ] || PYTHONPATH="$TESTDIR/.." && export PYTHONPATH $ if [ -n "$COVERAGE" ]; then > coverage erase > alias cram="`which coverage` run --branch -a $TESTDIR/../scripts/cram" > else > alias cram="$PYTHON $TESTDIR/../scripts/cram" > fi $ command -v md5 > /dev/null || alias md5=md5sum Usage: $ cram -h [Uu]sage: cram \[OPTIONS\] TESTS\.\.\. (re) [Oo]ptions: (re) -h, --help show this help message and exit -V, --version show version information and exit -q, --quiet don't print diffs -v, --verbose show filenames and test status -i, --interactive interactively merge changed test output -d, --debug write script output directly to the terminal -y, --yes answer yes to all questions -n, --no answer no to all questions -E, --preserve-env don't reset common environment variables -e, --no-err-files don't write .err files on test failures --keep-tmpdir keep temporary directories --shell=PATH shell to use for running tests (default: /bin/sh) --shell-opts=OPTS arguments to invoke shell with --indent=NUM number of spaces to use for indentation (default: 2) --xunit-file=PATH path to write xUnit XML output The format in a nutshell: * Cram tests use the ``.t`` file extension. * Lines beginning with two spaces, a dollar sign, and a space are run in the shell. * Lines beginning with two spaces, a greater than sign, and a space allow multi-line commands. * All other lines beginning with two spaces are considered command output. * Output lines ending with a space and the keyword ``(re)`` are matched as `Perl-compatible regular expressions`_. * Lines ending with a space and the keyword ``(glob)`` are matched with a glob-like syntax. The only special characters supported are ``*`` and ``?``. Both characters can be escaped using ``\``, and the backslash can be escaped itself. * Output lines ending with either of the above keywords are always first matched literally with actual command output. * Lines ending with a space and the keyword ``(no-eol)`` will match actual output that doesn't end in a newline. * Actual output lines containing unprintable characters are escaped and suffixed with a space and the keyword ``(esc)``. Lines matching unprintable output must also contain the keyword. * Anything else is a comment. .. _Cram's own test suite: https://bitbucket.org/brodie/cram/src/0.6/tests/cram.t .. _Perl-compatible regular expressions: https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions Download -------- * `cram-0.7.tar.gz`_ (32 KB, requires Python 2.4-2.7 or Python 3.1 or newer) .. _cram-0.7.tar.gz: https://bitheap.org/cram/cram-0.7.tar.gz Installation ------------ Install Cram using make:: $ wget https://bitheap.org/cram/cram-0.7.tar.gz $ tar zxvf cram-0.7.tar.gz $ cd cram-0.7 $ make install Usage ----- Cram will print a dot for each passing test. If a test fails, a `unified context diff`_ is printed showing the test's expected output and the actual output. Skipped tests (empty tests and tests that exit with return code ``80``) are marked with ``s`` instead of a dot. For example, if we run Cram on `its own example tests`_:: .s.! --- examples/fail.t +++ examples/fail.t.err @@ -3,21 +3,22 @@ $ echo 1 1 $ echo 1 - 2 + 1 $ echo 1 1 Invalid regex: $ echo 1 - +++ (re) + 1 Offset regular expression: $ printf 'foo\nbar\nbaz\n\n1\nA\n@\n' foo + bar baz \d (re) [A-Z] (re) - # + @ s. # Ran 6 tests, 2 skipped, 1 failed. Unless run with ``-e`` or ``--no-err-files``, Cram will also write the test with its actual output to ``examples/fail.t.err``, allowing you to use other diff tools. This file is automatically removed the next time the test passes. When you're first writing a test, you might just write the commands and run the test to see what happens. If you run Cram with ``-i`` or ``--interactive``, you'll be prompted to merge the actual output back into the test. This makes it easy to quickly prototype new tests. You can specify a default set of options by creating a ``.cramrc`` file. For example:: [cram] verbose = True indent = 4 Is the same as invoking Cram with ``--verbose`` and ``--indent=4``. To change what configuration file Cram loads, you can set the ``CRAMRC`` environment variable. You can also specify command line options in the ``CRAM`` environment variable. Note that the following environment variables are reset before tests are run: * ``TMPDIR``, ``TEMP``, and ``TMP`` are set to the test runner's ``tmp`` directory. * ``LANG``, ``LC_ALL``, and ``LANGUAGE`` are set to ``C``. * ``TZ`` is set to ``GMT``. * ``COLUMNS`` is set to ``80``. (Note: When using ``--shell=zsh``, this cannot be reset. It will reflect the actual terminal's width.) * ``CDPATH`` and ``GREP_OPTIONS`` are set to an empty string. Cram also provides the following environment variables to tests: * ``CRAMTMP``, set to the test runner's temporary directory. * ``TESTDIR``, set to the directory containing the test file. * ``TESTFILE``, set to the basename of the current test file. * ``TESTSHELL``, set to the value specified by ``--shell``. Also note that care should be taken with commands that close the test shell's ``stdin``. For example, if you're trying to invoke ``ssh`` in a test, try adding the ``-n`` option to prevent it from closing ``stdin``. Similarly, if you invoke a daemon process that inherits ``stdout`` and fails to close it, it may cause Cram to hang while waiting for the test shell's ``stdout`` to be fully closed. .. _unified context diff: https://en.wikipedia.org/wiki/Diff#Unified_format .. _its own example tests: https://bitbucket.org/brodie/cram/src/default/examples/ Development ----------- Download the official development repository using Mercurial_:: hg clone https://bitbucket.org/brodie/cram Or Git_:: git clone https://github.com/brodie/cram.git Test Cram using Cram:: pip install -r requirements.txt make test Visit Bitbucket_ or GitHub_ if you'd like to fork the project, watch for new changes, or report issues. .. _Mercurial: http://mercurial.selenic.com/ .. _Git: http://git-scm.com/ .. _coverage.py: http://nedbatchelder.com/code/coverage/ .. _Bitbucket: https://bitbucket.org/brodie/cram .. _GitHub: https://github.com/brodie/cram ================================================ FILE: third_party/cram/TODO.md ================================================ * Add more comments explaining how different parts of the code work. * Add a man page. * Implement string substitutions (e.g., --substitute=FOOPORT=123). * Conditionals (e.g., --define=windows=1, #if windows ... #else ... #endif). * Support #!/usr/bin/env cram * Support .cramrc in test directories. Though, if I do this, what happens when there are multiple .cramrc files? Does the deepest one completely override the others? Do they merge together? * Homebrew formula. * Debian, Ubuntu, CentOS/RHEL repos. * Implement a test that does stricter style guide testing. * Write contributor guidelines. * Get the test suite running on AppVeyor under MSYS2. - http://help.appveyor.com/discussions/suggestions/615-support-for-msys2 - https://github.com/behdad/harfbuzz/pull/112/files - https://github.com/khaledhosny/ots/pull/67/files - https://github.com/appveyor/ci/issues/352#issuecomment-138149606 - https://github.com/appveyor/ci/issues/597 - http://www.appveyor.com * Get the test suite fully passing with Python.org's Windows distribution. * Global setup/teardown support. * Local setup/teardown? This is technically already supported via sourcing scripts and using exit traps, but dedicated syntax might be nice (e.g., #setup ... #endsetup? or maybe just #teardown ... #endteardown or #finally ... #endfinally?). * Implement -j flag for concurrency. * Flexible indentation support (with an algorithm similar to Python's for detecting indentation on a per-block basis). * Some sort of plugin system (one that doesn't require writing plugins in Python) that allows basic extension of Cram's functionality (and possibly even syntax, though perhaps limited to just "macros" like #foo, #bar, etc. and matchers like (baz), (quux), etc.). * Be able to run the Mercurial test suite. * Write cram plugins for other testing frameworks (nose, py.test, etc.). * Somehow make it possible to specify tests in Python doc strings (and similar things in other languages like Perl, Ruby, etc.). * Emacs mode. ================================================ FILE: third_party/cram/contrib/PKGBUILD ================================================ # Maintainer: Andrey Vlasovskikh pkgname=cram pkgver=0.7 pkgrel=1 pkgdesc="Functional tests for command line applications" arch=(any) url="https://bitheap.org/cram/" license=('GPL') depends=('python') source=("https://pypi.python.org/packages/source/c/cram/cram-$pkgver.tar.gz") md5sums=('2ea37ada5190526b9bcaac5e4099221c') build() { cd "$srcdir/$pkgname-$pkgver" python setup.py install --root="$pkgdir/" --optimize=1 } ================================================ FILE: third_party/cram/contrib/cram.vim ================================================ " Vim syntax file " Language: Cram Tests " Author: Steve Losh (steve@stevelosh.com) " " Add the following line to your ~/.vimrc to enable: " au BufNewFile,BufRead *.t set filetype=cram " " If you want folding you'll need the following line as well: " let cram_fold=1 " " You might also want to set the starting foldlevel for Cram files: " autocmd Syntax cram setlocal foldlevel=1 if exists("b:current_syntax") finish endif syn include @Shell syntax/sh.vim syn match cramComment /^[^ ].*$/ contains=@Spell syn region cramOutput start=/^ [^$>]/ start=/^ $/ end=/\v.(\n\n*[^ ])\@=/me=s end=/^ [$>]/me=e-3 end=/^$/ fold containedin=cramBlock syn match cramCommandStart /^ \$ / containedin=cramCommand syn region cramCommand start=/^ \$ /hs=s+4,rs=s+4 end=/^ [^>]/me=e-3 end=/^ $/me=e-2 containedin=cramBlock contains=@Shell keepend syn region cramBlock start=/^ /ms=e-2 end=/\v.(\n\n*[^ ])\@=/me=s end=/^$/me=e-1 fold keepend hi link cramCommandStart Keyword hi link cramComment Normal hi link cramOutput Comment if exists("cram_fold") setlocal foldmethod=syntax endif syn sync match cramSync grouphere NONE "^$" syn sync maxlines=200 " It's okay to set tab settings here, because an indent of two spaces is specified " by the file format. setlocal tabstop=2 softtabstop=2 shiftwidth=2 expandtab let b:current_syntax = "cram" ================================================ FILE: third_party/cram/cram/__init__.py ================================================ """Functional testing framework for command line applications""" from cram._main import main from cram._test import test, testfile __all__ = ['main', 'test', 'testfile'] ================================================ FILE: third_party/cram/cram/__main__.py ================================================ """Main module (invoked by "python -m cram")""" import sys import cram try: sys.exit(cram.main(sys.argv[1:])) except KeyboardInterrupt: pass ================================================ FILE: third_party/cram/cram/_cli.py ================================================ """The command line interface implementation""" import os import sys from cram._encoding import b, bytestype, stdoutb from cram._process import execute __all__ = ['runcli'] def _prompt(question, answers, auto=None): """Write a prompt to stdout and ask for answer in stdin. answers should be a string, with each character a single answer. An uppercase letter is considered the default answer. If an invalid answer is given, this asks again until it gets a valid one. If auto is set, the question is answered automatically with the specified value. """ default = [c for c in answers if c.isupper()] while True: sys.stdout.write('%s [%s] ' % (question, answers)) sys.stdout.flush() if auto is not None: sys.stdout.write(auto + '\n') sys.stdout.flush() return auto answer = sys.stdin.readline().strip().lower() if not answer and default: return default[0] elif answer and answer in answers.lower(): return answer def _log(msg=None, verbosemsg=None, verbose=False): """Write msg to standard out and flush. If verbose is True, write verbosemsg instead. """ if verbose: msg = verbosemsg if msg: if isinstance(msg, bytestype): stdoutb.write(msg) else: # pragma: nocover sys.stdout.write(msg) sys.stdout.flush() def _patch(cmd, diff): """Run echo [lines from diff] | cmd -p0""" out, retcode = execute([cmd, '-p0'], stdin=b('').join(diff)) return retcode == 0 def runcli(tests, quiet=False, verbose=False, patchcmd=None, answer=None, noerrfiles=False): """Run tests with command line interface input/output. tests should be a sequence of 2-tuples containing the following: (test path, test function) This function yields a new sequence where each test function is wrapped with a function that handles CLI input/output. If quiet is True, diffs aren't printed. If verbose is True, filenames and status information are printed. If patchcmd is set, a prompt is written to stdout asking if changed output should be merged back into the original test. The answer is read from stdin. If 'y', the test is patched using patch based on the changed output. """ total, skipped, failed = [0], [0], [0] for path, test in tests: def testwrapper(): """Test function that adds CLI output""" total[0] += 1 _log(None, path + b(': '), verbose) refout, postout, diff = test() if refout is None: skipped[0] += 1 _log('s', 'empty\n', verbose) return refout, postout, diff abspath = os.path.abspath(path) errpath = abspath + b('.err') if postout is None: skipped[0] += 1 _log('s', 'skipped\n', verbose) elif not diff: _log('.', 'passed\n', verbose) if os.path.exists(errpath): os.remove(errpath) else: failed[0] += 1 _log('!', 'failed\n', verbose) if not quiet: _log('\n', None, verbose) if not noerrfiles: errfile = open(errpath, 'wb') try: for line in postout: errfile.write(line) finally: errfile.close() if not quiet: origdiff = diff diff = [] for line in origdiff: stdoutb.write(line) diff.append(line) if (patchcmd and _prompt('Accept this change?', 'yN', answer) == 'y'): if _patch(patchcmd, diff): _log(None, path + b(': merged output\n'), verbose) if not noerrfiles: os.remove(errpath) else: _log(path + b(': merge failed\n')) return refout, postout, diff yield (path, testwrapper) if total[0] > 0: _log('\n', None, verbose) _log('# Ran %s tests, %s skipped, %s failed.\n' % (total[0], skipped[0], failed[0])) ================================================ FILE: third_party/cram/cram/_diff.py ================================================ """Utilities for diffing test files and their output""" import codecs import difflib import re from cram._encoding import b __all__ = ['esc', 'glob', 'regex', 'unified_diff'] def _regex(pattern, s): """Match a regular expression or return False if invalid. >>> from cram._encoding import b >>> [bool(_regex(r, b('foobar'))) for r in (b('foo.*'), b('***'))] [True, False] """ try: return re.match(pattern + b(r'\Z'), s) except re.error: return False def _glob(el, l): r"""Match a glob-like pattern. The only supported special characters are * and ?. Escaping is supported. >>> from cram._encoding import b >>> bool(_glob(b(r'\* \\ \? fo?b*'), b('* \\ ? foobar'))) True """ i, n = 0, len(el) res = b('') while i < n: c = el[i:i + 1] i += 1 if c == b('\\') and el[i] in b('*?\\'): res += el[i - 1:i + 1] i += 1 elif c == b('*'): res += b('.*') elif c == b('?'): res += b('.') else: res += re.escape(c) return _regex(res, l) def _matchannotation(keyword, matchfunc, el, l): """Apply match function based on annotation keyword""" ann = b(' (%s)\n' % keyword) return el.endswith(ann) and matchfunc(el[:-len(ann)], l[:-1]) def regex(el, l): """Apply a regular expression match to a line annotated with '(re)'""" return _matchannotation('re', _regex, el, l) def glob(el, l): """Apply a glob match to a line annotated with '(glob)'""" return _matchannotation('glob', _glob, el, l) def esc(el, l): """Apply an escape match to a line annotated with '(esc)'""" ann = b(' (esc)\n') if el.endswith(ann): el = codecs.escape_decode(el[:-len(ann)])[0] + b('\n') if el == l: return True if l.endswith(ann): l = codecs.escape_decode(l[:-len(ann)])[0] + b('\n') return el == l class _SequenceMatcher(difflib.SequenceMatcher, object): """Like difflib.SequenceMatcher, but supports custom match functions""" def __init__(self, *args, **kwargs): self._matchers = kwargs.pop('matchers', []) super(_SequenceMatcher, self).__init__(*args, **kwargs) def _match(self, el, l): """Tests for matching lines using custom matchers""" for matcher in self._matchers: if matcher(el, l): return True return False def find_longest_match(self, alo, ahi, blo, bhi): """Find longest matching block in a[alo:ahi] and b[blo:bhi]""" # SequenceMatcher uses find_longest_match() to slowly whittle down # the differences between a and b until it has each matching block. # Because of this, we can end up doing the same matches many times. matches = [] for n, (el, line) in enumerate(zip(self.a[alo:ahi], self.b[blo:bhi])): if el != line and self._match(el, line): # This fools the superclass's method into thinking that the # regex/glob in a is identical to b by replacing a's line (the # expected output) with b's line (the actual output). self.a[alo + n] = line matches.append((n, el)) ret = super(_SequenceMatcher, self).find_longest_match(alo, ahi, blo, bhi) # Restore the lines replaced above. Otherwise, the diff output # would seem to imply that the tests never had any regexes/globs. for n, el in matches: self.a[alo + n] = el return ret def unified_diff(l1, l2, fromfile=b(''), tofile=b(''), fromfiledate=b(''), tofiledate=b(''), n=3, lineterm=b('\n'), matchers=None): r"""Compare two sequences of lines; generate the delta as a unified diff. This is like difflib.unified_diff(), but allows custom matchers. >>> from cram._encoding import b >>> l1 = [b('a\n'), b('? (glob)\n')] >>> l2 = [b('a\n'), b('b\n')] >>> (list(unified_diff(l1, l2, b('f1'), b('f2'), b('1970-01-01'), ... b('1970-01-02'))) == ... [b('--- f1\t1970-01-01\n'), b('+++ f2\t1970-01-02\n'), ... b('@@ -1,2 +1,2 @@\n'), b(' a\n'), b('-? (glob)\n'), b('+b\n')]) True >>> from cram._diff import glob >>> list(unified_diff(l1, l2, matchers=[glob])) [] """ if matchers is None: matchers = [] started = False matcher = _SequenceMatcher(None, l1, l2, matchers=matchers) for group in matcher.get_grouped_opcodes(n): if not started: if fromfiledate: fromdate = b('\t') + fromfiledate else: fromdate = b('') if tofiledate: todate = b('\t') + tofiledate else: todate = b('') yield b('--- ') + fromfile + fromdate + lineterm yield b('+++ ') + tofile + todate + lineterm started = True i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4] yield (b("@@ -%d,%d +%d,%d @@" % (i1 + 1, i2 - i1, j1 + 1, j2 - j1)) + lineterm) for tag, i1, i2, j1, j2 in group: if tag == 'equal': for line in l1[i1:i2]: yield b(' ') + line continue if tag == 'replace' or tag == 'delete': for line in l1[i1:i2]: yield b('-') + line if tag == 'replace' or tag == 'insert': for line in l2[j1:j2]: yield b('+') + line ================================================ FILE: third_party/cram/cram/_encoding.py ================================================ """Encoding utilities""" import os import sys try: import builtins except ImportError: import __builtin__ as builtins __all__ = ['b', 'bchr', 'bytestype', 'envencode', 'fsdecode', 'fsencode', 'stdoutb', 'stderrb', 'u', 'ul', 'unicodetype'] bytestype = getattr(builtins, 'bytes', str) unicodetype = getattr(builtins, 'unicode', str) if getattr(os, 'fsdecode', None) is not None: fsdecode = os.fsdecode fsencode = os.fsencode elif bytestype is not str: if sys.platform == 'win32': def fsdecode(s): """Decode a filename from the filesystem encoding""" if isinstance(s, unicodetype): return s encoding = sys.getfilesystemencoding() if encoding == 'mbcs': return s.decode(encoding) else: return s.decode(encoding, 'surrogateescape') def fsencode(s): """Encode a filename to the filesystem encoding""" if isinstance(s, bytestype): return s encoding = sys.getfilesystemencoding() if encoding == 'mbcs': return s.encode(encoding) else: return s.encode(encoding, 'surrogateescape') else: def fsdecode(s): """Decode a filename from the filesystem encoding""" if isinstance(s, unicodetype): return s return s.decode(sys.getfilesystemencoding(), 'surrogateescape') def fsencode(s): """Encode a filename to the filesystem encoding""" if isinstance(s, bytestype): return s return s.encode(sys.getfilesystemencoding(), 'surrogateescape') else: def fsdecode(s): """Decode a filename from the filesystem encoding""" return s def fsencode(s): """Encode a filename to the filesystem encoding""" return s if bytestype is str: def envencode(s): """Encode a byte string to the os.environ encoding""" return s else: envencode = fsdecode if getattr(sys.stdout, 'buffer', None) is not None: stdoutb = sys.stdout.buffer stderrb = sys.stderr.buffer else: stdoutb = sys.stdout stderrb = sys.stderr if bytestype is str: def b(s): """Convert an ASCII string literal into a bytes object""" return s bchr = chr def u(s): """Convert an ASCII string literal into a unicode object""" return s.decode('ascii') else: def b(s): """Convert an ASCII string literal into a bytes object""" return s.encode('ascii') def bchr(i): """Return a bytes character for a given integer value""" return bytestype([i]) def u(s): """Convert an ASCII string literal into a unicode object""" return s try: eval(r'u""') except SyntaxError: ul = eval else: def ul(e): """Evaluate e as a unicode string literal""" return eval('u' + e) ================================================ FILE: third_party/cram/cram/_main.py ================================================ """Main entry point""" import optparse import os import shlex import shutil import sys import tempfile try: import configparser except ImportError: # pragma: nocover import ConfigParser as configparser from cram._cli import runcli from cram._encoding import b, fsencode, stderrb, stdoutb from cram._run import runtests from cram._xunit import runxunit def _which(cmd): """Return the path to cmd or None if not found""" cmd = fsencode(cmd) for p in os.environ['PATH'].split(os.pathsep): path = os.path.join(fsencode(p), cmd) if os.path.isfile(path) and os.access(path, os.X_OK): return os.path.abspath(path) return None def _expandpath(path): """Expands ~ and environment variables in path""" return os.path.expanduser(os.path.expandvars(path)) class _OptionParser(optparse.OptionParser): """Like optparse.OptionParser, but supports setting values through CRAM= and .cramrc.""" def __init__(self, *args, **kwargs): self._config_opts = {} optparse.OptionParser.__init__(self, *args, **kwargs) def add_option(self, *args, **kwargs): option = optparse.OptionParser.add_option(self, *args, **kwargs) if option.dest and option.dest != 'version': key = option.dest.replace('_', '-') self._config_opts[key] = option.action == 'store_true' return option def parse_args(self, args=None, values=None): config = configparser.RawConfigParser() config.read(_expandpath(os.environ.get('CRAMRC', '.cramrc'))) defaults = {} for key, isbool in self._config_opts.items(): try: if isbool: try: value = config.getboolean('cram', key) except ValueError: value = config.get('cram', key) self.error('--%s: invalid boolean value: %r' % (key, value)) else: value = config.get('cram', key) except (configparser.NoSectionError, configparser.NoOptionError): pass else: defaults[key] = value self.set_defaults(**defaults) eargs = os.environ.get('CRAM', '').strip() if eargs: args = args or [] args += shlex.split(eargs) try: return optparse.OptionParser.parse_args(self, args, values) except optparse.OptionValueError: self.error(str(sys.exc_info()[1])) def _parseopts(args): """Parse command line arguments""" p = _OptionParser(usage='cram [OPTIONS] TESTS...', prog='cram') p.add_option('-V', '--version', action='store_true', help='show version information and exit') p.add_option('-q', '--quiet', action='store_true', help="don't print diffs") p.add_option('-v', '--verbose', action='store_true', help='show filenames and test status') p.add_option('-i', '--interactive', action='store_true', help='interactively merge changed test output') p.add_option('-d', '--debug', action='store_true', help='write script output directly to the terminal') p.add_option('-y', '--yes', action='store_true', help='answer yes to all questions') p.add_option('-n', '--no', action='store_true', help='answer no to all questions') p.add_option('-E', '--preserve-env', action='store_true', help="don't reset common environment variables") p.add_option('-e', '--no-err-files', action='store_true', help="don't write .err files on test failures") p.add_option('--keep-tmpdir', action='store_true', help='keep temporary directories') p.add_option('--shell', action='store', default='/bin/sh', metavar='PATH', help='shell to use for running tests (default: %default)') p.add_option('--shell-opts', action='store', metavar='OPTS', help='arguments to invoke shell with') p.add_option('--indent', action='store', default=2, metavar='NUM', type='int', help=('number of spaces to use for indentation ' '(default: %default)')) p.add_option('--xunit-file', action='store', metavar='PATH', help='path to write xUnit XML output') opts, paths = p.parse_args(args) paths = [fsencode(path) for path in paths] return opts, paths, p.get_usage def main(args): """Main entry point. If you're thinking of using Cram in other Python code (e.g., unit tests), consider using the test() or testfile() functions instead. :param args: Script arguments (excluding script name) :type args: str :return: Exit code (non-zero on failure) :rtype: int """ opts, paths, getusage = _parseopts(args) if opts.version: sys.stdout.write("""Cram CLI testing framework (version 0.7) Copyright (C) 2010-2016 Brodie Rao and others This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. """) return conflicts = [('--yes', opts.yes, '--no', opts.no), ('--quiet', opts.quiet, '--interactive', opts.interactive), ('--debug', opts.debug, '--quiet', opts.quiet), ('--debug', opts.debug, '--interactive', opts.interactive), ('--debug', opts.debug, '--verbose', opts.verbose), ('--debug', opts.debug, '--xunit-file', opts.xunit_file)] for s1, o1, s2, o2 in conflicts: if o1 and o2: sys.stderr.write('options %s and %s are mutually exclusive\n' % (s1, s2)) return 2 shellcmd = _which(opts.shell) if not shellcmd: stderrb.write(b('shell not found: ') + fsencode(opts.shell) + b('\n')) return 2 shell = [shellcmd] if opts.shell_opts: shell += shlex.split(opts.shell_opts) patchcmd = None if opts.interactive: patchcmd = _which('patch') if not patchcmd: sys.stderr.write('patch(1) required for -i\n') return 2 if not paths: sys.stdout.write(getusage()) return 2 badpaths = [path for path in paths if not os.path.exists(path)] if badpaths: stderrb.write(b('no such file: ') + badpaths[0] + b('\n')) return 2 if opts.yes: answer = 'y' elif opts.no: answer = 'n' else: answer = None tmpdir = os.environ['CRAMTMP'] = tempfile.mkdtemp('', 'cramtests-') tmpdirb = fsencode(tmpdir) proctmp = os.path.join(tmpdir, 'tmp') for s in ('TMPDIR', 'TEMP', 'TMP'): os.environ[s] = proctmp os.mkdir(proctmp) try: tests = runtests(paths, tmpdirb, shell, indent=opts.indent, cleanenv=not opts.preserve_env, debug=opts.debug, noerrfiles=opts.no_err_files) if not opts.debug: tests = runcli(tests, quiet=opts.quiet, verbose=opts.verbose, patchcmd=patchcmd, answer=answer, noerrfiles=opts.no_err_files) if opts.xunit_file is not None: tests = runxunit(tests, opts.xunit_file) hastests = False failed = False for path, test in tests: hastests = True refout, postout, diff = test() if diff: failed = True if not hastests: sys.stderr.write('no tests found\n') return 2 return int(failed) finally: if opts.keep_tmpdir: stdoutb.write(b('# Kept temporary directory: ') + tmpdirb + b('\n')) else: shutil.rmtree(tmpdir) ================================================ FILE: third_party/cram/cram/_process.py ================================================ """Utilities for running subprocesses""" import os import signal import subprocess import sys from cram._encoding import fsdecode __all__ = ['PIPE', 'STDOUT', 'execute'] PIPE = subprocess.PIPE STDOUT = subprocess.STDOUT def _makeresetsigpipe(): """Make a function to reset SIGPIPE to SIG_DFL (for use in subprocesses). Doing subprocess.Popen(..., preexec_fn=makeresetsigpipe()) will prevent Python's SIGPIPE handler (SIG_IGN) from being inherited by the child process. """ if (sys.platform == 'win32' or getattr(signal, 'SIGPIPE', None) is None): # pragma: nocover return None return lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL) def execute(args, stdin=None, stdout=None, stderr=None, cwd=None, env=None): """Run a process and return its output and return code. stdin may either be None or a string to send to the process. stdout may either be None or PIPE. If set to PIPE, the process's output is returned as a string. stderr may either be None or STDOUT. If stdout is set to PIPE and stderr is set to STDOUT, the process's stderr output will be interleaved with stdout and returned as a string. cwd sets the process's current working directory. env can be set to a dictionary to override the process's environment variables. This function returns a 2-tuple of (output, returncode). """ if sys.platform == 'win32': # pragma: nocover args = [fsdecode(arg) for arg in args] p = subprocess.Popen(args, stdin=PIPE, stdout=stdout, stderr=stderr, cwd=cwd, env=env, bufsize=-1, preexec_fn=_makeresetsigpipe(), close_fds=os.name == 'posix') out, err = p.communicate(stdin) return out, p.returncode ================================================ FILE: third_party/cram/cram/_run.py ================================================ """The test runner""" import os import sys from cram._encoding import b, fsdecode, fsencode from cram._test import testfile __all__ = ['runtests'] if sys.platform == 'win32': # pragma: nocover def _walk(top): top = fsdecode(top) for root, dirs, files in os.walk(top): yield (fsencode(root), [fsencode(p) for p in dirs], [fsencode(p) for p in files]) else: _walk = os.walk def _findtests(paths): """Yield tests in paths in sorted order""" for p in paths: if os.path.isdir(p): for root, dirs, files in _walk(p): if os.path.basename(root).startswith(b('.')): continue for f in sorted(files): if not f.startswith(b('.')) and f.endswith(b('.t')): yield os.path.normpath(os.path.join(root, f)) else: yield os.path.normpath(p) def runtests(paths, tmpdir, shell, indent=2, cleanenv=True, debug=False, noerrfiles=False): """Run tests and yield results. This yields a sequence of 2-tuples containing the following: (test path, test function) The test function, when called, runs the test in a temporary directory and returns a 3-tuple: (list of lines in the test, same list with actual output, diff) """ cwd = os.getcwd() seen = set() basenames = set() for i, path in enumerate(_findtests(paths)): abspath = os.path.abspath(path) if abspath in seen: continue seen.add(abspath) if not os.stat(path).st_size: yield (path, lambda: (None, None, None)) continue basename = os.path.basename(path) if basename in basenames: basename = basename + b('-%s' % i) else: basenames.add(basename) def test(): """Run test file""" testdir = os.path.join(tmpdir, basename) os.mkdir(testdir) try: os.chdir(testdir) return testfile(abspath, shell, indent=indent, cleanenv=cleanenv, debug=debug, testname=path, noerrfile=noerrfiles) finally: os.chdir(cwd) yield (path, test) ================================================ FILE: third_party/cram/cram/_test.py ================================================ """Utilities for running individual tests""" import itertools import os import re import time from cram._encoding import b, bchr, bytestype, envencode, unicodetype from cram._diff import esc, glob, regex, unified_diff from cram._process import PIPE, STDOUT, execute __all__ = ['test', 'testfile'] _needescape = re.compile(b(r'[\x00-\x09\x0b-\x1f\x7f-\xff]')).search _escapesub = re.compile(b(r'[\x00-\x09\x0b-\x1f\\\x7f-\xff]')).sub _escapemap = dict((bchr(i), b(r'\x%02x' % i)) for i in range(256)) _escapemap.update({b('\\'): b('\\\\'), b('\r'): b(r'\r'), b('\t'): b(r'\t')}) def _escape(s): """Like the string-escape codec, but doesn't escape quotes""" return (_escapesub(lambda m: _escapemap[m.group(0)], s[:-1]) + b(' (esc)\n')) def test(lines, shell='/bin/sh', indent=2, testname=None, env=None, cleanenv=True, debug=False, noerrfile=False): r"""Run test lines and return input, output, and diff. This returns a 3-tuple containing the following: (list of lines in test, same list with actual output, diff) diff is a generator that yields the diff between the two lists. If a test exits with return code 80, the actual output is set to None and diff is set to []. Note that the TESTSHELL environment variable is available in the test (set to the specified shell). However, the TESTDIR and TESTFILE environment variables are not available. To run actual test files, see testfile(). Example usage: >>> from cram._encoding import b >>> refout, postout, diff = test([b(' $ echo hi\n'), ... b(' [a-z]{2} (re)\n')]) >>> refout == [b(' $ echo hi\n'), b(' [a-z]{2} (re)\n')] True >>> postout == [b(' $ echo hi\n'), b(' hi\n')] True >>> bool(diff) False lines may also be a single bytes string: >>> refout, postout, diff = test(b(' $ echo hi\n bye\n')) >>> refout == [b(' $ echo hi\n'), b(' bye\n')] True >>> postout == [b(' $ echo hi\n'), b(' hi\n')] True >>> bool(diff) True >>> (b('').join(diff) == ... b('--- \n+++ \n@@ -1,2 +1,2 @@\n $ echo hi\n- bye\n+ hi\n')) True Note that the b() function is internal to Cram. If you're using Python 2, use normal string literals instead. If you're using Python 3, use bytes literals. :param lines: Test input :type lines: bytes or collections.Iterable[bytes] :param shell: Shell to run test in :type shell: bytes or str or list[bytes] or list[str] :param indent: Amount of indentation to use for shell commands :type indent: int :param testname: Optional test file name (used in diff output) :type testname: bytes or None :param env: Optional environment variables for the test shell :type env: dict or None :param cleanenv: Whether or not to sanitize the environment :type cleanenv: bool :param debug: Whether or not to run in debug mode (don't capture stdout) :type debug: bool :return: Input, output, and diff iterables :rtype: (list[bytes], list[bytes], collections.Iterable[bytes]) """ indent = b(' ') * indent cmdline = indent + b('$ ') conline = indent + b('> ') usalt = 'CRAM%s' % time.time() salt = b(usalt) if env is None: env = os.environ.copy() if cleanenv: for s in ('LANG', 'LC_ALL', 'LANGUAGE'): env[s] = 'C' env['TZ'] = 'GMT' env['CDPATH'] = '' env['COLUMNS'] = '80' env['GREP_OPTIONS'] = '' if isinstance(lines, bytestype): lines = lines.splitlines(True) if isinstance(shell, (bytestype, unicodetype)): shell = [shell] env['TESTSHELL'] = shell[0] if debug: stdin = [] for line in lines: if not line.endswith(b('\n')): line += b('\n') if line.startswith(cmdline): stdin.append(line[len(cmdline):]) elif line.startswith(conline): stdin.append(line[len(conline):]) execute(shell + ['-'], stdin=b('').join(stdin), env=env) return ([], [], []) after = {} refout, postout = [], [] i = pos = prepos = -1 stdin = [] for i, line in enumerate(lines): if not line.endswith(b('\n')): line += b('\n') refout.append(line) if line.startswith(cmdline): after.setdefault(pos, []).append(line) prepos = pos pos = i stdin.append(b('echo %s %s $?\n' % (usalt, i))) stdin.append(line[len(cmdline):]) elif line.startswith(conline): after.setdefault(prepos, []).append(line) stdin.append(line[len(conline):]) elif not line.startswith(indent): after.setdefault(pos, []).append(line) stdin.append(b('echo %s %s $?\n' % (usalt, i + 1))) output, retcode = execute(shell + ['-'], stdin=b('').join(stdin), stdout=PIPE, stderr=STDOUT, env=env) if retcode == 80: return (refout, None, []) pos = -1 ret = 0 for i, line in enumerate(output[:-1].splitlines(True)): out, cmd = line, None if salt in line: out, cmd = line.split(salt, 1) if out: if not out.endswith(b('\n')): out += b(' (no-eol)\n') if _needescape(out): out = _escape(out) postout.append(indent + out) if cmd: ret = int(cmd.split()[1]) if ret != 0: postout.append(indent + b('[%s]\n' % (ret))) postout += after.pop(pos, []) pos = int(cmd.split()[0]) postout += after.pop(pos, []) if testname: diffpath = testname errpath = diffpath + b('.err') else: diffpath = errpath = b('') diff = unified_diff(refout, postout, diffpath, errpath, matchers=[esc, glob, regex]) for firstline in diff: return refout, postout, itertools.chain([firstline], diff) return refout, postout, [] def testfile(path, shell='/bin/sh', indent=2, env=None, cleanenv=True, debug=False, testname=None, noerrfile=False): """Run test at path and return input, output, and diff. This returns a 3-tuple containing the following: (list of lines in test, same list with actual output, diff) diff is a generator that yields the diff between the two lists. If a test exits with return code 80, the actual output is set to None and diff is set to []. Note that the TESTDIR, TESTFILE, and TESTSHELL environment variables are available to use in the test. :param path: Path to test file :type path: bytes or str :param shell: Shell to run test in :type shell: bytes or str or list[bytes] or list[str] :param indent: Amount of indentation to use for shell commands :type indent: int :param env: Optional environment variables for the test shell :type env: dict or None :param cleanenv: Whether or not to sanitize the environment :type cleanenv: bool :param debug: Whether or not to run in debug mode (don't capture stdout) :type debug: bool :param testname: Optional test file name (used in diff output) :type testname: bytes or None :return: Input, output, and diff iterables :rtype: (list[bytes], list[bytes], collections.Iterable[bytes]) """ f = open(path, 'rb') try: abspath = os.path.abspath(path) env = env or os.environ.copy() env['TESTDIR'] = envencode(os.path.dirname(abspath)) env['TESTFILE'] = envencode(os.path.basename(abspath)) if testname is None: # pragma: nocover testname = os.path.basename(abspath) return test(f, shell, indent=indent, testname=testname, env=env, cleanenv=cleanenv, debug=debug, noerrfile=noerrfile) finally: f.close() ================================================ FILE: third_party/cram/cram/_xunit.py ================================================ """xUnit XML output""" import locale import os import re import socket import sys import time from cram._encoding import u, ul __all__ = ['runxunit'] _widecdataregex = ul(r"'(?:[^\x09\x0a\x0d\x20-\ud7ff\ue000-\ufffd" r"\U00010000-\U0010ffff]|]]>)'") _narrowcdataregex = ul(r"'(?:[^\x09\x0a\x0d\x20-\ud7ff\ue000-\ufffd]" r"|]]>)'") _widequoteattrregex = ul(r"'[^\x20\x21\x23-\x25\x27-\x3b\x3d" r"\x3f-\ud7ff\ue000-\ufffd" r"\U00010000-\U0010ffff]'") _narrowquoteattrregex = ul(r"'[^\x20\x21\x23-\x25\x27-\x3b\x3d" r"\x3f-\ud7ff\ue000-\ufffd]'") _replacementchar = ul(r"'\N{REPLACEMENT CHARACTER}'") if sys.maxunicode >= 0x10ffff: # pragma: nocover _cdatasub = re.compile(_widecdataregex).sub _quoteattrsub = re.compile(_widequoteattrregex).sub else: # pragma: nocover _cdatasub = re.compile(_narrowcdataregex).sub _quoteattrsub = re.compile(_narrowquoteattrregex).sub def _cdatareplace(m): """Replace _cdatasub() regex match""" if m.group(0) == u(']]>'): return u(']]>]]>>> from cram._encoding import ul >>> (_cdata('1<\'2\'>&"3\x00]]>\t\r\n') == ... ul(r"'&\"3\ufffd]]>]]>'")) True """ return u('') % _cdatasub(_cdatareplace, s) def _quoteattrreplace(m): """Replace _quoteattrsub() regex match""" return {u('\t'): u(' '), u('\n'): u(' '), u('\r'): u(' '), u('"'): u('"'), u('&'): u('&'), u('<'): u('<'), u('>'): u('>')}.get(m.group(0), _replacementchar) def _quoteattr(s): r"""Escape a string for use as an XML attribute value. >>> from cram._encoding import ul >>> (_quoteattr('1<\'2\'>&"3\x00]]>\t\r\n') == ... ul(r"'\"1<\'2\'>&"3\ufffd]]> \"'")) True """ return u('"%s"') % _quoteattrsub(_quoteattrreplace, s) def _timestamp(): """Return the current time in ISO 8601 format""" tm = time.localtime() if tm.tm_isdst == 1: # pragma: nocover tz = time.altzone else: # pragma: nocover tz = time.timezone timestamp = time.strftime('%Y-%m-%dT%H:%M:%S', tm) tzhours = int(-tz / 60 / 60) tzmins = int(abs(tz) / 60 % 60) timestamp += u('%+03d:%02d') % (tzhours, tzmins) return timestamp def runxunit(tests, xmlpath): """Run tests with xUnit XML output. tests should be a sequence of 2-tuples containing the following: (test path, test function) This function yields a new sequence where each test function is wrapped with a function that writes test results to an xUnit XML file. """ suitestart = time.time() timestamp = _timestamp() hostname = socket.gethostname() total, skipped, failed = [0], [0], [0] testcases = [] for path, test in tests: def testwrapper(): """Run test and collect XML output""" total[0] += 1 start = time.time() refout, postout, diff = test() testtime = time.time() - start classname = path.decode(locale.getpreferredencoding(), 'replace') name = os.path.basename(classname) if postout is None: skipped[0] += 1 testcase = (u(' \n' ' \n' ' \n') % {'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime}) elif diff: failed[0] += 1 diff = list(diff) diffu = u('').join(l.decode(locale.getpreferredencoding(), 'replace') for l in diff) testcase = (u(' \n' ' %(diff)s\n' ' \n') % {'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime, 'diff': _cdata(diffu)}) else: testcase = (u(' \n') % {'classname': _quoteattr(classname), 'name': _quoteattr(name), 'time': testtime}) testcases.append(testcase) return refout, postout, diff yield path, testwrapper suitetime = time.time() - suitestart header = (u('\n' '\n') % {'total': total[0], 'failed': failed[0], 'skipped': skipped[0], 'timestamp': _quoteattr(timestamp), 'hostname': _quoteattr(hostname), 'time': suitetime}) footer = u('\n') xmlfile = open(xmlpath, 'wb') try: xmlfile.write(header.encode('utf-8')) for testcase in testcases: xmlfile.write(testcase.encode('utf-8')) xmlfile.write(footer.encode('utf-8')) finally: xmlfile.close() ================================================ FILE: third_party/cram/examples/.hidden/hidden.t ================================================ This test is ignored because it's hidden. ================================================ FILE: third_party/cram/examples/.hidden.t ================================================ This test is ignored because it's hidden. ================================================ FILE: third_party/cram/examples/bare.t ================================================ $ true ================================================ FILE: third_party/cram/examples/empty.t ================================================ ================================================ FILE: third_party/cram/examples/env.t ================================================ Check environment variables: $ echo "$LANG" C $ echo "$LC_ALL" C $ echo "$LANGUAGE" C $ echo "$TZ" GMT $ echo "$CDPATH" $ echo "$GREP_OPTIONS" $ echo "$CRAMTMP" .+ (re) $ echo "$TESTDIR" */examples (glob) $ ls "$TESTDIR" bare.t empty.t env.t fail.t missingeol.t skip.t test.t $ echo "$TESTFILE" env.t $ pwd */cramtests*/env.t (glob) ================================================ FILE: third_party/cram/examples/fail.t ================================================ Output needing escaping: $ printf '\00\01\02\03\04\05\06\07\010\011\013\014\016\017\020\021\022\n' foo $ printf '\023\024\025\026\027\030\031\032\033\034\035\036\037\040\047\n' bar Wrong output and bad regexes: $ echo 1 2 $ printf '1\nfoo\n1\n' +++ (re) foo\ (re) (re) Filler to force a second diff hunk: Offset regular expression: $ printf 'foo\n\n1\n' \d (re) ================================================ FILE: third_party/cram/examples/missingeol.t ================================================ $ printf foo foo (no-eol) ================================================ FILE: third_party/cram/examples/skip.t ================================================ This test is considered "skipped" because it exits with return code 80. This is useful for skipping tests that only work on certain platforms or in certain settings. $ exit 80 ================================================ FILE: third_party/cram/examples/test.t ================================================ Simple commands: $ echo foo foo $ printf 'bar\nbaz\n' | cat bar baz Multi-line command: $ foo() { > echo bar > } $ foo bar Regular expression: $ echo foobarbaz foobar.* (re) Glob: $ printf '* \\foobarbaz {10}\n' \* \\fo?bar* {10} (glob) Literal match ending in (re) and (glob): $ echo 'foo\Z\Z\Z bar (re)' foo\Z\Z\Z bar (re) $ echo 'baz??? quux (glob)' baz??? quux (glob) Exit code: $ (exit 1) [1] Write to stderr: $ echo foo >&2 foo No newline: $ printf foo foo (no-eol) $ printf 'foo\nbar' foo bar (no-eol) $ printf ' ' (no-eol) $ printf ' \n ' (no-eol) $ echo foo foo $ printf foo foo (no-eol) Escaped output: $ printf '\00\01\02\03\04\05\06\07\010\011\013\014\016\017\020\021\022\n' \x00\x01\x02\x03\x04\x05\x06\x07\x08\t\x0b\x0c\x0e\x0f\x10\x11\x12 (esc) $ printf '\023\024\025\026\027\030\031\032\033\034\035\036\037\040\047\n' \x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' (esc) $ echo hi \x68\x69 (esc) $ echo '(esc) in output (esc)' (esc) in output (esc) $ echo '(esc) in output (esc)' (esc) in output \x28esc\x29 (esc) Command that closes a pipe: $ cat /dev/urandom | head -1 > /dev/null If Cram let Python's SIGPIPE handler get inherited by this script, we might see broken pipe messages. ================================================ FILE: third_party/cram/requirements.txt ================================================ check-manifest coverage pep8 pyflakes ================================================ FILE: third_party/cram/scripts/cram ================================================ #!/usr/bin/env python import sys import cram try: sys.exit(cram.main(sys.argv[1:])) except KeyboardInterrupt: pass ================================================ FILE: third_party/cram/setup.cfg ================================================ [bdist_wheel] universal = true [pep8] # E129: indentation between lines in conditions # E261: two spaces before inline comment # E301: expected blank line # E302: two new lines between functions/etc. ignore = E129,E261,E301,E302 ================================================ FILE: third_party/cram/setup.py ================================================ #!/usr/bin/env python """Installs cram""" import os import sys from distutils.core import setup COMMANDS = {} CRAM_DIR = os.path.abspath(os.path.dirname(__file__)) try: from wheel.bdist_wheel import bdist_wheel except ImportError: pass else: COMMANDS['bdist_wheel'] = bdist_wheel def long_description(): """Get the long description from the README""" return open(os.path.join(sys.path[0], 'README.rst')).read() setup( author='Brodie Rao', author_email='brodie@bitheap.org', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License (GPL)', ('License :: OSI Approved :: GNU General Public License v2 ' 'or later (GPLv2+)'), 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Programming Language :: Unix Shell', 'Topic :: Software Development :: Testing', ], cmdclass=COMMANDS, description='Functional tests for command line applications', download_url='https://bitheap.org/cram/cram-0.7.tar.gz', keywords='automatic functional test framework', license='GNU GPLv2 or any later version', long_description=long_description(), name='cram', packages=['cram'], scripts=['scripts/cram'], url='https://bitheap.org/cram/', version='0.7', ) ================================================ FILE: third_party/cram/tests/config.t ================================================ Set up cram alias and example tests: $ . "$TESTDIR"/setup.sh Options in .cramrc: $ cat > .cramrc < [cram] > yes = True > no = 1 > indent = 4 > EOF $ cram options --yes and --no are mutually exclusive [2] $ mv .cramrc config $ CRAMRC=config cram options --yes and --no are mutually exclusive [2] $ rm config Invalid option in .cramrc: $ cat > .cramrc < [cram] > indent = hmm > EOF $ cram [Uu]sage: cram \[OPTIONS\] TESTS\.\.\. (re) cram: error: option --indent: invalid integer value: 'hmm' [2] $ rm .cramrc $ cat > .cramrc < [cram] > verbose = hmm > EOF $ cram [Uu]sage: cram \[OPTIONS\] TESTS\.\.\. (re) cram: error: --verbose: invalid boolean value: 'hmm' [2] $ rm .cramrc Options in an environment variable: $ CRAM='-y -n' cram options --yes and --no are mutually exclusive [2] ================================================ FILE: third_party/cram/tests/debug.t ================================================ Set up cram alias and example tests: $ . "$TESTDIR"/setup.sh Debug mode: $ printf ' $ echo hi\n > echo bye' > debug.t $ cram -d -v debug.t options --debug and --verbose are mutually exclusive [2] $ cram -d -q debug.t options --debug and --quiet are mutually exclusive [2] $ cram -d -i debug.t options --debug and --interactive are mutually exclusive [2] $ cram -d --xunit-file==cram.xml debug.t options --debug and --xunit-file are mutually exclusive [2] $ cram -d debug.t hi bye $ cram -d examples/empty.t Debug mode with extra shell arguments: $ cram --shell-opts='-s' -d debug.t hi bye Test debug mode with set -x: $ cat > set-x.t < $ echo 1 > 1 > $ set -x > $ echo 2 > EOF $ cram -d set-x.t 1 \+.*echo 2 (re) 2 Test set -x without debug mode: $ cram set-x.t ! --- set-x.t +++ set-x.t.err @@ -1,4 +1,8 @@ $ echo 1 1 $ set -x \+ \+.*echo \(no-eol\) (re) $ echo 2 \+ \+.*echo 2 (re) + 2 \+ \+.*echo \(no-eol\) (re) # Ran 1 tests, 0 skipped, 1 failed. [1] Note that the "+ echo (no-eol)" lines are artifacts of the echo commands that Cram inserts into the test in order to track output. It'd be nice if Cram could avoid removing salt/line number/return code information from those lines, but it isn't possible to distinguish between set -x output and normal output. ================================================ FILE: third_party/cram/tests/dist.t ================================================ Skip this test if check-manifest isn't available: $ command -v check-manifest > /dev/null || exit 80 Confirm that "make dist" isn't going to miss any files: $ check-manifest "$TESTDIR/.." lists of files in version control and sdist match ================================================ FILE: third_party/cram/tests/doctest.t ================================================ Set up cram alias and example tests: $ . "$TESTDIR"/setup.sh Run doctests: $ doctest "$TESTDIR"/../cram ================================================ FILE: third_party/cram/tests/encoding.t ================================================ Set up cram alias and example tests: $ . "$TESTDIR"/setup.sh Test with Windows newlines: $ printf " $ echo hi\r\n hi\r\n" > windows-newlines.t $ cram windows-newlines.t . # Ran 1 tests, 0 skipped, 0 failed. Test with Latin-1 encoding: $ cat > good-latin-1.t < $ printf "hola se\361or\n" > hola se\xf1or (esc) > EOF $ cat > bad-latin-1.t < $ printf "hola se\361or\n" > hey > EOF $ cram good-latin-1.t bad-latin-1.t .! --- bad-latin-1.t +++ bad-latin-1.t.err @@ -1,2 +1,2 @@ $ printf "hola se\361or\n" - hey + hola se\xf1or (esc) # Ran 2 tests, 0 skipped, 1 failed. [1] Test with UTF-8 encoding: $ cat > good-utf-8.t < $ printf "hola se\303\261or\n" > hola se\xc3\xb1or (esc) > EOF $ cat > bad-utf-8.t < $ printf "hola se\303\261or\n" > hey > EOF $ cram good-utf-8.t bad-utf-8.t .! --- bad-utf-8.t +++ bad-utf-8.t.err @@ -1,2 +1,2 @@ $ printf "hola se\303\261or\n" - hey + hola se\xc3\xb1or (esc) # Ran 2 tests, 0 skipped, 1 failed. [1] Test file missing trailing newline: $ printf ' $ true' > passing-with-no-newline.t $ cram passing-with-no-newline.t . # Ran 1 tests, 0 skipped, 0 failed. $ printf ' $ false' > failing-with-no-newline.t $ cram failing-with-no-newline.t ! --- failing-with-no-newline.t +++ failing-with-no-newline.t.err @@ -1,1 +1,2 @@ $ false + [1] # Ran 1 tests, 0 skipped, 1 failed. [1] ================================================ FILE: third_party/cram/tests/interactive.t ================================================ Set up cram alias and example tests: $ . "$TESTDIR"/setup.sh Interactive mode (don't merge): $ cram -n -i examples/fail.t ! --- examples/fail.t +++ examples/fail.t.err @@ -1,18 +1,18 @@ Output needing escaping: $ printf '\00\01\02\03\04\05\06\07\010\011\013\014\016\017\020\021\022\n' - foo + \x00\x01\x02\x03\x04\x05\x06\x07\x08\t\x0b\x0c\x0e\x0f\x10\x11\x12 (esc) $ printf '\023\024\025\026\027\030\031\032\033\034\035\036\037\040\047\n' - bar + \x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' (esc) Wrong output and bad regexes: $ echo 1 - 2 + 1 $ printf '1\nfoo\n1\n' - +++ (re) - foo\ (re) - (re) + 1 + foo + 1 Filler to force a second diff hunk: @@ -20,5 +20,6 @@ Offset regular expression: $ printf 'foo\n\n1\n' + foo \d (re) Accept this change? [yN] n # Ran 1 tests, 0 skipped, 1 failed. [1] $ md5 examples/fail.t examples/fail.t.err .*\b0f598c2b7b8ca5bcb8880e492ff6b452\b.* (re) .*\b7a23dfa85773c77648f619ad0f9df554\b.* (re) Interactive mode (merge): $ cp examples/fail.t examples/fail.t.orig $ cram -y -i examples/fail.t ! --- examples/fail.t +++ examples/fail.t.err @@ -1,18 +1,18 @@ Output needing escaping: $ printf '\00\01\02\03\04\05\06\07\010\011\013\014\016\017\020\021\022\n' - foo + \x00\x01\x02\x03\x04\x05\x06\x07\x08\t\x0b\x0c\x0e\x0f\x10\x11\x12 (esc) $ printf '\023\024\025\026\027\030\031\032\033\034\035\036\037\040\047\n' - bar + \x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' (esc) Wrong output and bad regexes: $ echo 1 - 2 + 1 $ printf '1\nfoo\n1\n' - +++ (re) - foo\ (re) - (re) + 1 + foo + 1 Filler to force a second diff hunk: @@ -20,5 +20,6 @@ Offset regular expression: $ printf 'foo\n\n1\n' + foo \d (re) Accept this change? [yN] y patching file examples/fail.t # Ran 1 tests, 0 skipped, 1 failed. [1] $ md5 examples/fail.t .*\b1d9e5b527f01fbf2d9b1c121d005108c\b.* (re) $ mv examples/fail.t.orig examples/fail.t Verbose interactive mode (answer manually and don't merge): $ printf 'bad\nn\n' | cram -v -i examples/fail.t examples/fail.t: failed --- examples/fail.t +++ examples/fail.t.err @@ -1,18 +1,18 @@ Output needing escaping: $ printf '\00\01\02\03\04\05\06\07\010\011\013\014\016\017\020\021\022\n' - foo + \x00\x01\x02\x03\x04\x05\x06\x07\x08\t\x0b\x0c\x0e\x0f\x10\x11\x12 (esc) $ printf '\023\024\025\026\027\030\031\032\033\034\035\036\037\040\047\n' - bar + \x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' (esc) Wrong output and bad regexes: $ echo 1 - 2 + 1 $ printf '1\nfoo\n1\n' - +++ (re) - foo\ (re) - (re) + 1 + foo + 1 Filler to force a second diff hunk: @@ -20,5 +20,6 @@ Offset regular expression: $ printf 'foo\n\n1\n' + foo \d (re) Accept this change? [yN] Accept this change? [yN] # Ran 1 tests, 0 skipped, 1 failed. [1] $ md5 examples/fail.t examples/fail.t.err .*\b0f598c2b7b8ca5bcb8880e492ff6b452\b.* (re) .*\b7a23dfa85773c77648f619ad0f9df554\b.* (re) $ printf 'bad\n\n' | cram -v -i examples/fail.t examples/fail.t: failed --- examples/fail.t +++ examples/fail.t.err @@ -1,18 +1,18 @@ Output needing escaping: $ printf '\00\01\02\03\04\05\06\07\010\011\013\014\016\017\020\021\022\n' - foo + \x00\x01\x02\x03\x04\x05\x06\x07\x08\t\x0b\x0c\x0e\x0f\x10\x11\x12 (esc) $ printf '\023\024\025\026\027\030\031\032\033\034\035\036\037\040\047\n' - bar + \x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' (esc) Wrong output and bad regexes: $ echo 1 - 2 + 1 $ printf '1\nfoo\n1\n' - +++ (re) - foo\ (re) - (re) + 1 + foo + 1 Filler to force a second diff hunk: @@ -20,5 +20,6 @@ Offset regular expression: $ printf 'foo\n\n1\n' + foo \d (re) Accept this change? [yN] Accept this change? [yN] # Ran 1 tests, 0 skipped, 1 failed. [1] $ md5 examples/fail.t examples/fail.t.err .*\b0f598c2b7b8ca5bcb8880e492ff6b452\b.* (re) .*\b7a23dfa85773c77648f619ad0f9df554\b.* (re) Verbose interactive mode (answer manually and merge): $ cp examples/fail.t examples/fail.t.orig $ printf 'bad\ny\n' | cram -v -i examples/fail.t examples/fail.t: failed --- examples/fail.t +++ examples/fail.t.err @@ -1,18 +1,18 @@ Output needing escaping: $ printf '\00\01\02\03\04\05\06\07\010\011\013\014\016\017\020\021\022\n' - foo + \x00\x01\x02\x03\x04\x05\x06\x07\x08\t\x0b\x0c\x0e\x0f\x10\x11\x12 (esc) $ printf '\023\024\025\026\027\030\031\032\033\034\035\036\037\040\047\n' - bar + \x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' (esc) Wrong output and bad regexes: $ echo 1 - 2 + 1 $ printf '1\nfoo\n1\n' - +++ (re) - foo\ (re) - (re) + 1 + foo + 1 Filler to force a second diff hunk: @@ -20,5 +20,6 @@ Offset regular expression: $ printf 'foo\n\n1\n' + foo \d (re) Accept this change? [yN] Accept this change? [yN] patching file examples/fail.t examples/fail.t: merged output # Ran 1 tests, 0 skipped, 1 failed. [1] $ md5 examples/fail.t .*\b1d9e5b527f01fbf2d9b1c121d005108c\b.* (re) $ mv examples/fail.t.orig examples/fail.t Test missing patch(1) and patch(1) error: $ PATH=. cram -i examples/fail.t patch(1) required for -i [2] $ cat > patch < #!/bin/sh > echo "patch failed" 1>&2 > exit 1 > EOF $ chmod +x patch $ PATH=. cram -y -i examples/fail.t ! --- examples/fail.t +++ examples/fail.t.err @@ -1,18 +1,18 @@ Output needing escaping: $ printf '\00\01\02\03\04\05\06\07\010\011\013\014\016\017\020\021\022\n' - foo + \x00\x01\x02\x03\x04\x05\x06\x07\x08\t\x0b\x0c\x0e\x0f\x10\x11\x12 (esc) $ printf '\023\024\025\026\027\030\031\032\033\034\035\036\037\040\047\n' - bar + \x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' (esc) Wrong output and bad regexes: $ echo 1 - 2 + 1 $ printf '1\nfoo\n1\n' - +++ (re) - foo\ (re) - (re) + 1 + foo + 1 Filler to force a second diff hunk: @@ -20,5 +20,6 @@ Offset regular expression: $ printf 'foo\n\n1\n' + foo \d (re) Accept this change? [yN] y patch failed examples/fail.t: merge failed # Ran 1 tests, 0 skipped, 1 failed. [1] $ md5 examples/fail.t examples/fail.t.err .*\b0f598c2b7b8ca5bcb8880e492ff6b452\b.* (re) .*\b7a23dfa85773c77648f619ad0f9df554\b.* (re) $ rm patch examples/fail.t.err ================================================ FILE: third_party/cram/tests/pep8.t ================================================ Skip this test if pep8 isn't available: $ command -v pep8 > /dev/null || exit 80 Check that the Python source code style is PEP 8 compliant: $ pep8 --config="$TESTDIR/.."/setup.cfg --repeat "$TESTDIR/.." ================================================ FILE: third_party/cram/tests/pyflakes.t ================================================ Skip this test if pyflakes isn't available: $ command -v pyflakes > /dev/null || exit 80 Check that there are no obvious Python source code errors: $ pyflakes "$TESTDIR/.." ================================================ FILE: third_party/cram/tests/run-doctests.py ================================================ #!/usr/bin/env python import doctest import os import sys def _getmodules(pkgdir): """Import and yield modules in pkgdir""" for root, dirs, files in os.walk(pkgdir): if '__pycache__' in dirs: dirs.remove('__pycache__') for fn in files: if not fn.endswith('.py') or fn == '__main__.py': continue modname = fn.replace(os.sep, '.')[:-len('.py')] if modname.endswith('.__init__'): modname = modname[:-len('.__init__')] modname = '.'.join(['cram', modname]) if '.' in modname: fromlist = [modname.rsplit('.', 1)[1]] else: fromlist = [] yield __import__(modname, {}, {}, fromlist) def rundoctests(pkgdir): """Run doctests in the given package directory""" totalfailures = totaltests = 0 for module in _getmodules(pkgdir): failures, tests = doctest.testmod(module) totalfailures += failures totaltests += tests return totalfailures != 0 if __name__ == '__main__': try: sys.exit(rundoctests(sys.argv[1])) except KeyboardInterrupt: pass ================================================ FILE: third_party/cram/tests/setup.sh ================================================ #!/bin/sh # Bash doesn't expand aliases by default in non-interactive mode, so # we enable it manually if the test is run with --shell=/bin/bash. [ "$TESTSHELL" = "/bin/bash" ] && shopt -s expand_aliases # The $PYTHON environment variable should be set when running this test # from Python. [ -n "$PYTHON" ] || PYTHON="`which python`" [ -n "$PYTHONPATH" ] || PYTHONPATH="$TESTDIR/.." && export PYTHONPATH if [ -n "$COVERAGE" ]; then if [ -z "$COVERAGE_FILE" ]; then COVERAGE_FILE="$TESTDIR/../.coverage" export COVERAGE_FILE fi alias cram="`which "$COVERAGE"` run -a --rcfile=$TESTDIR/../.coveragerc \ $TESTDIR/../scripts/cram --shell=$TESTSHELL" alias doctest="`which "$COVERAGE"` run -a --rcfile=$TESTDIR/../.coveragerc \ $TESTDIR/run-doctests.py" else PYTHON="`command -v "$PYTHON" || echo "$PYTHON"`" alias cram="$PYTHON $TESTDIR/../scripts/cram --shell=$TESTSHELL" alias doctest="$PYTHON $TESTDIR/run-doctests.py" fi command -v md5 > /dev/null || alias md5=md5sum # Copy in example tests cp -R "$TESTDIR"/../examples . find . -name '*.err' -exec rm '{}' \; ================================================ FILE: third_party/cram/tests/test.t ================================================ Set up cram alias and example tests: $ . "$TESTDIR"/setup.sh Run cram examples: $ cram -q examples examples/fail.t .s.!.s. # Ran 7 tests, 2 skipped, 1 failed. [1] $ md5 examples/fail.t examples/fail.t.err .*\b0f598c2b7b8ca5bcb8880e492ff6b452\b.* (re) .*\b7a23dfa85773c77648f619ad0f9df554\b.* (re) $ rm examples/fail.t.err Run examples with bash: $ cram --shell=/bin/bash -q examples examples/fail.t .s.!.s. # Ran 7 tests, 2 skipped, 1 failed. [1] $ md5 examples/fail.t examples/fail.t.err .*\b0f598c2b7b8ca5bcb8880e492ff6b452\b.* (re) .*\b7a23dfa85773c77648f619ad0f9df554\b.* (re) $ rm examples/fail.t.err Verbose mode: $ cram -q -v examples examples/fail.t examples/bare.t: passed examples/empty.t: empty examples/env.t: passed examples/fail.t: failed examples/missingeol.t: passed examples/skip.t: skipped examples/test.t: passed # Ran 7 tests, 2 skipped, 1 failed. [1] $ md5 examples/fail.t examples/fail.t.err .*\b0f598c2b7b8ca5bcb8880e492ff6b452\b.* (re) .*\b7a23dfa85773c77648f619ad0f9df554\b.* (re) $ rm examples/fail.t.err Test that a fixed .err file is deleted: $ echo " $ echo 1" > fixed.t $ cram fixed.t ! --- fixed.t +++ fixed.t.err @@ -1,1 +1,2 @@ $ echo 1 + 1 # Ran 1 tests, 0 skipped, 1 failed. [1] $ cp fixed.t.err fixed.t $ cram fixed.t . # Ran 1 tests, 0 skipped, 0 failed. $ test \! -f fixed.t.err $ rm fixed.t Don't sterilize environment: $ TZ=foo; export TZ $ CDPATH=foo; export CDPATH $ GREP_OPTIONS=foo; export GREP_OPTIONS $ cram -E examples/env.t ! \-\-\- examples/env\.t\s* (re) \+\+\+ examples/env\.t\.err\s* (re) @@ -7,11 +7,11 @@ $ echo "$LANGUAGE" C $ echo "$TZ" - GMT + foo $ echo "$CDPATH" - + foo $ echo "$GREP_OPTIONS" - + foo $ echo "$CRAMTMP" .+ (re) $ echo "$TESTDIR" # Ran 1 tests, 0 skipped, 1 failed. [1] $ rm examples/env.t.err Note: We can't set the locale to foo because some shells will issue warnings for invalid locales. Test --keep-tmpdir: $ cram -q --keep-tmpdir examples/test.t | while read line; do > echo "$line" 1>&2 > msg=`echo "$line" | cut -d ' ' -f 1-4` > if [ "$msg" = '# Kept temporary directory:' ]; then > echo "$line" | cut -d ' ' -f 5 > fi > done > keeptmp . # Ran 1 tests, 0 skipped, 0 failed. # Kept temporary directory: */cramtests-* (glob) $ ls "`cat keeptmp`" | sort test.t tmp Custom indentation: $ cat > indent.t < Indented by 4 spaces: > > $ echo foo > foo > > Not part of the test: > > $ echo foo > bar > EOF $ cram --indent=4 indent.t . # Ran 1 tests, 0 skipped, 0 failed. Test running tests with the same filename in different directories: $ mkdir subdir1 subdir2 $ cat > subdir1/test.t < $ echo 1 > EOF $ cat > subdir2/test.t < $ echo 2 > EOF $ cram subdir1 subdir2 ! --- subdir1/test.t +++ subdir1/test.t.err @@ -1,1 +1,2 @@ $ echo 1 + 1 ! --- subdir2/test.t +++ subdir2/test.t.err @@ -1,1 +1,2 @@ $ echo 2 + 2 # Ran 2 tests, 0 skipped, 2 failed. [1] Test failing a test in a read-only directory with the --no-err-files option: $ mkdir subdir $ cat > subdir/test.t < $ echo 1 > EOF $ chmod a-w subdir $ cram subdir >/dev/null 2>&1 [1] $ cram --no-err-files subdir ! --- subdir/test.t +++ subdir/test.t.err @@ -1,1 +1,2 @@ $ echo 1 + 1 # Ran 1 tests, 0 skipped, 1 failed. [1] $ chmod a+w subdir ================================================ FILE: third_party/cram/tests/usage.t ================================================ Set up cram alias and example tests: $ . "$TESTDIR"/setup.sh Usage: $ cram -h [Uu]sage: cram \[OPTIONS\] TESTS\.\.\. (re) [Oo]ptions: (re) -h, --help show this help message and exit -V, --version show version information and exit -q, --quiet don't print diffs -v, --verbose show filenames and test status -i, --interactive interactively merge changed test output -d, --debug write script output directly to the terminal -y, --yes answer yes to all questions -n, --no answer no to all questions -E, --preserve-env don't reset common environment variables -e, --no-err-files don't write .err files on test failures --keep-tmpdir keep temporary directories --shell=PATH shell to use for running tests (default: /bin/sh) --shell-opts=OPTS arguments to invoke shell with --indent=NUM number of spaces to use for indentation (default: 2) --xunit-file=PATH path to write xUnit XML output $ cram -V Cram CLI testing framework (version 0.7) Copyright (C) 2010-2016 Brodie Rao and others This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ cram [Uu]sage: cram \[OPTIONS\] TESTS\.\.\. (re) [2] $ cram -y -n options --yes and --no are mutually exclusive [2] $ cram non-existent also-not-here no such file: non-existent [2] $ mkdir empty $ cram empty no tests found [2] $ cram --shell=./badsh shell not found: ./badsh [2] ================================================ FILE: third_party/cram/tests/xunit.t ================================================ Set up cram alias and example tests: $ . "$TESTDIR"/setup.sh xUnit XML output: $ cram -q -v --xunit-file=cram.xml examples examples/bare.t: passed examples/empty.t: empty examples/env.t: passed examples/fail.t: failed examples/missingeol.t: passed examples/skip.t: skipped examples/test.t: passed # Ran 7 tests, 2 skipped, 1 failed. [1] $ cat cram.xml (re) (re) (re) (re) (re) (re) (re) (re) $ rm cram.xml examples/fail.t.err ================================================ FILE: third_party/luajit/Makefile.am ================================================ # Copyright (C) 2016 Alexey Kopytov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA EXTRA_DIST = luajit if IS_MACOS export MACOSX_DEPLOYMENT_TARGET := @MACOSX_DEPLOYMENT_TARGET@ endif all-local: $(builddir)/lib/libluajit-5.1.a # LuaJIT does not support VPATH builds $(builddir)/lib/libluajit-5.1.a: $(MAKE) -C $(srcdir)/luajit clean rm -rf tmp mkdir tmp tar -C $(srcdir) -cf - luajit | tar -xf - -C tmp/ chmod -R u+w tmp $(MAKE) -C tmp/luajit \ PREFIX=$(abs_top_builddir)/third_party/luajit \ INSTALL_INC=$(abs_top_builddir)/third_party/luajit/inc \ install clean-local: rm -rf tmp bin inc lib share ================================================ FILE: third_party/luajit/luajit/.gitignore ================================================ *.[oa] *.so *.obj *.lib *.exp *.dll *.exe *.manifest *.dmp *.swp .tags ================================================ FILE: third_party/luajit/luajit/COPYRIGHT ================================================ =============================================================================== LuaJIT -- a Just-In-Time Compiler for Lua. https://luajit.org/ Copyright (C) 2005-2022 Mike Pall. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. [ MIT license: https://www.opensource.org/licenses/mit-license.php ] =============================================================================== [ LuaJIT includes code from Lua 5.1/5.2, which has this license statement: ] Copyright (C) 1994-2012 Lua.org, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =============================================================================== [ LuaJIT includes code from dlmalloc, which has this license statement: ] This is a version (aka dlmalloc) of malloc/free/realloc written by Doug Lea and released to the public domain, as explained at https://creativecommons.org/licenses/publicdomain =============================================================================== ================================================ FILE: third_party/luajit/luajit/README ================================================ README for LuaJIT 2.1.0-beta3 ----------------------------- LuaJIT is a Just-In-Time (JIT) compiler for the Lua programming language. Project Homepage: https://luajit.org/ LuaJIT is Copyright (C) 2005-2022 Mike Pall. LuaJIT is free software, released under the MIT license. See full Copyright Notice in the COPYRIGHT file or in luajit.h. Documentation for LuaJIT is available in HTML format. Please point your favorite browser to: doc/luajit.html ================================================ FILE: third_party/luajit/luajit/doc/bluequad-print.css ================================================ /* Copyright (C) 2004-2022 Mike Pall. * * You are welcome to use the general ideas of this design for your own sites. * But please do not steal the stylesheet, the layout or the color scheme. */ body { font-family: serif; font-size: 11pt; margin: 0 3em; padding: 0; border: none; } a:link, a:visited, a:hover, a:active { text-decoration: none; background: transparent; color: #0000ff; } h1, h2, h3 { font-family: sans-serif; font-weight: bold; text-align: left; margin: 0.5em 0; padding: 0; } h1 { font-size: 200%; } h2 { font-size: 150%; } h3 { font-size: 125%; } p { margin: 0 0 0.5em 0; padding: 0; } ul, ol { margin: 0.5em 0; padding: 0 0 0 2em; } ul { list-style: outside square; } ol { list-style: outside decimal; } li { margin: 0; padding: 0; } dl { margin: 1em 0; padding: 1em; border: 1px solid black; } dt { font-weight: bold; margin: 0; padding: 0; } dt sup { float: right; margin-left: 1em; } dd { margin: 0.5em 0 0 2em; padding: 0; } table { table-layout: fixed; width: 100%; margin: 1em 0; padding: 0; border: 1px solid black; border-spacing: 0; border-collapse: collapse; } tr { margin: 0; padding: 0; border: none; } td { text-align: left; margin: 0; padding: 0.2em 0.5em; border-top: 1px solid black; border-bottom: 1px solid black; } tr.separate td { border-top: double; } tt, pre, code, kbd, samp { font-family: monospace; font-size: 75%; } kbd { font-weight: bolder; } blockquote, pre { margin: 1em 2em; padding: 0; } img { border: none; vertical-align: baseline; margin: 0; padding: 0; } img.left { float: left; margin: 0.5em 1em 0.5em 0; } img.right { float: right; margin: 0.5em 0 0.5em 1em; } .flush { clear: both; visibility: hidden; } .hide, .noprint, #nav { display: none !important; } .pagebreak { page-break-before: always; } #site { text-align: right; font-family: sans-serif; font-weight: bold; margin: 0 1em; border-bottom: 1pt solid black; } #site a { font-size: 1.2em; } #site a:link, #site a:visited { text-decoration: none; font-weight: bold; background: transparent; color: #ffffff; } #logo { color: #ff8000; } #head { clear: both; margin: 0 1em; } #main { line-height: 1.3; text-align: justify; margin: 1em; } #foot { clear: both; font-size: 80%; text-align: center; margin: 0 1.25em; padding: 0.5em 0 0 0; border-top: 1pt solid black; page-break-before: avoid; page-break-after: avoid; } ================================================ FILE: third_party/luajit/luajit/doc/bluequad.css ================================================ /* Copyright (C) 2004-2022 Mike Pall. * * You are welcome to use the general ideas of this design for your own sites. * But please do not steal the stylesheet, the layout or the color scheme. */ /* colorscheme: * * site | head #4162bf/white | #6078bf/#e6ecff * ------+------ ----------------+------------------- * nav | main #bfcfff | #e6ecff/black * * nav: hiback loback #c5d5ff #b9c9f9 * hiborder loborder #e6ecff #97a7d7 * link hover #2142bf #ff0000 * * link: link visited hover #2142bf #8122bf #ff0000 * * main: boxback boxborder #f0f4ff #bfcfff */ body { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt; margin: 0; padding: 0; border: none; background: #e0e0e0; color: #000000; } a:link { text-decoration: none; background: transparent; color: #2142bf; } a:visited { text-decoration: none; background: transparent; color: #8122bf; } a:hover, a:active { text-decoration: underline; background: transparent; color: #ff0000; } h1, h2, h3 { font-weight: bold; text-align: left; margin: 0.5em 0; padding: 0; background: transparent; } h1 { font-size: 200%; line-height: 3em; /* really 6em relative to body, match #site span */ margin: 0; } h2 { font-size: 150%; color: #606060; } h3 { font-size: 125%; color: #404040; } p { max-width: 600px; margin: 0 0 0.5em 0; padding: 0; } b { color: #404040; } ul, ol { max-width: 600px; margin: 0.5em 0; padding: 0 0 0 2em; } ul { list-style: outside square; } ol { list-style: outside decimal; } li { margin: 0; padding: 0; } dl { max-width: 600px; margin: 1em 0; padding: 1em; border: 1px solid #bfcfff; background: #f0f4ff; } dt { font-weight: bold; margin: 0; padding: 0; } dt sup { float: right; margin-left: 1em; color: #808080; } dt a:visited { text-decoration: none; color: #2142bf; } dt a:hover, dt a:active { text-decoration: none; color: #ff0000; } dd { margin: 0.5em 0 0 2em; padding: 0; } div.tablewrap { /* for IE *sigh* */ max-width: 600px; } table { table-layout: fixed; border-spacing: 0; border-collapse: collapse; max-width: 600px; width: 100%; margin: 1em 0; padding: 0; border: 1px solid #bfcfff; } tr { margin: 0; padding: 0; border: none; } tr.odd { background: #f0f4ff; } tr.separate td { border-top: 1px solid #bfcfff; } td { text-align: left; margin: 0; padding: 0.2em 0.5em; border: none; } tt, code, kbd, samp { font-family: Courier New, Courier, monospace; line-height: 1.2; font-size: 110%; } kbd { font-weight: bolder; } blockquote, pre { max-width: 600px; margin: 1em 2em; padding: 0; } pre { line-height: 1.1; } pre.code { line-height: 1.4; margin: 0.5em 0 1em 0.5em; padding: 0.5em 1em; border: 1px solid #bfcfff; background: #f0f4ff; } pre.mark { padding-left: 2em; } span.codemark { position:absolute; left: 16em; color: #4040c0; } span.mark { color: #4040c0; font-family: Courier New, Courier, monospace; line-height: 1.1; } img { border: none; vertical-align: baseline; margin: 0; padding: 0; } img.left { float: left; margin: 0.5em 1em 0.5em 0; } img.right { float: right; margin: 0.5em 0 0.5em 1em; } .indent { padding-left: 1em; } .flush { clear: both; visibility: hidden; } .hide, .noscreen { display: none !important; } .ext { color: #ff8000; } .new { font-size: 6pt; vertical-align: middle; background: #ff8000; color: #ffffff; } #site { clear: both; float: left; width: 13em; text-align: center; font-weight: bold; margin: 0; padding: 0; background: transparent; color: #ffffff; } #site a { font-size: 200%; } #site a:link, #site a:visited { text-decoration: none; font-weight: bold; background: transparent; color: #ffffff; } #site span { line-height: 3em; /* really 6em relative to body, match h1 */ } #logo { color: #ffb380; } #head { margin: 0; padding: 0 0 0 2em; border-left: solid 13em #4162bf; border-right: solid 3em #6078bf; background: #6078bf; color: #e6ecff; } #nav { clear: both; float: left; overflow: hidden; text-align: left; line-height: 1.5; width: 13em; padding-top: 1em; background: transparent; } #nav ul { list-style: none outside; margin: 0; padding: 0; } #nav li { margin: 0; padding: 0; } #nav a { display: block; text-decoration: none; font-weight: bold; margin: 0; padding: 2px 1em; border-top: 1px solid transparent; border-bottom: 1px solid transparent; background: transparent; color: #2142bf; } #nav a:hover, #nav a:active { text-decoration: none; border-top: 1px solid #97a7d7; border-bottom: 1px solid #e6ecff; background: #b9c9f9; color: #ff0000; } #nav a.current, #nav a.current:hover, #nav a.current:active { border-top: 1px solid #e6ecff; border-bottom: 1px solid #97a7d7; background: #c5d5ff; color: #2142bf; } #nav ul ul a { padding: 0 1em 0 1.7em; } #nav ul ul ul a { padding: 0 0.5em 0 2.4em; } #main { line-height: 1.5; text-align: left; margin: 0; padding: 1em 2em; border-left: solid 13em #bfcfff; border-right: solid 3em #e6ecff; background: #e6ecff; } #foot { clear: both; font-size: 80%; text-align: center; margin: 0; padding: 0.5em; background: #6078bf; color: #ffffff; } #foot a:link, #foot a:visited { text-decoration: underline; background: transparent; color: #ffffff; } #foot a:hover, #foot a:active { text-decoration: underline; background: transparent; color: #bfcfff; } ================================================ FILE: third_party/luajit/luajit/doc/contact.html ================================================ Contact

If you want to report bugs, propose fixes or suggest enhancements, please use the » GitHub issue tracker.

Please send general questions to the » LuaJIT mailing list.

You can also send any questions you have directly to me:

Note: I cannot reply to GMail, Google Workplace, Outlook or Office365 mail addresses, since they prefer to mindlessly filter out mails sent from small domains using independent mail servers, such as mine. If you don't like that, please complain to Google or Microsoft, not me.

Copyright

All documentation is Copyright © 2005-2022 Mike Pall.


================================================ FILE: third_party/luajit/luajit/doc/ext_buffer.html ================================================ String Buffer Library

The string buffer library allows high-performance manipulation of string-like data.

Unlike Lua strings, which are constants, string buffers are mutable sequences of 8-bit (binary-transparent) characters. Data can be stored, formatted and encoded into a string buffer and later converted, extracted or decoded.

The convenient string buffer API simplifies common string manipulation tasks, that would otherwise require creating many intermediate strings. String buffers improve performance by eliminating redundant memory copies, object creation, string interning and garbage collection overhead. In conjunction with the FFI library, they allow zero-copy operations.

The string buffer library also includes a high-performance serializer for Lua objects.

Work in Progress

This library is a work in progress. More functionality will be added soon.

Using the String Buffer Library

The string buffer library is built into LuaJIT by default, but it's not loaded by default. Add this to the start of every Lua file that needs one of its functions:

local buffer = require("string.buffer")

The convention for the syntax shown on this page is that buffer refers to the buffer library and buf refers to an individual buffer object.

Please note the difference between a Lua function call, e.g. buffer.new() (with a dot) and a Lua method call, e.g. buf:reset() (with a colon).

Buffer Objects

A buffer object is a garbage-collected Lua object. After creation with buffer.new(), it can (and should) be reused for many operations. When the last reference to a buffer object is gone, it will eventually be freed by the garbage collector, along with the allocated buffer space.

Buffers operate like a FIFO (first-in first-out) data structure. Data can be appended (written) to the end of the buffer and consumed (read) from the front of the buffer. These operations may be freely mixed.

The buffer space that holds the characters is managed automatically — it grows as needed and already consumed space is recycled. Use buffer.new(size) and buf:free(), if you need more control.

The maximum size of a single buffer is the same as the maximum size of a Lua string, which is slightly below two gigabytes. For huge data sizes, neither strings nor buffers are the right data structure — use the FFI library to directly map memory or files up to the virtual memory limit of your OS.

Buffer Method Overview

  • The buf:put*()-like methods append (write) characters to the end of the buffer.
  • The buf:get*()-like methods consume (read) characters from the front of the buffer.
  • Other methods, like buf:tostring() only read the buffer contents, but don't change the buffer.
  • The buf:set() method allows zero-copy consumption of a string or an FFI cdata object as a buffer.
  • The FFI-specific methods allow zero-copy read/write-style operations or modifying the buffer contents in-place. Please check the FFI caveats below, too.
  • Methods that don't need to return anything specific, return the buffer object itself as a convenience. This allows method chaining, e.g.: buf:reset():encode(obj) or buf:skip(len):get()

Buffer Creation and Management

local buf = buffer.new([size [,options]])
local buf = buffer.new([options])

Creates a new buffer object.

The optional size argument ensures a minimum initial buffer size. This is strictly an optimization when the required buffer size is known beforehand. The buffer space will grow as needed, in any case.

The optional table options sets various serialization options.

buf = buf:reset()

Reset (empty) the buffer. The allocated buffer space is not freed and may be reused.

buf = buf:free()

The buffer space of the buffer object is freed. The object itself remains intact, empty and may be reused.

Note: you normally don't need to use this method. The garbage collector automatically frees the buffer space, when the buffer object is collected. Use this method, if you need to free the associated memory immediately.

Buffer Writers

buf = buf:put([str|num|obj] [,…])

Appends a string str, a number num or any object obj with a __tostring metamethod to the buffer. Multiple arguments are appended in the given order.

Appending a buffer to a buffer is possible and short-circuited internally. But it still involves a copy. Better combine the buffer writes to use a single buffer.

buf = buf:putf(format, …)

Appends the formatted arguments to the buffer. The format string supports the same options as string.format().

buf = buf:putcdata(cdata, len)FFI

Appends the given len number of bytes from the memory pointed to by the FFI cdata object to the buffer. The object needs to be convertible to a (constant) pointer.

buf = buf:set(str)
buf = buf:set(cdata, len)
FFI

This method allows zero-copy consumption of a string or an FFI cdata object as a buffer. It stores a reference to the passed string str or the FFI cdata object in the buffer. Any buffer space originally allocated is freed. This is not an append operation, unlike the buf:put*() methods.

After calling this method, the buffer behaves as if buf:free():put(str) or buf:free():put(cdata, len) had been called. However, the data is only referenced and not copied, as long as the buffer is only consumed.

In case the buffer is written to later on, the referenced data is copied and the object reference is removed (copy-on-write semantics).

The stored reference is an anchor for the garbage collector and keeps the originally passed string or FFI cdata object alive.

ptr, len = buf:reserve(size)FFI
buf = buf:commit(used)FFI

The reserve method reserves at least size bytes of write space in the buffer. It returns an uint8_t * FFI cdata pointer ptr that points to this space.

The available length in bytes is returned in len. This is at least size bytes, but may be more to facilitate efficient buffer growth. You can either make use of the additional space or ignore len and only use size bytes.

The commit method appends the used bytes of the previously returned write space to the buffer data.

This pair of methods allows zero-copy use of C read-style APIs:

local MIN_SIZE = 65536
repeat
  local ptr, len = buf:reserve(MIN_SIZE)
  local n = C.read(fd, ptr, len)
  if n == 0 then break end -- EOF.
  if n < 0 then error("read error") end
  buf:commit(n)
until false

The reserved write space is not initialized. At least the used bytes must be written to before calling the commit method. There's no need to call the commit method, if nothing is added to the buffer (e.g. on error).

Buffer Readers

len = #buf

Returns the current length of the buffer data in bytes.

res = str|num|buf .. str|num|buf […]

The Lua concatenation operator .. also accepts buffers, just like strings or numbers. It always returns a string and not a buffer.

Note that although this is supported for convenience, this thwarts one of the main reasons to use buffers, which is to avoid string allocations. Rewrite it with buf:put() and buf:get().

Mixing this with unrelated objects that have a __concat metamethod may not work, since these probably only expect strings.

buf = buf:skip(len)

Skips (consumes) len bytes from the buffer up to the current length of the buffer data.

str, … = buf:get([len|nil] [,…])

Consumes the buffer data and returns one or more strings. If called without arguments, the whole buffer data is consumed. If called with a number, up to len bytes are consumed. A nil argument consumes the remaining buffer space (this only makes sense as the last argument). Multiple arguments consume the buffer data in the given order.

Note: a zero length or no remaining buffer data returns an empty string and not nil.

str = buf:tostring()
str = tostring(buf)

Creates a string from the buffer data, but doesn't consume it. The buffer remains unchanged.

Buffer objects also define a __tostring metamethod. This means buffers can be passed to the global tostring() function and many other functions that accept this in place of strings. The important internal uses in functions like io.write() are short-circuited to avoid the creation of an intermediate string object.

ptr, len = buf:ref()FFI

Returns an uint8_t * FFI cdata pointer ptr that points to the buffer data. The length of the buffer data in bytes is returned in len.

The returned pointer can be directly passed to C functions that expect a buffer and a length. You can also do bytewise reads (local x = ptr[i]) or writes (ptr[i] = 0x40) of the buffer data.

In conjunction with the skip method, this allows zero-copy use of C write-style APIs:

repeat
  local ptr, len = buf:ref()
  if len == 0 then break end
  local n = C.write(fd, ptr, len)
  if n < 0 then error("write error") end
  buf:skip(n)
until n >= len

Unlike Lua strings, buffer data is not implicitly zero-terminated. It's not safe to pass ptr to C functions that expect zero-terminated strings. If you're not using len, then you're doing something wrong.

Serialization of Lua Objects

The following functions and methods allow high-speed serialization (encoding) of a Lua object into a string and decoding it back to a Lua object. This allows convenient storage and transport of structured data.

The encoded data is in an internal binary format. The data can be stored in files, binary-transparent databases or transmitted to other LuaJIT instances across threads, processes or networks.

Encoding speed can reach up to 1 Gigabyte/second on a modern desktop- or server-class system, even when serializing many small objects. Decoding speed is mostly constrained by object creation cost.

The serializer handles most Lua types, common FFI number types and nested structures. Functions, thread objects, other FFI cdata and full userdata cannot be serialized (yet).

The encoder serializes nested structures as trees. Multiple references to a single object will be stored separately and create distinct objects after decoding. Circular references cause an error.

Serialization Functions and Methods

str = buffer.encode(obj)
buf = buf:encode(obj)

Serializes (encodes) the Lua object obj. The stand-alone function returns a string str. The buffer method appends the encoding to the buffer.

obj can be any of the supported Lua types — it doesn't need to be a Lua table.

This function may throw an error when attempting to serialize unsupported object types, circular references or deeply nested tables.

obj = buffer.decode(str)
obj = buf:decode()

The stand-alone function deserializes (decodes) the string str, the buffer method deserializes one object from the buffer. Both return a Lua object obj.

The returned object may be any of the supported Lua types — even nil.

This function may throw an error when fed with malformed or incomplete encoded data. The stand-alone function throws when there's left-over data after decoding a single top-level object. The buffer method leaves any left-over data in the buffer.

Attempting to deserialize an FFI type will throw an error, if the FFI library is not built-in or has not been loaded, yet.

Serialization Options

The options table passed to buffer.new() may contain the following members (all optional):

  • dict is a Lua table holding a dictionary of strings that commonly occur as table keys of objects you are serializing. These keys are compactly encoded as indexes during serialization. A well-chosen dictionary saves space and improves serialization performance.
  • metatable is a Lua table holding a dictionary of metatables for the table objects you are serializing.

dict needs to be an array of strings and metatable needs to be an array of tables. Both starting at index 1 and without holes (no nil in between). The tables are anchored in the buffer object and internally modified into a two-way index (don't do this yourself, just pass a plain array). The tables must not be modified after they have been passed to buffer.new().

The dict and metatable tables used by the encoder and decoder must be the same. Put the most common entries at the front. Extend at the end to ensure backwards-compatibility — older encodings can then still be read. You may also set some indexes to false to explicitly drop backwards-compatibility. Old encodings that use these indexes will throw an error when decoded.

Metatables that are not found in the metatable dictionary are ignored when encoding. Decoding returns a table with a nil metatable.

Note: parsing and preparation of the options table is somewhat expensive. Create a buffer object only once and recycle it for multiple uses. Avoid mixing encoder and decoder buffers, since the buf:set() method frees the already allocated buffer space:

local options = {
  dict = { "commonly", "used", "string", "keys" },
}
local buf_enc = buffer.new(options)
local buf_dec = buffer.new(options)

local function encode(obj)
  return buf_enc:reset():encode(obj):get()
end

local function decode(str)
  return buf_dec:set(str):decode()
end

Streaming Serialization

In some contexts, it's desirable to do piecewise serialization of large datasets, also known as streaming.

This serialization format can be safely concatenated and supports streaming. Multiple encodings can simply be appended to a buffer and later decoded individually:

local buf = buffer.new()
buf:encode(obj1)
buf:encode(obj2)
local copy1 = buf:decode()
local copy2 = buf:decode()

Here's how to iterate over a stream:

while #buf ~= 0 do
  local obj = buf:decode()
  -- Do something with obj.
end

Since the serialization format doesn't prepend a length to its encoding, network applications may need to transmit the length, too.

Serialization Format Specification

This serialization format is designed for internal use by LuaJIT applications. Serialized data is upwards-compatible and portable across all supported LuaJIT platforms.

It's an 8-bit binary format and not human-readable. It uses e.g. embedded zeroes and stores embedded Lua string objects unmodified, which are 8-bit-clean, too. Encoded data can be safely concatenated for streaming and later decoded one top-level object at a time.

The encoding is reasonably compact, but tuned for maximum performance, not for minimum space usage. It compresses well with any of the common byte-oriented data compression algorithms.

Although documented here for reference, this format is explicitly not intended to be a 'public standard' for structured data interchange across computer languages (like JSON or MessagePack). Please do not use it as such.

The specification is given below as a context-free grammar with a top-level object as the starting point. Alternatives are separated by the | symbol and * indicates repeats. Grouping is implicit or indicated by {…}. Terminals are either plain hex numbers, encoded as bytes, or have a .format suffix.

object    → nil | false | true
          | null | lightud32 | lightud64
          | int | num | tab | tab_mt
          | int64 | uint64 | complex
          | string

nil       → 0x00
false     → 0x01
true      → 0x02

null      → 0x03                            // NULL lightuserdata
lightud32 → 0x04 data.I                   // 32 bit lightuserdata
lightud64 → 0x05 data.L                   // 64 bit lightuserdata

int       → 0x06 int.I                                 // int32_t
num       → 0x07 double.L

tab       → 0x08                                   // Empty table
          | 0x09 h.U h*{object object}          // Key/value hash
          | 0x0a a.U a*object                    // 0-based array
          | 0x0b a.U a*object h.U h*{object object}      // Mixed
          | 0x0c a.U (a-1)*object                // 1-based array
          | 0x0d a.U (a-1)*object h.U h*{object object}  // Mixed
tab_mt    → 0x0e (index-1).U tab          // Metatable dict entry

int64     → 0x10 int.L                             // FFI int64_t
uint64    → 0x11 uint.L                           // FFI uint64_t
complex   → 0x12 re.L im.L                         // FFI complex

string    → (0x20+len).U len*char.B
          | 0x0f (index-1).U                 // String dict entry

.B = 8 bit
.I = 32 bit little-endian
.L = 64 bit little-endian
.U = prefix-encoded 32 bit unsigned number n:
     0x00..0xdf   → n.B
     0xe0..0x1fdf → (0xe0|(((n-0xe0)>>8)&0x1f)).B ((n-0xe0)&0xff).B
   0x1fe0..       → 0xff n.I

Error handling

Many of the buffer methods can throw an error. Out-of-memory or usage errors are best caught with an outer wrapper for larger parts of code. There's not much one can do after that, anyway.

OTOH, you may want to catch some errors individually. Buffer methods need to receive the buffer object as the first argument. The Lua colon-syntax obj:method() does that implicitly. But to wrap a method with pcall(), the arguments need to be passed like this:

local ok, err = pcall(buf.encode, buf, obj)
if not ok then
  -- Handle error in err.
end

FFI caveats

The string buffer library has been designed to work well together with the FFI library. But due to the low-level nature of the FFI library, some care needs to be taken:

First, please remember that FFI pointers are zero-indexed. The space returned by buf:reserve() and buf:ref() starts at the returned pointer and ends before len bytes after that.

I.e. the first valid index is ptr[0] and the last valid index is ptr[len-1]. If the returned length is zero, there's no valid index at all. The returned pointer may even be NULL.

The space pointed to by the returned pointer is only valid as long as the buffer is not modified in any way (neither append, nor consume, nor reset, etc.). The pointer is also not a GC anchor for the buffer object itself.

Buffer data is only guaranteed to be byte-aligned. Casting the returned pointer to a data type with higher alignment may cause unaligned accesses. It depends on the CPU architecture whether this is allowed or not (it's always OK on x86/x64 and mostly OK on other modern architectures).

FFI pointers or references do not count as GC anchors for an underlying object. E.g. an array allocated with ffi.new() is anchored by buf:set(array, len), but not by buf:set(array+offset, len). The addition of the offset creates a new pointer, even when the offset is zero. In this case, you need to make sure there's still a reference to the original array as long as its contents are in use by the buffer.

Even though each LuaJIT VM instance is single-threaded (but you can create multiple VMs), FFI data structures can be accessed concurrently. Be careful when reading/writing FFI cdata from/to buffers to avoid concurrent accesses or modifications. In particular, the memory referenced by buf:set(cdata, len) must not be modified while buffer readers are working on it. Shared, but read-only memory mappings of files are OK, but only if the file does not change.


================================================ FILE: third_party/luajit/luajit/doc/ext_c_api.html ================================================ Lua/C API Extensions

LuaJIT adds some extensions to the standard Lua/C API. The LuaJIT include directory must be in the compiler search path (-Ipath) to be able to include the required header for C code:

#include "luajit.h"

Or for C++ code:

#include "lua.hpp"

luaJIT_setmode(L, idx, mode) — Control VM

This is a C API extension to allow control of the VM from C code. The full prototype of LuaJIT_setmode is:

LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode);

The returned status is either success (1) or failure (0). The second argument is either 0 or a stack index (similar to the other Lua/C API functions).

The third argument specifies the mode, which is 'or'ed with a flag. The flag can be LUAJIT_MODE_OFF to turn a feature off, LUAJIT_MODE_ON to turn a feature on, or LUAJIT_MODE_FLUSH to flush cached code.

The following modes are defined:

luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE|flag)

Turn the whole JIT compiler on or off or flush the whole cache of compiled code.

luaJIT_setmode(L, idx, LUAJIT_MODE_FUNC|flag)
luaJIT_setmode(L, idx, LUAJIT_MODE_ALLFUNC|flag)
luaJIT_setmode(L, idx, LUAJIT_MODE_ALLSUBFUNC|flag)

This sets the mode for the function at the stack index idx or the parent of the calling function (idx = 0). It either enables JIT compilation for a function, disables it and flushes any already compiled code, or only flushes already compiled code. This applies recursively to all sub-functions of the function with LUAJIT_MODE_ALLFUNC or only to the sub-functions with LUAJIT_MODE_ALLSUBFUNC.

luaJIT_setmode(L, trace,
  LUAJIT_MODE_TRACE|LUAJIT_MODE_FLUSH)

Flushes the specified root trace and all of its side traces from the cache. The code for the trace will be retained as long as there are any other traces which link to it.

luaJIT_setmode(L, idx, LUAJIT_MODE_WRAPCFUNC|flag)

This mode defines a wrapper function for calls to C functions. If called with LUAJIT_MODE_ON, the stack index at idx must be a lightuserdata object holding a pointer to the wrapper function. From now on, all C functions are called through the wrapper function. If called with LUAJIT_MODE_OFF this mode is turned off and all C functions are directly called.

The wrapper function can be used for debugging purposes or to catch and convert foreign exceptions. But please read the section on C++ exception interoperability first. Recommended usage can be seen in this C++ code excerpt:

#include <exception>
#include "lua.hpp"

// Catch C++ exceptions and convert them to Lua error messages.
// Customize as needed for your own exception classes.
static int wrap_exceptions(lua_State *L, lua_CFunction f)
{
  try {
    return f(L);  // Call wrapped function and return result.
  } catch (const char *s) {  // Catch and convert exceptions.
    lua_pushstring(L, s);
  } catch (std::exception& e) {
    lua_pushstring(L, e.what());
  } catch (...) {
    lua_pushliteral(L, "caught (...)");
  }
  return lua_error(L);  // Rethrow as a Lua error.
}

static int myinit(lua_State *L)
{
  ...
  // Define wrapper function and enable it.
  lua_pushlightuserdata(L, (void *)wrap_exceptions);
  luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_ON);
  lua_pop(L, 1);
  ...
}

Note that you can only define a single global wrapper function, so be careful when using this mechanism from multiple C++ modules. Also note that this mechanism is not without overhead.


================================================ FILE: third_party/luajit/luajit/doc/ext_ffi.html ================================================ FFI Library

The FFI library allows calling external C functions and using C data structures from pure Lua code.

The FFI library largely obviates the need to write tedious manual Lua/C bindings in C. No need to learn a separate binding language — it parses plain C declarations! These can be cut-n-pasted from C header files or reference manuals. It's up to the task of binding large libraries without the need for dealing with fragile binding generators.

The FFI library is tightly integrated into LuaJIT (it's not available as a separate module). The code generated by the JIT-compiler for accesses to C data structures from Lua code is on par with the code a C compiler would generate. Calls to C functions can be inlined in JIT-compiled code, unlike calls to functions bound via the classic Lua/C API.

This page gives a short introduction to the usage of the FFI library. Please use the FFI sub-topics in the navigation bar to learn more.

Motivating Example: Calling External C Functions

It's really easy to call an external C library function:

①
②


③local ffi = require("ffi")
ffi.cdef[[
int printf(const char *fmt, ...);
]]
ffi.C.printf("Hello %s!", "world")

So, let's pick that apart:

Load the FFI library.

Add a C declaration for the function. The part inside the double-brackets (in green) is just standard C syntax.

Call the named C function — Yes, it's that simple!

Actually, what goes on behind the scenes is far from simple: makes use of the standard C library namespace ffi.C. Indexing this namespace with a symbol name ("printf") automatically binds it to the standard C library. The result is a special kind of object which, when called, runs the printf function. The arguments passed to this function are automatically converted from Lua objects to the corresponding C types.

Ok, so maybe the use of printf() wasn't such a spectacular example. You could have done that with io.write() and string.format(), too. But you get the idea ...

So here's something to pop up a message box on Windows:

local ffi = require("ffi")
ffi.cdef[[
int MessageBoxA(void *w, const char *txt, const char *cap, int type);
]]
ffi.C.MessageBoxA(nil, "Hello world!", "Test", 0)

Bing! Again, that was far too easy, no?

Compare this with the effort required to bind that function using the classic Lua/C API: create an extra C file, add a C function that retrieves and checks the argument types passed from Lua and calls the actual C function, add a list of module functions and their names, add a luaopen_* function and register all module functions, compile and link it into a shared library (DLL), move it to the proper path, add Lua code that loads the module aaaand ... finally call the binding function. Phew!

Motivating Example: Using C Data Structures

The FFI library allows you to create and access C data structures. Of course, the main use for this is for interfacing with C functions. But they can be used stand-alone, too.

Lua is built upon high-level data types. They are flexible, extensible and dynamic. That's why we all love Lua so much. Alas, this can be inefficient for certain tasks, where you'd really want a low-level data type. E.g. a large array of a fixed structure needs to be implemented with a big table holding lots of tiny tables. This imposes both a substantial memory overhead as well as a performance overhead.

Here's a sketch of a library that operates on color images, plus a simple benchmark. First, the plain Lua version:

local floor = math.floor

local function image_ramp_green(n)
  local img = {}
  local f = 255/(n-1)
  for i=1,n do
    img[i] = { red = 0, green = floor((i-1)*f), blue = 0, alpha = 255 }
  end
  return img
end

local function image_to_gray(img, n)
  for i=1,n do
    local y = floor(0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue)
    img[i].red = y; img[i].green = y; img[i].blue = y
  end
end

local N = 400*400
local img = image_ramp_green(N)
for i=1,1000 do
  image_to_gray(img, N)
end

This creates a table with 160.000 pixels, each of which is a table holding four number values in the range of 0-255. First, an image with a green ramp is created (1D for simplicity), then the image is converted to grayscale 1000 times. Yes, that's silly, but I was in need of a simple example ...

And here's the FFI version. The modified parts have been marked in bold:

①





②

③
④






③
⑤local ffi = require("ffi")
ffi.cdef[[
typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel;
]]

local function image_ramp_green(n)
  local img = ffi.new("rgba_pixel[?]", n)
  local f = 255/(n-1)
  for i=0,n-1 do
    img[i].green = i*f
    img[i].alpha = 255
  end
  return img
end

local function image_to_grey(img, n)
  for i=0,n-1 do
    local y = 0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue
    img[i].red = y; img[i].green = y; img[i].blue = y
  end
end

local N = 400*400
local img = image_ramp_green(N)
for i=1,1000 do
  image_to_grey(img, N)
end

Ok, so that wasn't too difficult:

First, load the FFI library and declare the low-level data type. Here we choose a struct which holds four byte fields, one for each component of a 4x8 bit RGBA pixel.

Creating the data structure with ffi.new() is straightforward — the '?' is a placeholder for the number of elements of a variable-length array.

C arrays are zero-based, so the indexes have to run from 0 to n-1. One might want to allocate one more element instead to simplify converting legacy code.

Since ffi.new() zero-fills the array by default, we only need to set the green and the alpha fields.

The calls to math.floor() can be omitted here, because floating-point numbers are already truncated towards zero when converting them to an integer. This happens implicitly when the number is stored in the fields of each pixel.

Now let's have a look at the impact of the changes: first, memory consumption for the image is down from 22 Megabytes to 640 Kilobytes (400*400*4 bytes). That's a factor of 35x less! So, yes, tables do have a noticeable overhead. BTW: The original program would consume 40 Megabytes in plain Lua (on x64).

Next, performance: the pure Lua version runs in 9.57 seconds (52.9 seconds with the Lua interpreter) and the FFI version runs in 0.48 seconds on my machine (YMMV). That's a factor of 20x faster (110x faster than the Lua interpreter).

The avid reader may notice that converting the pure Lua version over to use array indexes for the colors ([1] instead of .red, [2] instead of .green etc.) ought to be more compact and faster. This is certainly true (by a factor of ~1.7x). Switching to a struct-of-arrays would help, too.

However, the resulting code would be less idiomatic and rather error-prone. And it still doesn't get even close to the performance of the FFI version of the code. Also, high-level data structures cannot be easily passed to other C functions, especially I/O functions, without undue conversion penalties.


================================================ FILE: third_party/luajit/luajit/doc/ext_ffi_api.html ================================================ ffi.* API Functions

This page describes the API functions provided by the FFI library in detail. It's recommended to read through the introduction and the FFI tutorial first.

Glossary

  • cdecl — An abstract C type declaration (a Lua string).
  • ctype — A C type object. This is a special kind of cdata returned by ffi.typeof(). It serves as a cdata constructor when called.
  • cdata — A C data object. It holds a value of the corresponding ctype.
  • ct — A C type specification which can be used for most of the API functions. Either a cdecl, a ctype or a cdata serving as a template type.
  • cb — A callback object. This is a C data object holding a special function pointer. Calling this function from C code runs an associated Lua function.
  • VLA — A variable-length array is declared with a ? instead of the number of elements, e.g. "int[?]". The number of elements (nelem) must be given when it's created.
  • VLS — A variable-length struct is a struct C type where the last element is a VLA. The same rules for declaration and creation apply.

Declaring and Accessing External Symbols

External symbols must be declared first and can then be accessed by indexing a C library namespace, which automatically binds the symbol to a specific library.

ffi.cdef(def)

Adds multiple C declarations for types or external symbols (named variables or functions). def must be a Lua string. It's recommended to use the syntactic sugar for string arguments as follows:

ffi.cdef[[
typedef struct foo { int a, b; } foo_t;  // Declare a struct and typedef.
int dofoo(foo_t *f, int n);  /* Declare an external C function. */
]]

The contents of the string (the part in green above) must be a sequence of C declarations, separated by semicolons. The trailing semicolon for a single declaration may be omitted.

Please note, that external symbols are only declared, but they are not bound to any specific address, yet. Binding is achieved with C library namespaces (see below).

C declarations are not passed through a C pre-processor, yet. No pre-processor tokens are allowed, except for #pragma pack. Replace #define in existing C header files with enum, static const or typedef and/or pass the files through an external C pre-processor (once). Be careful not to include unneeded or redundant declarations from unrelated header files.

ffi.C

This is the default C library namespace — note the uppercase 'C'. It binds to the default set of symbols or libraries on the target system. These are more or less the same as a C compiler would offer by default, without specifying extra link libraries.

On POSIX systems, this binds to symbols in the default or global namespace. This includes all exported symbols from the executable and any libraries loaded into the global namespace. This includes at least libc, libm, libdl (on Linux), libgcc (if compiled with GCC), as well as any exported symbols from the Lua/C API provided by LuaJIT itself.

On Windows systems, this binds to symbols exported from the *.exe, the lua51.dll (i.e. the Lua/C API provided by LuaJIT itself), the C runtime library LuaJIT was linked with (msvcrt*.dll), kernel32.dll, user32.dll and gdi32.dll.

clib = ffi.load(name [,global])

This loads the dynamic library given by name and returns a new C library namespace which binds to its symbols. On POSIX systems, if global is true, the library symbols are loaded into the global namespace, too.

If name is a path, the library is loaded from this path. Otherwise name is canonicalized in a system-dependent way and searched in the default search path for dynamic libraries:

On POSIX systems, if the name contains no dot, the extension .so is appended. Also, the lib prefix is prepended if necessary. So ffi.load("z") looks for "libz.so" in the default shared library search path.

On Windows systems, if the name contains no dot, the extension .dll is appended. So ffi.load("ws2_32") looks for "ws2_32.dll" in the default DLL search path.

Creating cdata Objects

The following API functions create cdata objects (type() returns "cdata"). All created cdata objects are garbage collected.

cdata = ffi.new(ct [,nelem] [,init...])
cdata = ctype([nelem,] [init...])

Creates a cdata object for the given ct. VLA/VLS types require the nelem argument. The second syntax uses a ctype as a constructor and is otherwise fully equivalent.

The cdata object is initialized according to the rules for initializers, using the optional init arguments. Excess initializers cause an error.

Performance notice: if you want to create many objects of one kind, parse the cdecl only once and get its ctype with ffi.typeof(). Then use the ctype as a constructor repeatedly.

Please note, that an anonymous struct declaration implicitly creates a new and distinguished ctype every time you use it for ffi.new(). This is probably not what you want, especially if you create more than one cdata object. Different anonymous structs are not considered assignment-compatible by the C standard, even though they may have the same fields! Also, they are considered different types by the JIT-compiler, which may cause an excessive number of traces. It's strongly suggested to either declare a named struct or typedef with ffi.cdef() or to create a single ctype object for an anonymous struct with ffi.typeof().

ctype = ffi.typeof(ct)

Creates a ctype object for the given ct.

This function is especially useful to parse a cdecl only once and then use the resulting ctype object as a constructor.

cdata = ffi.cast(ct, init)

Creates a scalar cdata object for the given ct. The cdata object is initialized with init using the "cast" variant of the C type conversion rules.

This functions is mainly useful to override the pointer compatibility checks or to convert pointers to addresses or vice versa.

ctype = ffi.metatype(ct, metatable)

Creates a ctype object for the given ct and associates it with a metatable. Only struct/union types, complex numbers and vectors are allowed. Other types may be wrapped in a struct, if needed.

The association with a metatable is permanent and cannot be changed afterwards. Neither the contents of the metatable nor the contents of an __index table (if any) may be modified afterwards. The associated metatable automatically applies to all uses of this type, no matter how the objects are created or where they originate from. Note that predefined operations on types have precedence (e.g. declared field names cannot be overridden).

All standard Lua metamethods are implemented. These are called directly, without shortcuts, and on any mix of types. For binary operations, the left operand is checked first for a valid ctype metamethod. The __gc metamethod only applies to struct/union types and performs an implicit ffi.gc() call during creation of an instance.

cdata = ffi.gc(cdata, finalizer)

Associates a finalizer with a pointer or aggregate cdata object. The cdata object is returned unchanged.

This function allows safe integration of unmanaged resources into the automatic memory management of the LuaJIT garbage collector. Typical usage:

local p = ffi.gc(ffi.C.malloc(n), ffi.C.free)
...
p = nil -- Last reference to p is gone.
-- GC will eventually run finalizer: ffi.C.free(p)

A cdata finalizer works like the __gc metamethod for userdata objects: when the last reference to a cdata object is gone, the associated finalizer is called with the cdata object as an argument. The finalizer can be a Lua function or a cdata function or cdata function pointer. An existing finalizer can be removed by setting a nil finalizer, e.g. right before explicitly deleting a resource:

ffi.C.free(ffi.gc(p, nil)) -- Manually free the memory.

C Type Information

The following API functions return information about C types. They are most useful for inspecting cdata objects.

size = ffi.sizeof(ct [,nelem])

Returns the size of ct in bytes. Returns nil if the size is not known (e.g. for "void" or function types). Requires nelem for VLA/VLS types, except for cdata objects.

align = ffi.alignof(ct)

Returns the minimum required alignment for ct in bytes.

ofs [,bpos,bsize] = ffi.offsetof(ct, field)

Returns the offset (in bytes) of field relative to the start of ct, which must be a struct. Additionally returns the position and the field size (in bits) for bit fields.

status = ffi.istype(ct, obj)

Returns true if obj has the C type given by ct. Returns false otherwise.

C type qualifiers (const etc.) are ignored. Pointers are checked with the standard pointer compatibility rules, but without any special treatment for void *. If ct specifies a struct/union, then a pointer to this type is accepted, too. Otherwise the types must match exactly.

Note: this function accepts all kinds of Lua objects for the obj argument, but always returns false for non-cdata objects.

Utility Functions

err = ffi.errno([newerr])

Returns the error number set by the last C function call which indicated an error condition. If the optional newerr argument is present, the error number is set to the new value and the previous value is returned.

This function offers a portable and OS-independent way to get and set the error number. Note that only some C functions set the error number. And it's only significant if the function actually indicated an error condition (e.g. with a return value of -1 or NULL). Otherwise, it may or may not contain any previously set value.

You're advised to call this function only when needed and as close as possible after the return of the related C function. The errno value is preserved across hooks, memory allocations, invocations of the JIT compiler and other internal VM activity. The same applies to the value returned by GetLastError() on Windows, but you need to declare and call it yourself.

str = ffi.string(ptr [,len])

Creates an interned Lua string from the data pointed to by ptr.

If the optional argument len is missing, ptr is converted to a "char *" and the data is assumed to be zero-terminated. The length of the string is computed with strlen().

Otherwise ptr is converted to a "void *" and len gives the length of the data. The data may contain embedded zeros and need not be byte-oriented (though this may cause endianess issues).

This function is mainly useful to convert (temporary) "const char *" pointers returned by C functions to Lua strings and store them or pass them to other functions expecting a Lua string. The Lua string is an (interned) copy of the data and bears no relation to the original data area anymore. Lua strings are 8 bit clean and may be used to hold arbitrary, non-character data.

Performance notice: it's faster to pass the length of the string, if it's known. E.g. when the length is returned by a C call like sprintf().

ffi.copy(dst, src, len)
ffi.copy(dst, str)

Copies the data pointed to by src to dst. dst is converted to a "void *" and src is converted to a "const void *".

In the first syntax, len gives the number of bytes to copy. Caveat: if src is a Lua string, then len must not exceed #src+1.

In the second syntax, the source of the copy must be a Lua string. All bytes of the string plus a zero-terminator are copied to dst (i.e. #src+1 bytes).

Performance notice: ffi.copy() may be used as a faster (inlinable) replacement for the C library functions memcpy(), strcpy() and strncpy().

ffi.fill(dst, len [,c])

Fills the data pointed to by dst with len constant bytes, given by c. If c is omitted, the data is zero-filled.

Performance notice: ffi.fill() may be used as a faster (inlinable) replacement for the C library function memset(dst, c, len). Please note the different order of arguments!

Target-specific Information

status = ffi.abi(param)

Returns true if param (a Lua string) applies for the target ABI (Application Binary Interface). Returns false otherwise. The following parameters are currently defined:

Parameter Description
32bit32 bit architecture
64bit64 bit architecture
leLittle-endian architecture
beBig-endian architecture
fpuTarget has a hardware FPU
softfpsoftfp calling conventions
hardfphardfp calling conventions
eabiEABI variant of the standard ABI
winWindows variant of the standard ABI
uwpUniversal Windows Platform
gc6464 bit GC references

ffi.os

Contains the target OS name. Same contents as jit.os.

ffi.arch

Contains the target architecture name. Same contents as jit.arch.

Methods for Callbacks

The C types for callbacks have some extra methods:

cb:free()

Free the resources associated with a callback. The associated Lua function is unanchored and may be garbage collected. The callback function pointer is no longer valid and must not be called again (it may be reused by a subsequently created callback).

cb:set(func)

Associate a new Lua function with a callback. The C type of the callback and the callback function pointer are unchanged.

This method is useful to dynamically switch the receiver of callbacks without creating a new callback each time and registering it again (e.g. with a GUI library).

Extended Standard Library Functions

The following standard library functions have been extended to work with cdata objects:

n = tonumber(cdata)

Converts a number cdata object to a double and returns it as a Lua number. This is particularly useful for boxed 64 bit integer values. Caveat: this conversion may incur a precision loss.

s = tostring(cdata)

Returns a string representation of the value of 64 bit integers ("nnnLL" or "nnnULL") or complex numbers ("re±imi"). Otherwise returns a string representation of the C type of a ctype object ("ctype<type>") or a cdata object ("cdata<type>: address"), unless you override it with a __tostring metamethod (see ffi.metatype()).

iter, obj, start = pairs(cdata)
iter, obj, start = ipairs(cdata)

Calls the __pairs or __ipairs metamethod of the corresponding ctype.

Extensions to the Lua Parser

The parser for Lua source code treats numeric literals with the suffixes LL or ULL as signed or unsigned 64 bit integers. Case doesn't matter, but uppercase is recommended for readability. It handles decimal (42LL), hexadecimal (0x2aLL) and binary (0b101010LL) literals.

The imaginary part of complex numbers can be specified by suffixing number literals with i or I, e.g. 12.5i. Caveat: you'll need to use 1i to get an imaginary part with the value one, since i itself still refers to a variable named i.


================================================ FILE: third_party/luajit/luajit/doc/ext_ffi_semantics.html ================================================ FFI Semantics

This page describes the detailed semantics underlying the FFI library and its interaction with both Lua and C code.

Given that the FFI library is designed to interface with C code and that declarations can be written in plain C syntax, it closely follows the C language semantics, wherever possible. Some minor concessions are needed for smoother interoperation with Lua language semantics.

Please don't be overwhelmed by the contents of this page — this is a reference and you may need to consult it, if in doubt. It doesn't hurt to skim this page, but most of the semantics "just work" as you'd expect them to work. It should be straightforward to write applications using the LuaJIT FFI for developers with a C or C++ background.

C Language Support

The FFI library has a built-in C parser with a minimal memory footprint. It's used by the ffi.* library functions to declare C types or external symbols.

Its only purpose is to parse C declarations, as found e.g. in C header files. Although it does evaluate constant expressions, it's not a C compiler. The body of inline C function definitions is simply ignored.

Also, this is not a validating C parser. It expects and accepts correctly formed C declarations, but it may choose to ignore bad declarations or show rather generic error messages. If in doubt, please check the input against your favorite C compiler.

The C parser complies to the C99 language standard plus the following extensions:

  • The '\e' escape in character and string literals.
  • The C99/C++ boolean type, declared with the keywords bool or _Bool.
  • Complex numbers, declared with the keywords complex or _Complex.
  • Two complex number types: complex (aka complex double) and complex float.
  • Vector types, declared with the GCC mode or vector_size attribute.
  • Unnamed ('transparent') struct/union fields inside a struct/union.
  • Incomplete enum declarations, handled like incomplete struct declarations.
  • Unnamed enum fields inside a struct/union. This is similar to a scoped C++ enum, except that declared constants are visible in the global namespace, too.
  • Scoped static const declarations inside a struct/union (from C++).
  • Zero-length arrays ([0]), empty struct/union, variable-length arrays (VLA, [?]) and variable-length structs (VLS, with a trailing VLA).
  • C++ reference types (int &x).
  • Alternate GCC keywords with '__', e.g. __const__.
  • GCC __attribute__ with the following attributes: aligned, packed, mode, vector_size, cdecl, fastcall, stdcall, thiscall.
  • The GCC __extension__ keyword and the GCC __alignof__ operator.
  • GCC __asm__("symname") symbol name redirection for function declarations.
  • MSVC keywords for fixed-length types: __int8, __int16, __int32 and __int64.
  • MSVC __cdecl, __fastcall, __stdcall, __thiscall, __ptr32, __ptr64, __declspec(align(n)) and #pragma pack.
  • All other GCC/MSVC-specific attributes are ignored.

The following C types are predefined by the C parser (like a typedef, except re-declarations will be ignored):

  • Vararg handling: va_list, __builtin_va_list, __gnuc_va_list.
  • From <stddef.h>: ptrdiff_t, size_t, wchar_t.
  • From <stdint.h>: int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t, intptr_t, uintptr_t.
  • From <unistd.h> (POSIX): ssize_t.

You're encouraged to use these types in preference to compiler-specific extensions or target-dependent standard types. E.g. char differs in signedness and long differs in size, depending on the target architecture and platform ABI.

The following C features are not supported:

  • A declaration must always have a type specifier; it doesn't default to an int type.
  • Old-style empty function declarations (K&R) are not allowed. All C functions must have a proper prototype declaration. A function declared without parameters (int foo();) is treated as a function taking zero arguments, like in C++.
  • The long double C type is parsed correctly, but there's no support for the related conversions, accesses or arithmetic operations.
  • Wide character strings and character literals are not supported.
  • See below for features that are currently not implemented.

C Type Conversion Rules

Conversions from C types to Lua objects

These conversion rules apply for read accesses to C types: indexing pointers, arrays or struct/union types; reading external variables or constant values; retrieving return values from C calls:

Input Conversion Output
int8_t, int16_tsign-ext int32_tdoublenumber
uint8_t, uint16_tzero-ext int32_tdoublenumber
int32_t, uint32_tdoublenumber
int64_t, uint64_tboxed value64 bit int cdata
double, floatdoublenumber
bool0 → false, otherwise trueboolean
enumboxed valueenum cdata
Complex numberboxed valuecomplex cdata
Vectorboxed valuevector cdata
Pointerboxed valuepointer cdata
Arrayboxed referencereference cdata
struct/unionboxed referencereference cdata

Bitfields are treated like their underlying type.

Reference types are dereferenced before a conversion can take place — the conversion is applied to the C type pointed to by the reference.

Conversions from Lua objects to C types

These conversion rules apply for write accesses to C types: indexing pointers, arrays or struct/union types; initializing cdata objects; casts to C types; writing to external variables; passing arguments to C calls:

Input Conversion Output
numberdouble
booleanfalse → 0, true → 1bool
nilNULL(void *)
lightuserdatalightuserdata address →(void *)
userdatauserdata payload →(void *)
io.* fileget FILE * handle →(void *)
stringmatch against enum constantenum
stringcopy string data + zero-byteint8_t[], uint8_t[]
stringstring data →const char[]
functioncreate callbackC function type
tabletable initializerArray
tabletable initializerstruct/union
cdatacdata payload →C type

If the result type of this conversion doesn't match the C type of the destination, the conversion rules between C types are applied.

Reference types are immutable after initialization ("no re-seating of references"). For initialization purposes or when passing values to reference parameters, they are treated like pointers. Note that unlike in C++, there's no way to implement automatic reference generation of variables under the Lua language semantics. If you want to call a function with a reference parameter, you need to explicitly pass a one-element array.

Conversions between C types

These conversion rules are more or less the same as the standard C conversion rules. Some rules only apply to casts, or require pointer or type compatibility:

Input Conversion Output
Signed integernarrow or sign-extendInteger
Unsigned integernarrow or zero-extendInteger
Integerrounddouble, float
double, floattrunc int32_tnarrow(u)int8_t, (u)int16_t
double, floattrunc(u)int32_t, (u)int64_t
double, floatroundfloat, double
Numbern == 0 → 0, otherwise 1bool
boolfalse → 0, true → 1Number
Complex numberconvert real partNumber
Numberconvert real part, imag = 0Complex number
Complex numberconvert real and imag partComplex number
Numberconvert scalar and replicateVector
Vectorcopy (same size)Vector
struct/uniontake base address (compat)Pointer
Arraytake base address (compat)Pointer
Functiontake function addressFunction pointer
Numberconvert via uintptr_t (cast)Pointer
Pointerconvert address (compat/cast)Pointer
Pointerconvert address (cast)Integer
Arrayconvert base address (cast)Integer
Arraycopy (compat)Array
struct/unioncopy (identical type)struct/union

Bitfields or enum types are treated like their underlying type.

Conversions not listed above will raise an error. E.g. it's not possible to convert a pointer to a complex number or vice versa.

Conversions for vararg C function arguments

The following default conversion rules apply when passing Lua objects to the variable argument part of vararg C functions:

Input Conversion Output
numberdouble
booleanfalse → 0, true → 1bool
nilNULL(void *)
userdatauserdata payload →(void *)
lightuserdatalightuserdata address →(void *)
stringstring data →const char *
float cdatadouble
Array cdatatake base addressElement pointer
struct/union cdatatake base addressstruct/union pointer
Function cdatatake function addressFunction pointer
Any other cdatano conversionC type

To pass a Lua object, other than a cdata object, as a specific type, you need to override the conversion rules: create a temporary cdata object with a constructor or a cast and initialize it with the value to pass:

Assuming x is a Lua number, here's how to pass it as an integer to a vararg function:

ffi.cdef[[
int printf(const char *fmt, ...);
]]
ffi.C.printf("integer value: %d\n", ffi.new("int", x))

If you don't do this, the default Lua number → double conversion rule applies. A vararg C function expecting an integer will see a garbled or uninitialized value.

Initializers

Creating a cdata object with ffi.new() or the equivalent constructor syntax always initializes its contents, too. Different rules apply, depending on the number of optional initializers and the C types involved:

  • If no initializers are given, the object is filled with zero bytes.
  • Scalar types (numbers and pointers) accept a single initializer. The Lua object is converted to the scalar C type.
  • Valarrays (complex numbers and vectors) are treated like scalars when a single initializer is given. Otherwise they are treated like regular arrays.
  • Aggregate types (arrays and structs) accept either a single cdata initializer of the same type (copy constructor), a single table initializer, or a flat list of initializers.
  • The elements of an array are initialized, starting at index zero. If a single initializer is given for an array, it's repeated for all remaining elements. This doesn't happen if two or more initializers are given: all remaining uninitialized elements are filled with zero bytes.
  • Byte arrays may also be initialized with a Lua string. This copies the whole string plus a terminating zero-byte. The copy stops early only if the array has a known, fixed size.
  • The fields of a struct are initialized in the order of their declaration. Uninitialized fields are filled with zero bytes.
  • Only the first field of a union can be initialized with a flat initializer.
  • Elements or fields which are aggregates themselves are initialized with a single initializer, but this may be a table initializer or a compatible aggregate.
  • Excess initializers cause an error.

Table Initializers

The following rules apply if a Lua table is used to initialize an Array or a struct/union:

  • If the table index [0] is non-nil, then the table is assumed to be zero-based. Otherwise it's assumed to be one-based.
  • Array elements, starting at index zero, are initialized one-by-one with the consecutive table elements, starting at either index [0] or [1]. This process stops at the first nil table element.
  • If exactly one array element was initialized, it's repeated for all the remaining elements. Otherwise all remaining uninitialized elements are filled with zero bytes.
  • The above logic only applies to arrays with a known fixed size. A VLA is only initialized with the element(s) given in the table. Depending on the use case, you may need to explicitly add a NULL or 0 terminator to a VLA.
  • A struct/union can be initialized in the order of the declaration of its fields. Each field is initialized with consecutive table elements, starting at either index [0] or [1]. This process stops at the first nil table element.
  • Otherwise, if neither index [0] nor [1] is present, a struct/union is initialized by looking up each field name (as a string key) in the table. Each non-nil value is used to initialize the corresponding field.
  • Uninitialized fields of a struct are filled with zero bytes, except for the trailing VLA of a VLS.
  • Initialization of a union stops after one field has been initialized. If no field has been initialized, the union is filled with zero bytes.
  • Elements or fields which are aggregates themselves are initialized with a single initializer, but this may be a nested table initializer (or a compatible aggregate).
  • Excess initializers for an array cause an error. Excess initializers for a struct/union are ignored. Unrelated table entries are ignored, too.

Example:

local ffi = require("ffi")

ffi.cdef[[
struct foo { int a, b; };
union bar { int i; double d; };
struct nested { int x; struct foo y; };
]]

ffi.new("int[3]", {})            --> 0, 0, 0
ffi.new("int[3]", {1})           --> 1, 1, 1
ffi.new("int[3]", {1,2})         --> 1, 2, 0
ffi.new("int[3]", {1,2,3})       --> 1, 2, 3
ffi.new("int[3]", {[0]=1})       --> 1, 1, 1
ffi.new("int[3]", {[0]=1,2})     --> 1, 2, 0
ffi.new("int[3]", {[0]=1,2,3})   --> 1, 2, 3
ffi.new("int[3]", {[0]=1,2,3,4}) --> error: too many initializers

ffi.new("struct foo", {})            --> a = 0, b = 0
ffi.new("struct foo", {1})           --> a = 1, b = 0
ffi.new("struct foo", {1,2})         --> a = 1, b = 2
ffi.new("struct foo", {[0]=1,2})     --> a = 1, b = 2
ffi.new("struct foo", {b=2})         --> a = 0, b = 2
ffi.new("struct foo", {a=1,b=2,c=3}) --> a = 1, b = 2  'c' is ignored

ffi.new("union bar", {})        --> i = 0, d = 0.0
ffi.new("union bar", {1})       --> i = 1, d = ?
ffi.new("union bar", {[0]=1,2}) --> i = 1, d = ?    '2' is ignored
ffi.new("union bar", {d=2})     --> i = ?, d = 2.0

ffi.new("struct nested", {1,{2,3}})     --> x = 1, y.a = 2, y.b = 3
ffi.new("struct nested", {x=1,y={2,3}}) --> x = 1, y.a = 2, y.b = 3

Operations on cdata Objects

All standard Lua operators can be applied to cdata objects or a mix of a cdata object and another Lua object. The following list shows the predefined operations.

Reference types are dereferenced before performing each of the operations below — the operation is applied to the C type pointed to by the reference.

The predefined operations are always tried first before deferring to a metamethod or index table (if any) for the corresponding ctype (except for __new). An error is raised if the metamethod lookup or index table lookup fails.

Indexing a cdata object

  • Indexing a pointer/array: a cdata pointer/array can be indexed by a cdata number or a Lua number. The element address is computed as the base address plus the number value multiplied by the element size in bytes. A read access loads the element value and converts it to a Lua object. A write access converts a Lua object to the element type and stores the converted value to the element. An error is raised if the element size is undefined or a write access to a constant element is attempted.
  • Dereferencing a struct/union field: a cdata struct/union or a pointer to a struct/union can be dereferenced by a string key, giving the field name. The field address is computed as the base address plus the relative offset of the field. A read access loads the field value and converts it to a Lua object. A write access converts a Lua object to the field type and stores the converted value to the field. An error is raised if a write access to a constant struct/union or a constant field is attempted. Scoped enum constants or static constants are treated like a constant field.
  • Indexing a complex number: a complex number can be indexed either by a cdata number or a Lua number with the values 0 or 1, or by the strings "re" or "im". A read access loads the real part ([0], .re) or the imaginary part ([1], .im) part of a complex number and converts it to a Lua number. The sub-parts of a complex number are immutable — assigning to an index of a complex number raises an error. Accessing out-of-bound indexes returns unspecified results, but is guaranteed not to trigger memory access violations.
  • Indexing a vector: a vector is treated like an array for indexing purposes, except the vector elements are immutable — assigning to an index of a vector raises an error.

A ctype object can be indexed with a string key, too. The only predefined operation is reading scoped constants of struct/union types. All other accesses defer to the corresponding metamethods or index tables (if any).

Note: since there's (deliberately) no address-of operator, a cdata object holding a value type is effectively immutable after initialization. The JIT compiler benefits from this fact when applying certain optimizations.

As a consequence, the elements of complex numbers and vectors are immutable. But the elements of an aggregate holding these types may be modified, of course. I.e. you cannot assign to foo.c.im, but you can assign a (newly created) complex number to foo.c.

The JIT compiler implements strict aliasing rules: accesses to different types do not alias, except for differences in signedness (this applies even to char pointers, unlike C99). Type punning through unions is explicitly detected and allowed.

Calling a cdata object

  • Constructor: a ctype object can be called and used as a constructor. This is equivalent to ffi.new(ct, ...), unless a __new metamethod is defined. The __new metamethod is called with the ctype object plus any other arguments passed to the constructor. Note that you have to use ffi.new inside the metamethod, since calling ct(...) would cause infinite recursion.
  • C function call: a cdata function or cdata function pointer can be called. The passed arguments are converted to the C types of the parameters given by the function declaration. Arguments passed to the variable argument part of vararg C function use special conversion rules. This C function is called and the return value (if any) is converted to a Lua object.
    On Windows/x86 systems, __stdcall functions are automatically detected, and a function declared as __cdecl (the default) is silently fixed up after the first call.

Arithmetic on cdata objects

  • Pointer arithmetic: a cdata pointer/array and a cdata number or a Lua number can be added or subtracted. The number must be on the right-hand side for a subtraction. The result is a pointer of the same type with an address plus or minus the number value multiplied by the element size in bytes. An error is raised if the element size is undefined.
  • Pointer difference: two compatible cdata pointers/arrays can be subtracted. The result is the difference between their addresses, divided by the element size in bytes. An error is raised if the element size is undefined or zero.
  • 64 bit integer arithmetic: the standard arithmetic operators (+ - * / % ^ and unary minus) can be applied to two cdata numbers, or a cdata number and a Lua number. If one of them is an uint64_t, the other side is converted to an uint64_t and an unsigned arithmetic operation is performed. Otherwise, both sides are converted to an int64_t and a signed arithmetic operation is performed. The result is a boxed 64 bit cdata object.
    If one of the operands is an enum and the other operand is a string, the string is converted to the value of a matching enum constant before the above conversion.
    These rules ensure that 64 bit integers are "sticky". Any expression involving at least one 64 bit integer operand results in another one. The undefined cases for the division, modulo and power operators return 2LL ^ 63 or 2ULL ^ 63.
    You'll have to explicitly convert a 64 bit integer to a Lua number (e.g. for regular floating-point calculations) with tonumber(). But note this may incur a precision loss.
  • 64 bit bitwise operations: the rules for 64 bit arithmetic operators apply analogously.
    Unlike the other bit.* operations, bit.tobit() converts a cdata number via int64_t to int32_t and returns a Lua number.
    For bit.band(), bit.bor() and bit.bxor(), the conversion to int64_t or uint64_t applies to all arguments, if any argument is a cdata number.
    For all other operations, only the first argument is used to determine the output type. This implies that a cdata number as a shift count for shifts and rotates is accepted, but that alone does not cause a cdata number output.

Comparisons of cdata objects

  • Pointer comparison: two compatible cdata pointers/arrays can be compared. The result is the same as an unsigned comparison of their addresses. nil is treated like a NULL pointer, which is compatible with any other pointer type.
  • 64 bit integer comparison: two cdata numbers, or a cdata number and a Lua number can be compared with each other. If one of them is an uint64_t, the other side is converted to an uint64_t and an unsigned comparison is performed. Otherwise, both sides are converted to an int64_t and a signed comparison is performed.
    If one of the operands is an enum and the other operand is a string, the string is converted to the value of a matching enum constant before the above conversion.
  • Comparisons for equality/inequality never raise an error. Even incompatible pointers can be compared for equality by address. Any other incompatible comparison (also with non-cdata objects) treats the two sides as unequal.

cdata objects as table keys

Lua tables may be indexed by cdata objects, but this doesn't provide any useful semantics — cdata objects are unsuitable as table keys!

A cdata object is treated like any other garbage-collected object and is hashed and compared by its address for table indexing. Since there's no interning for cdata value types, the same value may be boxed in different cdata objects with different addresses. Thus, t[1LL+1LL] and t[2LL] usually do not point to the same hash slot, and they certainly do not point to the same hash slot as t[2].

It would seriously drive up implementation complexity and slow down the common case, if one were to add extra handling for by-value hashing and comparisons to Lua tables. Given the ubiquity of their use inside the VM, this is not acceptable.

There are three viable alternatives, if you really need to use cdata objects as keys:

  • If you can get by with the precision of Lua numbers (52 bits), then use tonumber() on a cdata number or combine multiple fields of a cdata aggregate to a Lua number. Then use the resulting Lua number as a key when indexing tables.
    One obvious benefit: t[tonumber(2LL)] does point to the same slot as t[2].
  • Otherwise, use either tostring() on 64 bit integers or complex numbers or combine multiple fields of a cdata aggregate to a Lua string (e.g. with ffi.string()). Then use the resulting Lua string as a key when indexing tables.
  • Create your own specialized hash table implementation using the C types provided by the FFI library, just like you would in C code. Ultimately, this may give much better performance than the other alternatives or what a generic by-value hash table could possibly provide.

Parameterized Types

To facilitate some abstractions, the two functions ffi.typeof and ffi.cdef support parameterized types in C declarations. Note: none of the other API functions taking a cdecl allow this.

Any place you can write a typedef name, an identifier or a number in a declaration, you can write $ (the dollar sign) instead. These placeholders are replaced in order of appearance with the arguments following the cdecl string:

-- Declare a struct with a parameterized field type and name:
ffi.cdef([[
typedef struct { $ $; } foo_t;
]], type1, name1)

-- Anonymous struct with dynamic names:
local bar_t = ffi.typeof("struct { int $, $; }", name1, name2)
-- Derived pointer type:
local bar_ptr_t = ffi.typeof("$ *", bar_t)

-- Parameterized dimensions work even where a VLA won't work:
local matrix_t = ffi.typeof("uint8_t[$][$]", width, height)

Caveat: this is not simple text substitution! A passed ctype or cdata object is treated like the underlying type, a passed string is considered an identifier and a number is considered a number. You must not mix this up: e.g. passing "int" as a string doesn't work in place of a type, you'd need to use ffi.typeof("int") instead.

The main use for parameterized types are libraries implementing abstract data types (» example), similar to what can be achieved with C++ template metaprogramming. Another use case are derived types of anonymous structs, which avoids pollution of the global struct namespace.

Please note that parameterized types are a nice tool and indispensable for certain use cases. But you'll want to use them sparingly in regular code, e.g. when all types are actually fixed.

Garbage Collection of cdata Objects

All explicitly (ffi.new(), ffi.cast() etc.) or implicitly (accessors) created cdata objects are garbage collected. You need to ensure to retain valid references to cdata objects somewhere on a Lua stack, an upvalue or in a Lua table while they are still in use. Once the last reference to a cdata object is gone, the garbage collector will automatically free the memory used by it (at the end of the next GC cycle).

Please note, that pointers themselves are cdata objects, however they are not followed by the garbage collector. So e.g. if you assign a cdata array to a pointer, you must keep the cdata object holding the array alive as long as the pointer is still in use:

ffi.cdef[[
typedef struct { int *a; } foo_t;
]]

local s = ffi.new("foo_t", ffi.new("int[10]")) -- WRONG!

local a = ffi.new("int[10]") -- OK
local s = ffi.new("foo_t", a)
-- Now do something with 's', but keep 'a' alive until you're done.

Similar rules apply for Lua strings which are implicitly converted to "const char *": the string object itself must be referenced somewhere or it'll be garbage collected eventually. The pointer will then point to stale data, which may have already been overwritten. Note that string literals are automatically kept alive as long as the function containing it (actually its prototype) is not garbage collected.

Objects which are passed as an argument to an external C function are kept alive until the call returns. So it's generally safe to create temporary cdata objects in argument lists. This is a common idiom for passing specific C types to vararg functions.

Memory areas returned by C functions (e.g. from malloc()) must be manually managed, of course (or use ffi.gc()). Pointers to cdata objects are indistinguishable from pointers returned by C functions (which is one of the reasons why the GC cannot follow them).

Callbacks

The LuaJIT FFI automatically generates special callback functions whenever a Lua function is converted to a C function pointer. This associates the generated callback function pointer with the C type of the function pointer and the Lua function object (closure).

This can happen implicitly due to the usual conversions, e.g. when passing a Lua function to a function pointer argument. Or, you can use ffi.cast() to explicitly cast a Lua function to a C function pointer.

Currently, only certain C function types can be used as callback functions. Neither C vararg functions nor functions with pass-by-value aggregate argument or result types are supported. There are no restrictions on the kind of Lua functions that can be called from the callback — no checks for the proper number of arguments are made. The return value of the Lua function will be converted to the result type, and an error will be thrown for invalid conversions.

It's allowed to throw errors across a callback invocation, but it's not advisable in general. Do this only if you know the C function, that called the callback, copes with the forced stack unwinding and doesn't leak resources.

One thing that's not allowed, is to let an FFI call into a C function get JIT-compiled, which in turn calls a callback, calling into Lua again. Usually this attempt is caught by the interpreter first and the C function is blacklisted for compilation.

However, this heuristic may fail under specific circumstances: e.g. a message polling function might not run Lua callbacks right away and the call gets JIT-compiled. If it later happens to call back into Lua (e.g. a rarely invoked error callback), you'll get a VM PANIC with the message "bad callback". Then you'll need to manually turn off JIT-compilation with jit.off() for the surrounding Lua function that invokes such a message polling function (or similar).

Callback resource handling

Callbacks take up resources — you can only have a limited number of them at the same time (500 - 1000, depending on the architecture). The associated Lua functions are anchored to prevent garbage collection, too.

Callbacks due to implicit conversions are permanent! There is no way to guess their lifetime, since the C side might store the function pointer for later use (typical for GUI toolkits). The associated resources cannot be reclaimed until termination:

ffi.cdef[[
typedef int (__stdcall *WNDENUMPROC)(void *hwnd, intptr_t l);
int EnumWindows(WNDENUMPROC func, intptr_t l);
]]

-- Implicit conversion to a callback via function pointer argument.
local count = 0
ffi.C.EnumWindows(function(hwnd, l)
  count = count + 1
  return true
end, 0)
-- The callback is permanent and its resources cannot be reclaimed!
-- Ok, so this may not be a problem, if you do this only once.

Note: this example shows that you must properly declare __stdcall callbacks on Windows/x86 systems. The calling convention cannot be automatically detected, unlike for __stdcall calls to Windows functions.

For some use cases, it's necessary to free up the resources or to dynamically redirect callbacks. Use an explicit cast to a C function pointer and keep the resulting cdata object. Then use the cb:free() or cb:set() methods on the cdata object:

-- Explicitly convert to a callback via cast.
local count = 0
local cb = ffi.cast("WNDENUMPROC", function(hwnd, l)
  count = count + 1
  return true
end)

-- Pass it to a C function.
ffi.C.EnumWindows(cb, 0)
-- EnumWindows doesn't need the callback after it returns, so free it.

cb:free()
-- The callback function pointer is no longer valid and its resources
-- will be reclaimed. The created Lua closure will be garbage collected.

Callback performance

Callbacks are slow! First, the C to Lua transition itself has an unavoidable cost, similar to a lua_call() or lua_pcall(). Argument and result marshalling add to that cost. And finally, neither the C compiler nor LuaJIT can inline or optimize across the language barrier and hoist repeated computations out of a callback function.

Do not use callbacks for performance-sensitive work: e.g. consider a numerical integration routine which takes a user-defined function to integrate over. It's a bad idea to call a user-defined Lua function from C code millions of times. The callback overhead will be absolutely detrimental for performance.

It's considerably faster to write the numerical integration routine itself in Lua — the JIT compiler will be able to inline the user-defined function and optimize it together with its calling context, with very competitive performance.

As a general guideline: use callbacks only when you must, because of existing C APIs. E.g. callback performance is irrelevant for a GUI application, which waits for user input most of the time, anyway.

For new designs avoid push-style APIs: a C function repeatedly calling a callback for each result. Instead, use pull-style APIs: call a C function repeatedly to get a new result. Calls from Lua to C via the FFI are much faster than the other way round. Most well-designed libraries already use pull-style APIs (read/write, get/put).

C Library Namespaces

A C library namespace is a special kind of object which allows access to the symbols contained in shared libraries or the default symbol namespace. The default ffi.C namespace is automatically created when the FFI library is loaded. C library namespaces for specific shared libraries may be created with the ffi.load() API function.

Indexing a C library namespace object with a symbol name (a Lua string) automatically binds it to the library. First, the symbol type is resolved — it must have been declared with ffi.cdef. Then the symbol address is resolved by searching for the symbol name in the associated shared libraries or the default symbol namespace. Finally, the resulting binding between the symbol name, the symbol type and its address is cached. Missing symbol declarations or nonexistent symbol names cause an error.

This is what happens on a read access for the different kinds of symbols:

  • External functions: a cdata object with the type of the function and its address is returned.
  • External variables: the symbol address is dereferenced and the loaded value is converted to a Lua object and returned.
  • Constant values (static const or enum constants): the constant is converted to a Lua object and returned.

This is what happens on a write access:

  • External variables: the value to be written is converted to the C type of the variable and then stored at the symbol address.
  • Writing to constant variables or to any other symbol type causes an error, like any other attempted write to a constant location.

C library namespaces themselves are garbage collected objects. If the last reference to the namespace object is gone, the garbage collector will eventually release the shared library reference and remove all memory associated with the namespace. Since this may trigger the removal of the shared library from the memory of the running process, it's generally not safe to use function cdata objects obtained from a library if the namespace object may be unreferenced.

Performance notice: the JIT compiler specializes to the identity of namespace objects and to the strings used to index it. This effectively turns function cdata objects into constants. It's not useful and actually counter-productive to explicitly cache these function objects, e.g. local strlen = ffi.C.strlen. OTOH, it is useful to cache the namespace itself, e.g. local C = ffi.C.

No Hand-holding!

The FFI library has been designed as a low-level library. The goal is to interface with C code and C data types with a minimum of overhead. This means you can do anything you can do from C: access all memory, overwrite anything in memory, call machine code at any memory address and so on.

The FFI library provides no memory safety, unlike regular Lua code. It will happily allow you to dereference a NULL pointer, to access arrays out of bounds or to misdeclare C functions. If you make a mistake, your application might crash, just like equivalent C code would.

This behavior is inevitable, since the goal is to provide full interoperability with C code. Adding extra safety measures, like bounds checks, would be futile. There's no way to detect misdeclarations of C functions, since shared libraries only provide symbol names, but no type information. Likewise, there's no way to infer the valid range of indexes for a returned pointer.

Again: the FFI library is a low-level library. This implies it needs to be used with care, but it's flexibility and performance often outweigh this concern. If you're a C or C++ developer, it'll be easy to apply your existing knowledge. OTOH, writing code for the FFI library is not for the faint of heart and probably shouldn't be the first exercise for someone with little experience in Lua, C or C++.

As a corollary of the above, the FFI library is not safe for use by untrusted Lua code. If you're sandboxing untrusted Lua code, you definitely don't want to give this code access to the FFI library or to any cdata object (except 64 bit integers or complex numbers). Any properly engineered Lua sandbox needs to provide safety wrappers for many of the standard Lua library functions — similar wrappers need to be written for high-level operations on FFI data types, too.

Current Status

The initial release of the FFI library has some limitations and is missing some features. Most of these will be fixed in future releases.

C language support is currently incomplete:

  • C declarations are not passed through a C pre-processor, yet.
  • The C parser is able to evaluate most constant expressions commonly found in C header files. However, it doesn't handle the full range of C expression semantics and may fail for some obscure constructs.
  • static const declarations only work for integer types up to 32 bits. Neither declaring string constants nor floating-point constants is supported.
  • Packed struct bitfields that cross container boundaries are not implemented.
  • Native vector types may be defined with the GCC mode or vector_size attribute. But no operations other than loading, storing and initializing them are supported, yet.
  • The volatile type qualifier is currently ignored by compiled code.
  • ffi.cdef silently ignores most re-declarations. Note: avoid re-declarations which do not conform to C99. The implementation will eventually be changed to perform strict checks.

The JIT compiler already handles a large subset of all FFI operations. It automatically falls back to the interpreter for unimplemented operations (you can check for this with the -jv command line option). The following operations are currently not compiled and may exhibit suboptimal performance, especially when used in inner loops:

  • Vector operations.
  • Table initializers.
  • Initialization of nested struct/union types.
  • Non-default initialization of VLA/VLS or large C types (> 128 bytes or > 16 array elements).
  • Bitfield initializations.
  • Pointer differences for element sizes that are not a power of two.
  • Calls to C functions with aggregates passed or returned by value.
  • Calls to ctype metamethods which are not plain functions.
  • ctype __newindex tables and non-string lookups in ctype __index tables.
  • tostring() for cdata types.
  • Calls to ffi.cdef(), ffi.load() and ffi.metatype().

Other missing features:

  • Arithmetic for complex numbers.
  • Passing structs by value to vararg C functions.
  • C++ exception interoperability does not extend to C functions called via the FFI, if the call is compiled.

================================================ FILE: third_party/luajit/luajit/doc/ext_ffi_tutorial.html ================================================ FFI Tutorial

This page is intended to give you an overview of the features of the FFI library by presenting a few use cases and guidelines.

This page makes no attempt to explain all of the FFI library, though. You'll want to have a look at the ffi.* API function reference and the FFI semantics to learn more.

Loading the FFI Library

The FFI library is built into LuaJIT by default, but it's not loaded and initialized by default. The suggested way to use the FFI library is to add the following to the start of every Lua file that needs one of its functions:

local ffi = require("ffi")

Please note, this doesn't define an ffi variable in the table of globals — you really need to use the local variable. The require function ensures the library is only loaded once.

Note: If you want to experiment with the FFI from the interactive prompt of the command line executable, omit the local, as it doesn't preserve local variables across lines.

Accessing Standard System Functions

The following code explains how to access standard system functions. We slowly print two lines of dots by sleeping for 10 milliseconds after each dot:

 
①





②
③
④



⑤





⑥local ffi = require("ffi")
ffi.cdef[[
void Sleep(int ms);
int poll(struct pollfd *fds, unsigned long nfds, int timeout);
]]

local sleep
if ffi.os == "Windows" then
  function sleep(s)
    ffi.C.Sleep(s*1000)
  end
else
  function sleep(s)
    ffi.C.poll(nil, 0, s*1000)
  end
end

for i=1,160 do
  io.write("."); io.flush()
  sleep(0.01)
end
io.write("\n")

Here's the step-by-step explanation:

This defines the C library functions we're going to use. The part inside the double-brackets (in green) is just standard C syntax. You can usually get this info from the C header files or the documentation provided by each C library or C compiler.

The difficulty we're facing here, is that there are different standards to choose from. Windows has a simple Sleep() function. On other systems there are a variety of functions available to achieve sub-second sleeps, but with no clear consensus. Thankfully poll() can be used for this task, too, and it's present on most non-Windows systems. The check for ffi.os makes sure we use the Windows-specific function only on Windows systems.

Here we're wrapping the call to the C function in a Lua function. This isn't strictly necessary, but it's helpful to deal with system-specific issues only in one part of the code. The way we're wrapping it ensures the check for the OS is only done during initialization and not for every call.

A more subtle point is that we defined our sleep() function (for the sake of this example) as taking the number of seconds, but accepting fractional seconds. Multiplying this by 1000 gets us milliseconds, but that still leaves it a Lua number, which is a floating-point value. Alas, the Sleep() function only accepts an integer value. Luckily for us, the FFI library automatically performs the conversion when calling the function (truncating the FP value towards zero, like in C).

Some readers will notice that Sleep() is part of KERNEL32.DLL and is also a stdcall function. So how can this possibly work? The FFI library provides the ffi.C default C library namespace, which allows calling functions from the default set of libraries, like a C compiler would. Also, the FFI library automatically detects stdcall functions, so you don't need to declare them as such.

The poll() function takes a couple more arguments we're not going to use. You can simply use nil to pass a NULL pointer and 0 for the nfds parameter. Please note, that the number 0 does not convert to a pointer value, unlike in C++. You really have to pass pointers to pointer arguments and numbers to number arguments.

The page on FFI semantics has all of the gory details about conversions between Lua objects and C types. For the most part you don't have to deal with this, as it's performed automatically and it's carefully designed to bridge the semantic differences between Lua and C.

Now that we have defined our own sleep() function, we can just call it from plain Lua code. That wasn't so bad, huh? Turning these boring animated dots into a fascinating best-selling game is left as an exercise for the reader. :-)

Accessing the zlib Compression Library

The following code shows how to access the » zlib compression library from Lua code. We'll define two convenience wrapper functions that take a string and compress or uncompress it to another string:

 
①






②


③

④


⑤


⑥







⑦local ffi = require("ffi")
ffi.cdef[[
unsigned long compressBound(unsigned long sourceLen);
int compress2(uint8_t *dest, unsigned long *destLen,
	      const uint8_t *source, unsigned long sourceLen, int level);
int uncompress(uint8_t *dest, unsigned long *destLen,
	       const uint8_t *source, unsigned long sourceLen);
]]
local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")

local function compress(txt)
  local n = zlib.compressBound(#txt)
  local buf = ffi.new("uint8_t[?]", n)
  local buflen = ffi.new("unsigned long[1]", n)
  local res = zlib.compress2(buf, buflen, txt, #txt, 9)
  assert(res == 0)
  return ffi.string(buf, buflen[0])
end

local function uncompress(comp, n)
  local buf = ffi.new("uint8_t[?]", n)
  local buflen = ffi.new("unsigned long[1]", n)
  local res = zlib.uncompress(buf, buflen, comp, #comp)
  assert(res == 0)
  return ffi.string(buf, buflen[0])
end

-- Simple test code.
local txt = string.rep("abcd", 1000)
print("Uncompressed size: ", #txt)
local c = compress(txt)
print("Compressed size: ", #c)
local txt2 = uncompress(c, #txt)
assert(txt2 == txt)

Here's the step-by-step explanation:

This defines some of the C functions provided by zlib. For the sake of this example, some type indirections have been reduced and it uses the predefined fixed-size integer types, while still adhering to the zlib API/ABI.

This loads the zlib shared library. On POSIX systems, it's named libz.so and usually comes pre-installed. Since ffi.load() automatically adds any missing standard prefixes/suffixes, we can simply load the "z" library. On Windows it's named zlib1.dll and you'll have to download it first from the » zlib site. The check for ffi.os makes sure we pass the right name to ffi.load().

First, the maximum size of the compression buffer is obtained by calling the zlib.compressBound function with the length of the uncompressed string. The next line allocates a byte buffer of this size. The [?] in the type specification indicates a variable-length array (VLA). The actual number of elements of this array is given as the 2nd argument to ffi.new().

This may look strange at first, but have a look at the declaration of the compress2 function from zlib: the destination length is defined as a pointer! This is because you pass in the maximum buffer size and get back the actual length that was used.

In C you'd pass in the address of a local variable (&buflen). But since there's no address-of operator in Lua, we'll just pass in a one-element array. Conveniently, it can be initialized with the maximum buffer size in one step. Calling the actual zlib.compress2 function is then straightforward.

We want to return the compressed data as a Lua string, so we'll use ffi.string(). It needs a pointer to the start of the data and the actual length. The length has been returned in the buflen array, so we'll just get it from there.

Note that since the function returns now, the buf and buflen variables will eventually be garbage collected. This is fine, because ffi.string() has copied the contents to a newly created (interned) Lua string. If you plan to call this function lots of times, consider reusing the buffers and/or handing back the results in buffers instead of strings. This will reduce the overhead for garbage collection and string interning.

The uncompress functions does the exact opposite of the compress function. The compressed data doesn't include the size of the original string, so this needs to be passed in. Otherwise, no surprises here.

The code, that makes use of the functions we just defined, is just plain Lua code. It doesn't need to know anything about the LuaJIT FFI — the convenience wrapper functions completely hide it.

One major advantage of the LuaJIT FFI is that you are now able to write those wrappers in Lua. And at a fraction of the time it would cost you to create an extra C module using the Lua/C API. Many of the simpler C functions can probably be used directly from your Lua code, without any wrappers.

Side note: the zlib API uses the long type for passing lengths and sizes around. But all those zlib functions actually only deal with 32 bit values. This is an unfortunate choice for a public API, but may be explained by zlib's history — we'll just have to deal with it.

First, you should know that a long is a 64 bit type e.g. on POSIX/x64 systems, but a 32 bit type on Windows/x64 and on 32 bit systems. Thus a long result can be either a plain Lua number or a boxed 64 bit integer cdata object, depending on the target system.

Ok, so the ffi.* functions generally accept cdata objects wherever you'd want to use a number. That's why we get a away with passing n to ffi.string() above. But other Lua library functions or modules don't know how to deal with this. So for maximum portability, one needs to use tonumber() on returned long results before passing them on. Otherwise the application might work on some systems, but would fail in a POSIX/x64 environment.

Defining Metamethods for a C Type

The following code explains how to define metamethods for a C type. We define a simple point type and add some operations to it:

 
①



②

③

④



⑤

⑥local ffi = require("ffi")
ffi.cdef[[
typedef struct { double x, y; } point_t;
]]

local point
local mt = {
  __add = function(a, b) return point(a.x+b.x, a.y+b.y) end,
  __len = function(a) return math.sqrt(a.x*a.x + a.y*a.y) end,
  __index = {
    area = function(a) return a.x*a.x + a.y*a.y end,
  },
}
point = ffi.metatype("point_t", mt)

local a = point(3, 4)
print(a.x, a.y)  --> 3  4
print(#a)        --> 5
print(a:area())  --> 25
local b = a + point(0.5, 8)
print(#b)        --> 12.5

Here's the step-by-step explanation:

This defines the C type for a two-dimensional point object.

We have to declare the variable holding the point constructor first, because it's used inside of a metamethod.

Let's define an __add metamethod which adds the coordinates of two points and creates a new point object. For simplicity, this function assumes that both arguments are points. But it could be any mix of objects, if at least one operand is of the required type (e.g. adding a point plus a number or vice versa). Our __len metamethod returns the distance of a point to the origin.

If we run out of operators, we can define named methods, too. Here, the __index table defines an area function. For custom indexing needs, one might want to define __index and __newindex functions instead.

This associates the metamethods with our C type. This only needs to be done once. For convenience, a constructor is returned by ffi.metatype(). We're not required to use it, though. The original C type can still be used e.g. to create an array of points. The metamethods automatically apply to any and all uses of this type.

Please note, that the association with a metatable is permanent and the metatable must not be modified afterwards! Ditto for the __index table.

Here are some simple usage examples for the point type and their expected results. The predefined operations (such as a.x) can be freely mixed with the newly defined metamethods. Note that area is a method and must be called with the Lua syntax for methods: a:area(), not a.area().

The C type metamethod mechanism is most useful when used in conjunction with C libraries that are written in an object-oriented style. Creators return a pointer to a new instance, and methods take an instance pointer as the first argument. Sometimes you can just point __index to the library namespace and __gc to the destructor and you're done. But often enough you'll want to add convenience wrappers, e.g. to return actual Lua strings or when returning multiple values.

Some C libraries only declare instance pointers as an opaque void * type. In this case you can use a fake type for all declarations, e.g. a pointer to a named (incomplete) struct will do: typedef struct foo_type *foo_handle. The C side doesn't know what you declare with the LuaJIT FFI, but as long as the underlying types are compatible, everything still works.

Translating C Idioms

Here's a list of common C idioms and their translation to the LuaJIT FFI:

Idiom C code Lua code
Pointer dereference
int *p;
x = *p;
*p = y;
x = p[0]
p[0] = y
Pointer indexing
int i, *p;
x = p[i];
p[i+1] = y;
x = p[i]
p[i+1] = y
Array indexing
int i, a[];
x = a[i];
a[i+1] = y;
x = a[i]
a[i+1] = y
struct/union dereference
struct foo s;
x = s.field;
s.field = y;
x = s.field
s.field = y
struct/union pointer deref.
struct foo *sp;
x = sp->field;
sp->field = y;
x = s.field
s.field = y
Pointer arithmetic
int i, *p;
x = p + i;
y = p - i;
x = p + i
y = p - i
Pointer difference
int *p1, *p2;
x = p1 - p2;x = p1 - p2
Array element pointer
int i, a[];
x = &a[i];x = a+i
Cast pointer to address
int *p;
x = (intptr_t)p;x = tonumber(
 ffi.cast("intptr_t",
          p))
Functions with outargs
void foo(int *inoutlen);
int len = x;
foo(&len);
y = len;
local len =
  ffi.new("int[1]", x)
foo(len)
y = len[0]
Vararg conversions
int printf(char *fmt, ...);
printf("%g", 1.0);
printf("%d", 1);
 
printf("%g", 1);
printf("%d",
  ffi.new("int", 1))

To Cache or Not to Cache

It's a common Lua idiom to cache library functions in local variables or upvalues, e.g.:

local byte, char = string.byte, string.char
local function foo(x)
  return char(byte(x)+1)
end

This replaces several hash-table lookups with a (faster) direct use of a local or an upvalue. This is less important with LuaJIT, since the JIT compiler optimizes hash-table lookups a lot and is even able to hoist most of them out of the inner loops. It can't eliminate all of them, though, and it saves some typing for often-used functions. So there's still a place for this, even with LuaJIT.

The situation is a bit different with C function calls via the FFI library. The JIT compiler has special logic to eliminate all of the lookup overhead for functions resolved from a C library namespace! Thus it's not helpful and actually counter-productive to cache individual C functions like this:

local funca, funcb = ffi.C.funca, ffi.C.funcb -- Not helpful!
local function foo(x, n)
  for i=1,n do funcb(funca(x, i), 1) end
end

This turns them into indirect calls and generates bigger and slower machine code. Instead, you'll want to cache the namespace itself and rely on the JIT compiler to eliminate the lookups:

local C = ffi.C          -- Instead use this!
local function foo(x, n)
  for i=1,n do C.funcb(C.funca(x, i), 1) end
end

This generates both shorter and faster code. So don't cache C functions, but do cache namespaces! Most often the namespace is already in a local variable at an outer scope, e.g. from local lib = ffi.load(...). Note that copying it to a local variable in the function scope is unnecessary.


================================================ FILE: third_party/luajit/luajit/doc/ext_jit.html ================================================ jit.* Library

The functions in this built-in module control the behavior of the JIT compiler engine. Note that JIT-compilation is fully automatic — you probably won't need to use any of the following functions unless you have special needs.

jit.on()
jit.off()

Turns the whole JIT compiler on (default) or off.

These functions are typically used with the command line options -j on or -j off.

jit.flush()

Flushes the whole cache of compiled code.

jit.on(func|true [,true|false])
jit.off(func|true [,true|false])
jit.flush(func|true [,true|false])

jit.on enables JIT compilation for a Lua function (this is the default).

jit.off disables JIT compilation for a Lua function and flushes any already compiled code from the code cache.

jit.flush flushes the code, but doesn't affect the enable/disable status.

The current function, i.e. the Lua function calling this library function, can also be specified by passing true as the first argument.

If the second argument is true, JIT compilation is also enabled, disabled or flushed recursively for all sub-functions of a function. With false only the sub-functions are affected.

The jit.on and jit.off functions only set a flag which is checked when the function is about to be compiled. They do not trigger immediate compilation.

Typical usage is jit.off(true, true) in the main chunk of a module to turn off JIT compilation for the whole module for debugging purposes.

jit.flush(tr)

Flushes the root trace, specified by its number, and all of its side traces from the cache. The code for the trace will be retained as long as there are any other traces which link to it.

status, ... = jit.status()

Returns the current status of the JIT compiler. The first result is either true or false if the JIT compiler is turned on or off. The remaining results are strings for CPU-specific features and enabled optimizations.

jit.version

Contains the LuaJIT version string.

jit.version_num

Contains the version number of the LuaJIT core. Version xx.yy.zz is represented by the decimal number xxyyzz.

jit.os

Contains the target OS name: "Windows", "Linux", "OSX", "BSD", "POSIX" or "Other".

jit.arch

Contains the target architecture name: "x86", "x64", "arm", "arm64", "arm64be", "ppc", "mips", "mipsel", "mips64", "mips64el", "mips64r6", "mips64r6el".

jit.opt.* — JIT compiler optimization control

This submodule provides the backend for the -O command line option.

You can also use it programmatically, e.g.:

jit.opt.start(2) -- same as -O2
jit.opt.start("-dce")
jit.opt.start("hotloop=10", "hotexit=2")

Unlike in LuaJIT 1.x, the module is built-in and optimization is turned on by default! It's no longer necessary to run require("jit.opt").start(), which was one of the ways to enable optimization.

jit.util.* — JIT compiler introspection

This submodule holds functions to introspect the bytecode, generated traces, the IR and the generated machine code. The functionality provided by this module is still in flux and therefore undocumented.

The debug modules -jbc, -jv and -jdump make extensive use of these functions. Please check out their source code, if you want to know more.


================================================ FILE: third_party/luajit/luajit/doc/ext_profiler.html ================================================ Profiler

LuaJIT has an integrated statistical profiler with very low overhead. It allows sampling the currently executing stack and other parameters in regular intervals.

The integrated profiler can be accessed from three levels:

High-Level Profiler

The bundled high-level profiler offers basic profiling functionality. It generates simple textual summaries or source code annotations. It can be accessed with the -jp command line option or from Lua code by loading the underlying jit.p module.

To cut to the chase — run this to get a CPU usage profile by function name:

luajit -jp myapp.lua

It's not a stated goal of the bundled profiler to add every possible option or to cater for special profiling needs. The low-level profiler APIs are documented below. They may be used by third-party authors to implement advanced functionality, e.g. IDE integration or graphical profilers.

Note: Sampling works for both interpreted and JIT-compiled code. The results for JIT-compiled code may sometimes be surprising. LuaJIT heavily optimizes and inlines Lua code — there's no simple one-to-one correspondence between source code lines and the sampled machine code.

-jp=[options[,output]]

The -jp command line option starts the high-level profiler. When the application run by the command line terminates, the profiler stops and writes the results to stdout or to the specified output file.

The options argument specifies how the profiling is to be performed:

  • f — Stack dump: function name, otherwise module:line. This is the default mode.
  • F — Stack dump: ditto, but dump module:name.
  • l — Stack dump: module:line.
  • <number> — stack dump depth (callee ← caller). Default: 1.
  • -<number> — Inverse stack dump depth (caller → callee).
  • s — Split stack dump after first stack level. Implies depth ≥ 2 or depth ≤ -2.
  • p — Show full path for module names.
  • v — Show VM states.
  • z — Show zones.
  • r — Show raw sample counts. Default: show percentages.
  • a — Annotate excerpts from source code files.
  • A — Annotate complete source code files.
  • G — Produce raw output suitable for graphical tools.
  • m<number> — Minimum sample percentage to be shown. Default: 3%.
  • i<number> — Sampling interval in milliseconds. Default: 10ms.
    Note: The actual sampling precision is OS-dependent.

The default output for -jp is a list of the most CPU consuming spots in the application. Increasing the stack dump depth with (say) -jp=2 may help to point out the main callers or callees of hotspots. But sample aggregation is still flat per unique stack dump.

To get a two-level view (split view) of callers/callees, use -jp=s or -jp=-s. The percentages shown for the second level are relative to the first level.

To see how much time is spent in each line relative to a function, use -jp=fl.

To see how much time is spent in different VM states or zones, use -jp=v or -jp=z.

Combinations of v/z with f/F/l produce two-level views, e.g. -jp=vf or -jp=fv. This shows the time spent in a VM state or zone vs. hotspots. This can be used to answer questions like "Which time-consuming functions are only interpreted?" or "What's the garbage collector overhead for a specific function?".

Multiple options can be combined — but not all combinations make sense, see above. E.g. -jp=3si4m1 samples three stack levels deep in 4ms intervals and shows a split view of the CPU consuming functions and their callers with a 1% threshold.

Source code annotations produced by -jp=a or -jp=A are always flat and at the line level. Obviously, the source code files need to be readable by the profiler script.

The high-level profiler can also be started and stopped from Lua code with:

require("jit.p").start(options, output)
...
require("jit.p").stop()

jit.zone — Zones

Zones can be used to provide information about different parts of an application to the high-level profiler. E.g. a game could make use of an "AI" zone, a "PHYS" zone, etc. Zones are hierarchical, organized as a stack.

The jit.zone module needs to be loaded explicitly:

local zone = require("jit.zone")
  • zone("name") pushes a named zone to the zone stack.
  • zone() pops the current zone from the zone stack and returns its name.
  • zone:get() returns the current zone name or nil.
  • zone:flush() flushes the zone stack.

To show the time spent in each zone use -jp=z. To show the time spent relative to hotspots use e.g. -jp=zf or -jp=fz.

Low-level Lua API

The jit.profile module gives access to the low-level API of the profiler from Lua code. This module needs to be loaded explicitly:

local profile = require("jit.profile")

This module can be used to implement your own higher-level profiler. A typical profiling run starts the profiler, captures stack dumps in the profiler callback, adds them to a hash table to aggregate the number of samples, stops the profiler and then analyzes all captured stack dumps. Other parameters can be sampled in the profiler callback, too. But it's important not to spend too much time in the callback, since this may skew the statistics.

profile.start(mode, cb) — Start profiler

This function starts the profiler. The mode argument is a string holding options:

  • f — Profile with precision down to the function level.
  • l — Profile with precision down to the line level.
  • i<number> — Sampling interval in milliseconds (default 10ms).
    Note: The actual sampling precision is OS-dependent.

The cb argument is a callback function which is called with three arguments: (thread, samples, vmstate). The callback is called on a separate coroutine, the thread argument is the state that holds the stack to sample for profiling. Note: do not modify the stack of that state or call functions on it.

samples gives the number of accumulated samples since the last callback (usually 1).

vmstate holds the VM state at the time the profiling timer triggered. This may or may not correspond to the state of the VM when the profiling callback is called. The state is either 'N' native (compiled) code, 'I' interpreted code, 'C' C code, 'G' the garbage collector, or 'J' the JIT compiler.

profile.stop() — Stop profiler

This function stops the profiler.

dump = profile.dumpstack([thread,] fmt, depth) — Dump stack

This function allows taking stack dumps in an efficient manner. It returns a string with a stack dump for the thread (coroutine), formatted according to the fmt argument:

  • p — Preserve the full path for module names. Otherwise, only the file name is used.
  • f — Dump the function name if it can be derived. Otherwise, use module:line.
  • F — Ditto, but dump module:name.
  • l — Dump module:line.
  • Z — Zap the following characters for the last dumped frame.
  • All other characters are added verbatim to the output string.

The depth argument gives the number of frames to dump, starting at the topmost frame of the thread. A negative number dumps the frames in inverse order.

The first example prints a list of the current module names and line numbers of up to 10 frames in separate lines. The second example prints semicolon-separated function names for all frames (up to 100) in inverse order:

print(profile.dumpstack(thread, "l\n", 10))
print(profile.dumpstack(thread, "lZ;", -100))

Low-level C API

The profiler can be controlled directly from C code, e.g. for use by IDEs. The declarations are in "luajit.h" (see Lua/C API extensions).

luaJIT_profile_start(L, mode, cb, data) — Start profiler

This function starts the profiler. See above for a description of the mode argument.

The cb argument is a callback function with the following declaration:

typedef void (*luaJIT_profile_callback)(void *data, lua_State *L,
                                        int samples, int vmstate);

data is available for use by the callback. L is the state that holds the stack to sample for profiling. Note: do not modify this stack or call functions on this stack — use a separate coroutine for this purpose. See above for a description of samples and vmstate.

luaJIT_profile_stop(L) — Stop profiler

This function stops the profiler.

p = luaJIT_profile_dumpstack(L, fmt, depth, len) — Dump stack

This function allows taking stack dumps in an efficient manner. See above for a description of fmt and depth.

This function returns a const char * pointing to a private string buffer of the profiler. The int *len argument returns the length of the output string. The buffer is overwritten on the next call and deallocated when the profiler stops. You either need to consume the content immediately or copy it for later use.


================================================ FILE: third_party/luajit/luajit/doc/extensions.html ================================================ Extensions

LuaJIT is fully upwards-compatible with Lua 5.1. It supports all » standard Lua library functions and the full set of » Lua/C API functions.

LuaJIT is also fully ABI-compatible to Lua 5.1 at the linker/dynamic loader level. This means you can compile a C module against the standard Lua headers and load the same shared library from either Lua or LuaJIT.

LuaJIT extends the standard Lua VM with new functionality and adds several extension modules. Please note, this page is only about functional enhancements and not about performance enhancements, such as the optimized VM, the faster interpreter or the JIT compiler.

Extensions Modules

LuaJIT comes with several built-in extension modules:

bit.* — Bitwise operations

LuaJIT supports all bitwise operations as defined by » Lua BitOp:

bit.tobit  bit.tohex  bit.bnot    bit.band bit.bor  bit.bxor
bit.lshift bit.rshift bit.arshift bit.rol  bit.ror  bit.bswap

This module is a LuaJIT built-in — you don't need to download or install Lua BitOp. The Lua BitOp site has full documentation for all » Lua BitOp API functions. The FFI adds support for 64 bit bitwise operations, using the same API functions.

Please make sure to require the module before using any of its functions:

local bit = require("bit")

An already installed Lua BitOp module is ignored by LuaJIT. This way you can use bit operations from both Lua and LuaJIT on a shared installation.

ffi.* — FFI library

The FFI library allows calling external C functions and the use of C data structures from pure Lua code.

jit.* — JIT compiler control

The functions in this module control the behavior of the JIT compiler engine.

C API extensions

LuaJIT adds some extra functions to the Lua/C API.

Profiler

LuaJIT has an integrated profiler.

Enhanced Standard Library Functions

xpcall(f, err [,args...]) passes arguments

Unlike the standard implementation in Lua 5.1, xpcall() passes any arguments after the error function to the function which is called in a protected context.

loadfile() etc. handle UTF-8 source code

Non-ASCII characters are handled transparently by the Lua source code parser. This allows the use of UTF-8 characters in identifiers and strings. A UTF-8 BOM is skipped at the start of the source code.

tostring() etc. canonicalize NaN and ±Inf

All number-to-string conversions consistently convert non-finite numbers to the same strings on all platforms. NaN results in "nan", positive infinity results in "inf" and negative infinity results in "-inf".

tonumber() etc. use builtin string to number conversion

All string-to-number conversions consistently convert integer and floating-point inputs in decimal, hexadecimal and binary on all platforms. strtod() is not used anymore, which avoids numerous problems with poor C library implementations. The builtin conversion function provides full precision according to the IEEE-754 standard, it works independently of the current locale and it supports hex floating-point numbers (e.g. 0x1.5p-3).

string.dump(f [,strip]) generates portable bytecode

An extra argument has been added to string.dump(). If set to true, 'stripped' bytecode without debug information is generated. This speeds up later bytecode loading and reduces memory usage. See also the -b command line option.

The generated bytecode is portable and can be loaded on any architecture that LuaJIT supports, independent of word size or endianess. However, the bytecode compatibility versions must match. Bytecode stays compatible for dot releases (x.y.0 → x.y.1), but may change with major or minor releases (2.0 → 2.1) or between any beta release. Foreign bytecode (e.g. from Lua 5.1) is incompatible and cannot be loaded.

Note: LJ_GC64 mode requires a different frame layout, which implies a different, incompatible bytecode format for all 64 bit ports. This may be rectified in the future.

table.new(narray, nhash) allocates a pre-sized table

An extra library function table.new() can be made available via require("table.new"). This creates a pre-sized table, just like the C API equivalent lua_createtable(). This is useful for big tables if the final table size is known and automatic table resizing is too expensive.

table.clear(tab) clears a table

An extra library function table.clear() can be made available via require("table.clear"). This clears all keys and values from a table, but preserves the allocated array/hash sizes. This is useful when a table, which is linked from multiple places, needs to be cleared and/or when recycling a table for use by the same context. This avoids managing backlinks, saves an allocation and the overhead of incremental array/hash part growth.

Please note, this function is meant for very specific situations. In most cases it's better to replace the (usually single) link with a new table and let the GC do its work.

Enhanced PRNG for math.random()

LuaJIT uses a Tausworthe PRNG with period 2^223 to implement math.random() and math.randomseed(). The quality of the PRNG results is much superior compared to the standard Lua implementation, which uses the platform-specific ANSI rand().

The PRNG generates the same sequences from the same seeds on all platforms and makes use of all bits in the seed argument. math.random() without arguments generates 52 pseudo-random bits for every call. The result is uniformly distributed between 0.0 and 1.0. It's correctly scaled up and rounded for math.random(n [,m]) to preserve uniformity.

Important: Neither this nor any other PRNG based on the simplistic math.random() API is suitable for cryptographic use.

io.* functions handle 64 bit file offsets

The file I/O functions in the standard io.* library handle 64 bit file offsets. In particular, this means it's possible to open files larger than 2 Gigabytes and to reposition or obtain the current file position for offsets beyond 2 GB (fp:seek() method).

debug.* functions identify metamethods

debug.getinfo() and lua_getinfo() also return information about invoked metamethods. The namewhat field is set to "metamethod" and the name field has the name of the corresponding metamethod (e.g. "__index").

Fully Resumable VM

The LuaJIT VM is fully resumable. This means you can yield from a coroutine even across contexts, where this would not possible with the standard Lua 5.1 VM: e.g. you can yield across pcall() and xpcall(), across iterators and across metamethods.

Extensions from Lua 5.2

LuaJIT supports some language and library extensions from Lua 5.2. Features that are unlikely to break existing code are unconditionally enabled:

  • goto and ::labels::.
  • Hex escapes '\x3F' and '\*' escape in strings.
  • load(string|reader [, chunkname [,mode [,env]]]).
  • loadstring() is an alias for load().
  • loadfile(filename [,mode [,env]]).
  • math.log(x [,base]).
  • string.rep(s, n [,sep]).
  • string.format(): %q reversible. %s checks __tostring. %a and "%A added.
  • String matching pattern %g added.
  • io.read("*L").
  • io.lines() and file:lines() process io.read() options.
  • os.exit(status|true|false [,close]).
  • package.searchpath(name, path [, sep [, rep]]).
  • package.loadlib(name, "*").
  • debug.getinfo() returns nparams and isvararg for option "u".
  • debug.getlocal() accepts function instead of level.
  • debug.getlocal() and debug.setlocal() accept negative indexes for varargs.
  • debug.getupvalue() and debug.setupvalue() handle C functions.
  • debug.upvalueid() and debug.upvaluejoin().
  • Lua/C API extensions: lua_version() lua_upvalueid() lua_upvaluejoin() lua_loadx() lua_copy() lua_tonumberx() lua_tointegerx() luaL_fileresult() luaL_execresult() luaL_loadfilex() luaL_loadbufferx() luaL_traceback() luaL_setfuncs() luaL_pushmodule() luaL_newlibtable() luaL_newlib() luaL_testudata() luaL_setmetatable()
  • Command line option -E.
  • Command line checks __tostring for errors.

Other features are only enabled, if LuaJIT is built with -DLUAJIT_ENABLE_LUA52COMPAT:

  • goto is a keyword and not a valid variable name anymore.
  • break can be placed anywhere. Empty statements (;;) are allowed.
  • __lt, __le are invoked for mixed types.
  • __len for tables. rawlen() library function.
  • pairs() and ipairs() check for __pairs and __ipairs.
  • coroutine.running() returns two results.
  • table.pack() and table.unpack() (same as unpack()).
  • io.write() and file:write() return file handle instead of true.
  • os.execute() and pipe:close() return detailed exit status.
  • debug.setmetatable() returns object.
  • debug.getuservalue() and debug.setuservalue().
  • Remove math.mod(), string.gfind().
  • package.searchers.
  • module() returns the module table.

Note: this provides only partial compatibility with Lua 5.2 at the language and Lua library level. LuaJIT is API+ABI-compatible with Lua 5.1, which prevents implementing features that would otherwise break the Lua/C API and ABI (e.g. _ENV).

Extensions from Lua 5.3

LuaJIT supports some extensions from Lua 5.3:

  • Unicode escape '\u{XX...}' embeds the UTF-8 encoding in string literals.
  • The argument table arg can be read (and modified) by LUA_INIT and -e chunks.
  • io.read() and file:read() accept formats with or without a leading *.
  • assert() accepts any type of error object.
  • table.move(a1, f, e, t [,a2]).
  • coroutine.isyieldable().
  • Lua/C API extensions: lua_isyieldable()

C++ Exception Interoperability

LuaJIT has built-in support for interoperating with C++ exceptions. The available range of features depends on the target platform and the toolchain used to compile LuaJIT:

Platform Compiler Interoperability
External frame unwinding GCC, Clang, MSVC Full
Internal frame unwinding + DWARF2 GCC, Clang Limited
Windows 64 bit non-MSVC Limited
Other platforms Other compilers No

Full interoperability means:

  • C++ exceptions can be caught on the Lua side with pcall(), lua_pcall() etc.
  • C++ exceptions will be converted to the generic Lua error "C++ exception", unless you use the C call wrapper feature.
  • It's safe to throw C++ exceptions across non-protected Lua frames on the C stack. The contents of the C++ exception object pass through unmodified.
  • Lua errors can be caught on the C++ side with catch(...). The corresponding Lua error message can be retrieved from the Lua stack.
    For MSVC for Windows 64 bit this requires compilation of your C++ code with /EHa.
  • Throwing Lua errors across C++ frames is safe. C++ destructors will be called.

Limited interoperability means:

  • C++ exceptions can be caught on the Lua side with pcall(), lua_pcall() etc.
  • C++ exceptions will be converted to the generic Lua error "C++ exception", unless you use the C call wrapper feature.
  • C++ exceptions will be caught by non-protected Lua frames and are rethrown as a generic Lua error. The C++ exception object will be destroyed.
  • Lua errors cannot be caught on the C++ side.
  • Throwing Lua errors across C++ frames will not call C++ destructors.

No interoperability means:

  • It's not safe to throw C++ exceptions across Lua frames.
  • C++ exceptions cannot be caught on the Lua side.
  • Lua errors cannot be caught on the C++ side.
  • Throwing Lua errors across C++ frames will not call C++ destructors.

================================================ FILE: third_party/luajit/luajit/doc/faq.html ================================================ Frequently Asked Questions (FAQ)
Q: Where can I learn more about LuaJIT and Lua?
Q: Where can I learn more about the compiler technology used by LuaJIT?
Please use the following Google Scholar searches to find relevant papers:
Search for: » Trace Compiler
Search for: » JIT Compiler
Search for: » Dynamic Language Optimizations
Search for: » SSA Form
Search for: » Linear Scan Register Allocation
Here is a list of the » innovative features in LuaJIT.
And, you know, reading the source is of course the only way to enlightenment.
Q: Why do I get this error: "attempt to index global 'arg' (a nil value)"?
Q: My vararg functions fail after switching to LuaJIT!
LuaJIT is compatible to the Lua 5.1 language standard. It doesn't support the implicit arg parameter for old-style vararg functions from Lua 5.0.
Please convert your code to the » Lua 5.1 vararg syntax.
Q: Why do I get this error: "bad FPU precision"?
Q: I get weird behavior after initializing Direct3D.
Q: Some FPU operations crash after I load a Delphi DLL.
DirectX/Direct3D (up to version 9) sets the x87 FPU to single-precision mode by default. This violates the Windows ABI and interferes with the operation of many programs — LuaJIT is affected, too. Please make sure you always use the D3DCREATE_FPU_PRESERVE flag when initializing Direct3D.
Direct3D version 10 or higher do not show this behavior anymore. Consider testing your application with older versions, too.
Similarly, the Borland/Delphi runtime modifies the FPU control word and enables FP exceptions. Of course, this violates the Windows ABI, too. Please check the Delphi docs for the Set8087CW method.
Q: Sometimes Ctrl-C fails to stop my Lua program. Why?
The interrupt signal handler sets a Lua debug hook. But this is ignored by compiled code. If your program is running in a tight loop and never falls back to the interpreter, the debug hook never runs and can't throw the "interrupted!" error.
You have to press Ctrl-C twice to stop your program. That's similar to when it's stuck running inside a C function under the Lua interpreter.
Q: Table iteration with pairs() does not result in the same order?
The order of table iteration is explicitly undefined by the Lua language standard.
Different Lua implementations or versions may use different orders for otherwise identical tables. Different ways of constructing a table may result in different orders, too.
Due to improved VM security, LuaJIT 2.1 may even use a different order on separate VM invocations or when string keys are newly interned.

If your program relies on a deterministic order, it has a bug. Rewrite it, so it doesn't rely on the key order. Or sort the table keys, if you must.
Q: Can Lua code be safely sandboxed?
Maybe for an extremely restricted subset of Lua and if you relentlessly scrutinize every single interface function you offer to the untrusted code.
Although Lua provides some sandboxing functionality (setfenv(), hooks), it's very hard to get this right even for the Lua core libraries. Of course, you'll need to inspect any extension library, too. And there are libraries that are inherently unsafe, e.g. the FFI library.
More reading material at the » Lua Wiki and » Wikipedia.

Relatedly, loading untrusted bytecode is not safe!
It's trivial to crash the Lua or LuaJIT VM with maliciously crafted bytecode. This is well known and there's no bytecode verification on purpose, so please don't report a bug about it. Check the mode parameter for the load*() functions to disable loading of bytecode.

In general, the only promising approach is to sandbox Lua code at the process level and not the VM level.
Q: Lua runs everywhere. Why doesn't LuaJIT support my CPU?
Because it's a compiler — it needs to generate native machine code. This means the code generator must be ported to each architecture. And the fast interpreter is written in assembler and must be ported, too. This is quite an undertaking.
The install documentation shows the supported architectures.
Other architectures may follow based on sufficient user demand and market-relevance of the architecture. Sponsoring is required to develop the port itself, to integrate it and to continuously maintain it in the actively developed branches.

================================================ FILE: third_party/luajit/luajit/doc/install.html ================================================ Installation

LuaJIT is only distributed as a source package. This page explains how to build and install LuaJIT with different operating systems and C compilers.

For the impatient (on POSIX systems):

make && sudo make install

Requirements

Systems

LuaJIT currently builds out-of-the box on most systems:

OS Min. Version Requirements LuaJIT Versions
Windows 7 x86 or x64, ARM64: TBA v2.0 –
Linux     v2.0 –
*BSD     v2.0 –
macOS (OSX) 10.4   v2.1 –
POSIX   mmap, dlopen v2.0 –
Android 4.0 Recent Android NDK v2.0 –
iOS 3.0 Xcode iOS SDK v2.1 –
PS3   PS3 SDK v2.0 – v2.1 EOL
PS4   PS4 SDK (ORBIS) v2.0 –
PS5   PS5 SDK (PROSPERO) v2.1 –
PS Vita   PS Vita SDK (PSP2) v2.0 – v2.1 EOL
Xbox 360   Xbox 360 SDK (XEDK) v2.0 – v2.1 EOL
Xbox One   Xbox One SDK (DURANGO) v2.1 –
Nintendo Switch   NintendoSDK + NX Addon v2.1 –

The codebase has compatibility defines for some more systems, but without official support.

Toolchains

Building LuaJIT requires a recent toolchain based on GCC, Clang/LLVM or MSVC++.

The Makefile-based build system requires GNU Make and supports cross-builds. Batch files are provided for MSVC++ builds and console cross-builds.

CPU Architectures

CPU Bits Requirements Variants LuaJIT Versions
x86 32 v2.1+: SSE2   v2.0 –
x64 64     v2.0 –
ARM 32 ARMv5+, ARM9E+ hard-fp + soft-fp v2.0 –
ARM64 64   ARM64le + ARM64be v2.1 –
PPC32 32   hard-fp + soft-fp v2.0 – v2.1 EOL
PPC/e500 32 e500v2   v2.0 EOL
MIPS32 32 MIPS32r1 – r5 hard-fp + soft-fp v2.0 –
MIPS64 64 MIPS64r1 – r5 hard-fp + soft-fp v2.1 –
MIPS64 64 MIPS64r6 hard-fp + soft-fp v2.1 EOL
RISC-V 64 RVA22+   TBA

There are no plans to add historic architectures or to continue support for end-of-life (EOL) architectures, for which no new CPUs are commonly available anymore. Likewise, there are no plans to support marginal and/or de-facto-dead architectures.

Configuring LuaJIT

The standard configuration should work fine for most installations. Usually there is no need to tweak the settings. The following files hold all user-configurable settings:

  • src/luaconf.h sets some configuration variables.
  • Makefile has settings for installing LuaJIT (POSIX only).
  • src/Makefile has settings for compiling LuaJIT under POSIX, MinGW or Cygwin.
  • src/msvcbuild.bat has settings for compiling LuaJIT with MSVC (Visual Studio).

Please read the instructions given in these files, before changing any settings.

All LuaJIT 64 bit ports use 64 bit GC objects by default (LJ_GC64). For x64, you can select the old 32-on-64 bit mode by adding XCFLAGS=-DLUAJIT_DISABLE_GC64 to the make command. Please check the note about the bytecode format differences, too.

POSIX Systems (Linux, macOS, *BSD etc.)

Prerequisites

Depending on your distribution, you may need to install a package for GCC, the development headers and/or a complete SDK. E.g. on a current Debian/Ubuntu, install libc6-dev with the package manager.

The recommended way to fetch the latest version is to do a pull from the git repository.

Alternatively, download the latest source package of LuaJIT (pick the .tar.gz). Move it to a directory of your choice, open a terminal window and change to this directory. Now unpack the archive and change to the newly created directory (replace XX.YY.ZZ with the version you downloaded):

tar zxf LuaJIT-XX.YY.ZZ.tar.gz
cd LuaJIT-XX.YY.ZZ

Building LuaJIT

The supplied Makefiles try to auto-detect the settings needed for your operating system and your compiler. They need to be run with GNU Make, which is probably the default on your system, anyway. Simply run:

make

This always builds a native binary, depending on the host OS you're running this command on. Check the section on cross-compilation for more options.

By default, modules are only searched under the prefix /usr/local. You can add an extra prefix to the search paths by appending the PREFIX option, e.g.:

make PREFIX=/home/myself/lj2

Note for macOS: you must set the MACOSX_DEPLOYMENT_TARGET environment variable to a value supported by your toolchain:

MACOSX_DEPLOYMENT_TARGET=XX.YY make

Installing LuaJIT

The top-level Makefile installs LuaJIT by default under /usr/local, i.e. the executable ends up in /usr/local/bin and so on. You need root privileges to write to this path. So, assuming sudo is installed on your system, run the following command and enter your sudo password:

sudo make install

Otherwise specify the directory prefix as an absolute path, e.g.:

make install PREFIX=/home/myself/lj2

Obviously the prefixes given during build and installation need to be the same.

Windows Systems

Prerequisites

Either install one of the open source SDKs (» MinGW or » Cygwin), which come with a modified GCC plus the required development headers. Or install Microsoft's Visual Studio (MSVC).

Next, pull from the git repository or download the source package and unpack it using an archive manager (e.g. the Windows Explorer) to a directory of your choice.

Building with MSVC

Open a "Visual Studio Command Prompt" (either x86 or x64), cd to the directory where you've unpacked the sources and run these commands:

cd src
msvcbuild

Check the msvcbuild.bat file for more options. Then follow the installation instructions below.

Building with MinGW or Cygwin

Open a command prompt window and make sure the MinGW or Cygwin programs are in your path. Then cd to the directory of the git repository or where you've unpacked the sources. Then run this command for MinGW:

mingw32-make

Or this command for Cygwin:

make

Then follow the installation instructions below.

Installing LuaJIT

Copy luajit.exe and lua51.dll (built in the src directory) to a newly created directory (any location is ok). Add lua and lua\jit directories below it and copy all Lua files from the src\jit directory of the distribution to the latter directory.

There are no hardcoded absolute path names — all modules are loaded relative to the directory where luajit.exe is installed (see src/luaconf.h).

Cross-compiling LuaJIT

First, let's clear up some terminology:

  • Host: This is your development system, usually based on a x64 or x86 CPU.
  • Target: This is the target system you want LuaJIT to run on, e.g. Android/ARM.
  • Toolchain: This comprises a C compiler, linker, assembler and a matching C library.
  • Host (or system) toolchain: This is the toolchain used to build native binaries for your host system.
  • Cross-compile toolchain: This is the toolchain used to build binaries for the target system. They can only be run on the target system.

The GNU Makefile-based build system allows cross-compiling on any host for any supported target:

  • Yes, you need a toolchain for both your host and your target!
  • Both host and target architectures must have the same pointer size.
  • E.g. if you want to cross-compile to a 32 bit target on a 64 bit host, you need to install the multilib development package (e.g. libc6-dev-i386 on Debian/Ubuntu) and build a 32 bit host part (HOST_CC="gcc -m32").
  • 64 bit targets always require compilation on a 64 bit host.

You need to specify TARGET_SYS whenever the host OS and the target OS differ, or you'll get assembler or linker errors:

  • E.g. if you're compiling on a Windows or macOS host for embedded Linux or Android, you need to add TARGET_SYS=Linux to the examples below.
  • For a minimal target OS, you may need to disable the built-in allocator in src/Makefile and use TARGET_SYS=Other.
  • Don't forget to specify the same TARGET_SYS for the install step, too.

Here are some examples where host and target have the same CPU:

# Cross-compile to a 32 bit binary on a multilib x64 OS
make CC="gcc -m32"

# Cross-compile on Debian/Ubuntu for Windows (mingw32 package)
make HOST_CC="gcc -m32" CROSS=i586-mingw32msvc- TARGET_SYS=Windows

The CROSS prefix allows specifying a standard GNU cross-compile toolchain (Binutils, GCC and a matching libc). The prefix may vary depending on the --target the toolchain was built for (note the CROSS prefix has a trailing "-"). The examples below use the canonical toolchain triplets for Linux.

Since there's often no easy way to detect CPU features at runtime, it's important to compile with the proper CPU or architecture settings:

  • The best way to get consistent results is to specify the correct settings when building the toolchain yourself.
  • For a pre-built, generic toolchain add -mcpu=... or -march=... and other necessary flags to TARGET_CFLAGS.
  • For ARM it's important to have the correct -mfloat-abi=... setting, too. Otherwise LuaJIT may not run at the full performance of your target CPU.
  • For MIPS it's important to select a supported ABI (o32 on MIPS32, n64 on MIPS64) and consistently compile your project either with hard-float or soft-float compiler settings.

Here are some examples for targets with a different CPU than the host:

# ARM soft-float
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
     TARGET_CFLAGS="-mfloat-abi=soft"

# ARM soft-float ABI with VFP (example for Cortex-A9)
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
     TARGET_CFLAGS="-mcpu=cortex-a9 -mfloat-abi=softfp"

# ARM hard-float ABI with VFP (armhf, most modern toolchains)
make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabihf-

# ARM64
make CROSS=aarch64-linux-

# PPC
make HOST_CC="gcc -m32" CROSS=powerpc-linux-gnu-

# MIPS32 big-endian
make HOST_CC="gcc -m32" CROSS=mips-linux-
# MIPS32 little-endian
make HOST_CC="gcc -m32" CROSS=mipsel-linux-

# MIPS64 big-endian
make CROSS=mips-linux- TARGET_CFLAGS="-mips64r2 -mabi=64"
# MIPS64 little-endian
make CROSS=mipsel-linux- TARGET_CFLAGS="-mips64r2 -mabi=64"

You can cross-compile for Android using the » Android NDK. Please adapt the environment variables to match the install locations and the desired target platform. E.g. Android 4.1 corresponds to ABI level 16.

# Android/ARM64, aarch64, Android 5.0+ (L)
NDKDIR=/opt/android/ndk
NDKBIN=$NDKDIR/toolchains/llvm/prebuilt/linux-x86_64/bin
NDKCROSS=$NDKBIN/aarch64-linux-android-
NDKCC=$NDKBIN/aarch64-linux-android21-clang
make CROSS=$NDKCROSS \
     STATIC_CC=$NDKCC DYNAMIC_CC="$NDKCC -fPIC" \
     TARGET_LD=$NDKCC TARGET_AR="$NDKBIN/llvm-ar rcus" \
     TARGET_STRIP=$NDKBIN/llvm-strip

# Android/ARM, armeabi-v7a (ARMv7 VFP), Android 4.1+ (JB)
NDKDIR=/opt/android/ndk
NDKBIN=$NDKDIR/toolchains/llvm/prebuilt/linux-x86_64/bin
NDKCROSS=$NDKBIN/arm-linux-androideabi-
NDKCC=$NDKBIN/armv7a-linux-androideabi16-clang
make HOST_CC="gcc -m32" CROSS=$NDKCROSS \
     STATIC_CC=$NDKCC DYNAMIC_CC="$NDKCC -fPIC" \
     TARGET_LD=$NDKCC TARGET_AR="$NDKBIN/llvm-ar rcus" \
     TARGET_STRIP=$NDKBIN/llvm-strip

You can cross-compile for iOS 3.0+ (iPhone/iPad) using the » iOS SDK:

Note: the JIT compiler is disabled for iOS, because regular iOS Apps are not allowed to generate code at runtime. You'll only get the performance of the LuaJIT interpreter on iOS. This is still faster than plain Lua, but much slower than the JIT compiler. Please complain to Apple, not me. Or use Android. :-p

# iOS/ARM64
ISDKP=$(xcrun --sdk iphoneos --show-sdk-path)
ICC=$(xcrun --sdk iphoneos --find clang)
ISDKF="-arch arm64 -isysroot $ISDKP"
make DEFAULT_CC=clang CROSS="$(dirname $ICC)/" \
     TARGET_FLAGS="$ISDKF" TARGET_SYS=iOS

Cross-compiling for consoles

Building LuaJIT for consoles requires both a supported host compiler (x86 or x64) and a cross-compiler from the official console SDK.

Due to restrictions on consoles, the JIT compiler is disabled and only the fast interpreter is built. This is still faster than plain Lua, but much slower than the JIT compiler. The FFI is disabled, too, since it's not very useful in such an environment.

The following commands build a static library libluajit.a, which can be linked against your game, just like the Lua library.

To cross-compile for PS3 from a Linux host (requires 32 bit GCC, i.e. multilib Linux/x64) or a Windows host (requires 32 bit MinGW), run this command:

make HOST_CC="gcc -m32" CROSS=ppu-lv2-

To cross-compile for the other consoles from a Windows host, open a "Native Tools Command Prompt for VS". You need to choose either the 32 or the 64 bit version of the host compiler to match the target. Then cd to the src directory below where you've unpacked the sources and run the build command given in the table:

Console Bits Build Command
PS4 64 ps4build
PS5 64 ps5build
PS Vita 32 psvitabuild
Xbox 360 32 xedkbuild
Xbox One 64 xb1build
Nintendo Switch NX32 32 nxbuild
Nintendo Switch NX64 64 nxbuild

Please check out the comments in the corresponding *.bat file for more options.

Embedding LuaJIT

LuaJIT is API-compatible with Lua 5.1. If you've already embedded Lua into your application, you probably don't need to do anything to switch to LuaJIT, except link with a different library:

  • It's strongly suggested to build LuaJIT separately using the supplied build system. Please do not attempt to integrate the individual source files into your build tree. You'll most likely get the internal build dependencies wrong or mess up the compiler flags. Treat LuaJIT like any other external library and link your application with either the dynamic or static library, depending on your needs.
  • If you want to load C modules compiled for plain Lua with require(), you need to make sure the public symbols (e.g. lua_pushnumber) are exported, too:
    • On POSIX systems you can either link to the shared library or link the static library into your application. In the latter case you'll need to export all public symbols from your main executable (e.g. -Wl,-E on Linux) and add the external dependencies (e.g. -lm -ldl on Linux).
    • Since Windows symbols are bound to a specific DLL name, you need to link to the lua51.dll created by the LuaJIT build (do not rename the DLL). You may link LuaJIT statically on Windows only if you don't intend to load Lua/C modules at runtime.

Additional hints for initializing LuaJIT using the C API functions:

  • Here's a » simple example for embedding Lua or LuaJIT into your application.
  • Make sure you use luaL_newstate. Avoid using lua_newstate, since this uses the (slower) default memory allocator from your system (no support for this on 64 bit architectures).
  • Make sure you use luaL_openlibs and not the old Lua 5.0 style of calling luaopen_base etc. directly.
  • To change or extend the list of standard libraries to load, copy src/lib_init.c to your project and modify it accordingly. Make sure the jit library is loaded, or the JIT compiler will not be activated.
  • The bit.* module for bitwise operations is already built-in. There's no need to statically link » Lua BitOp to your application.

Hints for Distribution Maintainers

The LuaJIT build system has extra provisions for the needs of most POSIX-based distributions. If you're a package maintainer for a distribution, please make use of these features and avoid patching, subverting, autotoolizing or messing up the build system in unspeakable ways.

There should be absolutely no need to patch luaconf.h or any of the Makefiles. And please do not hand-pick files for your packages — simply use whatever make install creates. There's a reason for all the files and directories it creates.

The build system uses GNU make and auto-detects most settings based on the host you're building it on. This should work fine for native builds, even when sandboxed. You may need to pass some of the following flags to both the make and the make install command lines for a regular distribution build:

  • PREFIX overrides the installation path and should usually be set to /usr. Setting this also changes the module paths and the paths needed to locate the shared library.
  • DESTDIR is an absolute path which allows you to install to a shadow tree instead of the root tree of the build system.
  • MULTILIB sets the architecture-specific library path component for multilib systems. The default is lib.
  • Have a look at the top-level Makefile and src/Makefile for additional variables to tweak. The following variables may be overridden, but it's not recommended, except for special needs like cross-builds: BUILDMODE, CC, HOST_CC, STATIC_CC, DYNAMIC_CC, CFLAGS, HOST_CFLAGS, TARGET_CFLAGS, LDFLAGS, HOST_LDFLAGS, TARGET_LDFLAGS, TARGET_SHLDFLAGS, TARGET_FLAGS, LIBS, HOST_LIBS, TARGET_LIBS, CROSS, HOST_SYS, TARGET_SYS

The build system has a special target for an amalgamated build, i.e. make amalg. This compiles the LuaJIT core as one huge C file and allows GCC to generate faster and shorter code. Alas, this requires lots of memory during the build. This may be a problem for some users, that's why it's not enabled by default. But it shouldn't be a problem for most build farms. It's recommended that binary distributions use this target for their LuaJIT builds.

The tl;dr version of the above:

make amalg PREFIX=/usr && \
make install PREFIX=/usr DESTDIR=/tmp/buildroot

Finally, if you encounter any difficulties, please contact me first, instead of releasing a broken package onto unsuspecting users. Because they'll usually gonna complain to me (the upstream) and not you (the package maintainer), anyway.


================================================ FILE: third_party/luajit/luajit/doc/luajit.html ================================================ LuaJIT

LuaJIT is a Just-In-Time Compiler (JIT) for the » Lua programming language. Lua is a powerful, dynamic and light-weight programming language. It may be embedded or used as a general-purpose, stand-alone language.

LuaJIT is Copyright © 2005-2022 Mike Pall, released under the » MIT open source license.

Compatibility

WindowsLinuxBSDmacOSPOSIX
EmbeddedAndroidiOS
PS3PS4
PS5
PS VitaXbox 360Xbox OneNintendo
Switch
GCCClang
LLVM
MSVC
x86
x64
ARM
ARM64
PPCMIPS32
MIPS64
Lua 5.1
API+ABI
+ JIT+ BitOp+ FFIDrop-in
DLL/.so

Overview

3x
-  100x
115 KB
VM
90 KB
JIT
63 KLOC
C
24 KLOC
ASM
11 KLOC
Lua

LuaJIT has been successfully used as a scripting middleware in games, appliances, network and graphics apps, numerical simulations, trading platforms and many other specialty applications. It scales from embedded devices, smartphones, desktops up to server farms. It combines high flexibility with high performance and an unmatched low memory footprint.

LuaJIT has been in continuous development since 2005. It's widely considered to be one of the fastest dynamic language implementations. It has outperformed other dynamic languages on many cross-language benchmarks since its first release — often by a substantial margin.

For LuaJIT 2.0, the whole VM has been rewritten from the ground up and relentlessly optimized for performance. It combines a high-speed interpreter, written in assembler, with a state-of-the-art JIT compiler.

An innovative trace compiler is integrated with advanced, SSA-based optimizations and highly tuned code generation backends. A substantial reduction of the overhead associated with dynamic languages allows it to break into the performance range traditionally reserved for offline, static language compilers.

More ...

Please select a sub-topic in the navigation bar to learn more about LuaJIT.


================================================ FILE: third_party/luajit/luajit/doc/running.html ================================================ Running LuaJIT

LuaJIT has only a single stand-alone executable, called luajit on POSIX systems or luajit.exe on Windows. It can be used to run simple Lua statements or whole Lua applications from the command line. It has an interactive mode, too.

Command Line Options

The luajit stand-alone executable is just a slightly modified version of the regular lua stand-alone executable. It supports the same basic options, too. luajit -h prints a short list of the available options. Please have a look at the » Lua manual for details.

LuaJIT has some additional options:

-b[options] input output

This option saves or lists bytecode. The following additional options are accepted:

  • -l — Only list bytecode.
  • -s — Strip debug info (this is the default).
  • -g — Keep debug info.
  • -n name — Set module name (default: auto-detect from input name)
  • -t type — Set output file type (default: auto-detect from output name).
  • -a arch — Override architecture for object files (default: native).
  • -o os — Override OS for object files (default: native).
  • -F name — Override filename (default: input filename).
  • -e chunk — Use chunk string as input.
  • - (a single minus sign) — Use stdin as input and/or stdout as output.

The output file type is auto-detected from the extension of the output file name:

  • c — C source file, exported bytecode data.
  • h — C header file, static bytecode data.
  • obj or o — Object file, exported bytecode data (OS- and architecture-specific).
  • raw or any other extension — Raw bytecode file (portable).

Notes:

  • See also string.dump() for information on bytecode portability and compatibility.
  • A file in raw bytecode format is auto-detected and can be loaded like any Lua source file. E.g. directly from the command line or with loadfile(), dofile() etc.
  • To statically embed the bytecode of a module in your application, generate an object file and just link it with your application.
  • On most ELF-based systems (e.g. Linux) you need to explicitly export the global symbols when linking your application, e.g. with: -Wl,-E
  • require() tries to load embedded bytecode data from exported symbols (in *.exe or lua51.dll on Windows) and from shared libraries in package.cpath.

Typical usage examples:

luajit -b test.lua test.out                 # Save bytecode to test.out
luajit -bg test.lua test.out                # Keep debug info
luajit -be "print('hello world')" test.out  # Save cmdline script

luajit -bl test.lua                         # List to stdout
luajit -bl test.lua test.txt                # List to test.txt
luajit -ble "print('hello world')"          # List cmdline script

luajit -b test.lua test.obj                 # Generate object file
# Link test.obj with your application and load it with require("test")

-j cmd[=arg[,arg...]]

This option performs a LuaJIT control command or activates one of the loadable extension modules. The command is first looked up in the jit.* library. If no matching function is found, a module named jit.<cmd> is loaded and the start() function of the module is called with the specified arguments (if any). The space between -j and cmd is optional.

Here are the available LuaJIT control commands:

  • -jon — Turns the JIT compiler on (default).
  • -joff — Turns the JIT compiler off (only use the interpreter).
  • -jflush — Flushes the whole cache of compiled code.
  • -jv — Shows verbose information about the progress of the JIT compiler.
  • -jdump — Dumps the code and structures used in various compiler stages.
  • -jp — Start the integrated profiler.

The -jv and -jdump commands are extension modules written in Lua. They are mainly used for debugging the JIT compiler itself. For a description of their options and output format, please read the comment block at the start of their source. They can be found in the lib directory of the source distribution or installed under the jit directory. By default, this is /usr/local/share/luajit-XX.YY.ZZ>/jit on POSIX systems (replace XX.YY.ZZ by the installed version).

-O[level]
-O[+]flag   -O-flag
-Oparam=value

This options allows fine-tuned control of the optimizations used by the JIT compiler. This is mainly intended for debugging LuaJIT itself. Please note that the JIT compiler is extremely fast (we are talking about the microsecond to millisecond range). Disabling optimizations doesn't have any visible impact on its overhead, but usually generates code that runs slower.

The first form sets an optimization level — this enables a specific mix of optimization flags. -O0 turns off all optimizations and higher numbers enable more optimizations. Omitting the level (i.e. just -O) sets the default optimization level, which is -O3 in the current version.

The second form adds or removes individual optimization flags. The third form sets a parameter for the VM or the JIT compiler to a specific value.

You can either use this option multiple times (like -Ocse -O-dce -Ohotloop=10) or separate several settings with a comma (like -O+cse,-dce,hotloop=10). The settings are applied from left to right, and later settings override earlier ones. You can freely mix the three forms, but note that setting an optimization level overrides all earlier flags.

Note that -Ofma is not enabled by default at any level, because it affects floating-point result accuracy. Only enable this, if you fully understand the trade-offs of FMA for performance (higher), determinism (lower) and numerical accuracy (higher).

Here are the available flags and at what optimization levels they are enabled:

Flag -O1 -O2 -O3  
foldConstant Folding, Simplifications and Reassociation
cseCommon-Subexpression Elimination
dceDead-Code Elimination
narrow Narrowing of numbers to integers
loop Loop Optimizations (code hoisting)
fwd  Load Forwarding (L2L) and Store Forwarding (S2L)
dse  Dead-Store Elimination
abc  Array Bounds Check Elimination
sink  Allocation/Store Sinking
fuse  Fusion of operands into instructions
fma    Fused multiply-add

Here are the parameters and their default settings:

Parameter Default  
maxtrace1000Max. number of traces in the cache
maxrecord4000Max. number of recorded IR instructions
maxirconst500Max. number of IR constants of a trace
maxside100Max. number of side traces of a root trace
maxsnap500Max. number of snapshots for a trace
hotloop56Number of iterations to detect a hot loop or hot call
hotexit10Number of taken exits to start a side trace
tryside4Number of attempts to compile a side trace
instunroll4Max. unroll factor for instable loops
loopunroll15Max. unroll factor for loop ops in side traces
callunroll3Max. unroll factor for pseudo-recursive calls
recunroll2Min. unroll factor for true recursion
sizemcode32Size of each machine code area in KBytes (Windows: 64K)
maxmcode512Max. total size of all machine code areas in KBytes

================================================ FILE: third_party/luajit/luajit/doc/status.html ================================================ Status

This documentation is for LuaJIT 2.1.0-beta3. Please check the doc directory in each git branch for the version-specific documentation.

The currently developed branches are LuaJIT 2.1 and LuaJIT 2.0.

LuaJIT 2.0 is in feature-freeze — new features will only be added to LuaJIT 2.1.

Current Status

LuaJIT ought to run all Lua 5.1-compatible source code just fine. It's considered a serious bug if the VM crashes or produces unexpected results — please report this.

Known incompatibilities and issues in LuaJIT 2.0:

  • There are some differences in implementation-defined behavior. These either have a good reason, are arbitrary design choices, or are due to quirks in the VM. The latter cases may get fixed if a demonstrable need is shown.
  • The Lua debug API is missing a couple of features (return hooks for non-Lua functions) and shows slightly different behavior in LuaJIT (no per-coroutine hooks, no tail call counting).

================================================ FILE: third_party/luajit/luajit/dynasm/dasm_arm.h ================================================ /* ** DynASM ARM encoding engine. ** Copyright (C) 2005-2022 Mike Pall. All rights reserved. ** Released under the MIT license. See dynasm.lua for full copyright notice. */ #include #include #include #include #define DASM_ARCH "arm" #ifndef DASM_EXTERN #define DASM_EXTERN(a,b,c,d) 0 #endif /* Action definitions. */ enum { DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, /* The following actions need a buffer position. */ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, /* The following actions also have an argument. */ DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8, DASM__MAX }; /* Maximum number of section buffer positions for a single dasm_put() call. */ #define DASM_MAXSECPOS 25 /* DynASM encoder status codes. Action list offset or number are or'ed in. */ #define DASM_S_OK 0x00000000 #define DASM_S_NOMEM 0x01000000 #define DASM_S_PHASE 0x02000000 #define DASM_S_MATCH_SEC 0x03000000 #define DASM_S_RANGE_I 0x11000000 #define DASM_S_RANGE_SEC 0x12000000 #define DASM_S_RANGE_LG 0x13000000 #define DASM_S_RANGE_PC 0x14000000 #define DASM_S_RANGE_REL 0x15000000 #define DASM_S_UNDEF_LG 0x21000000 #define DASM_S_UNDEF_PC 0x22000000 /* Macros to convert positions (8 bit section + 24 bit index). */ #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) #define DASM_POS2BIAS(pos) ((pos)&0xff000000) #define DASM_SEC2POS(sec) ((sec)<<24) #define DASM_POS2SEC(pos) ((pos)>>24) #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) /* Action list type. */ typedef const unsigned int *dasm_ActList; /* Per-section structure. */ typedef struct dasm_Section { int *rbuf; /* Biased buffer pointer (negative section bias). */ int *buf; /* True buffer pointer. */ size_t bsize; /* Buffer size in bytes. */ int pos; /* Biased buffer position. */ int epos; /* End of biased buffer position - max single put. */ int ofs; /* Byte offset into section. */ } dasm_Section; /* Core structure holding the DynASM encoding state. */ struct dasm_State { size_t psize; /* Allocated size of this structure. */ dasm_ActList actionlist; /* Current actionlist pointer. */ int *lglabels; /* Local/global chain/pos ptrs. */ size_t lgsize; int *pclabels; /* PC label chains/pos ptrs. */ size_t pcsize; void **globals; /* Array of globals (bias -10). */ dasm_Section *section; /* Pointer to active section. */ size_t codesize; /* Total size of all code sections. */ int maxsection; /* 0 <= sectionidx < maxsection. */ int status; /* Status code. */ dasm_Section sections[1]; /* All sections. Alloc-extended. */ }; /* The size of the core structure depends on the max. number of sections. */ #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) /* Initialize DynASM state. */ void dasm_init(Dst_DECL, int maxsection) { dasm_State *D; size_t psz = 0; int i; Dst_REF = NULL; DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); D = Dst_REF; D->psize = psz; D->lglabels = NULL; D->lgsize = 0; D->pclabels = NULL; D->pcsize = 0; D->globals = NULL; D->maxsection = maxsection; for (i = 0; i < maxsection; i++) { D->sections[i].buf = NULL; /* Need this for pass3. */ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); D->sections[i].bsize = 0; D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ } } /* Free DynASM state. */ void dasm_free(Dst_DECL) { dasm_State *D = Dst_REF; int i; for (i = 0; i < D->maxsection; i++) if (D->sections[i].buf) DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); DASM_M_FREE(Dst, D, D->psize); } /* Setup global label array. Must be called before dasm_setup(). */ void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) { dasm_State *D = Dst_REF; D->globals = gl - 10; /* Negative bias to compensate for locals. */ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); } /* Grow PC label array. Can be called after dasm_setup(), too. */ void dasm_growpc(Dst_DECL, unsigned int maxpc) { dasm_State *D = Dst_REF; size_t osz = D->pcsize; DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); } /* Setup encoder. */ void dasm_setup(Dst_DECL, const void *actionlist) { dasm_State *D = Dst_REF; int i; D->actionlist = (dasm_ActList)actionlist; D->status = DASM_S_OK; D->section = &D->sections[0]; memset((void *)D->lglabels, 0, D->lgsize); if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); for (i = 0; i < D->maxsection; i++) { D->sections[i].pos = DASM_SEC2POS(i); D->sections[i].ofs = 0; } } #ifdef DASM_CHECKS #define CK(x, st) \ do { if (!(x)) { \ D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) #define CKPL(kind, st) \ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) #else #define CK(x, st) ((void)0) #define CKPL(kind, st) ((void)0) #endif static int dasm_imm12(unsigned int n) { int i; for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30)) if (n <= 255) return (int)(n + (i << 8)); return -1; } /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ void dasm_put(Dst_DECL, int start, ...) { va_list ap; dasm_State *D = Dst_REF; dasm_ActList p = D->actionlist + start; dasm_Section *sec = D->section; int pos = sec->pos, ofs = sec->ofs; int *b; if (pos >= sec->epos) { DASM_M_GROW(Dst, int, sec->buf, sec->bsize, sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); sec->rbuf = sec->buf - DASM_POS2BIAS(pos); sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); } b = sec->rbuf; b[pos++] = start; va_start(ap, start); while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16); if (action >= DASM__MAX) { ofs += 4; } else { int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; switch (action) { case DASM_STOP: goto stop; case DASM_SECTION: n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; goto stop; case DASM_ESC: p++; ofs += 4; break; case DASM_REL_EXT: break; case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; case DASM_REL_LG: n = (ins & 2047) - 10; pl = D->lglabels + n; /* Bkwd rel or global. */ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } pl += 10; n = *pl; if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ goto linkrel; case DASM_REL_PC: pl = D->pclabels + n; CKPL(pc, PC); putrel: n = *pl; if (n < 0) { /* Label exists. Get label pos and store it. */ b[pos] = -n; } else { linkrel: b[pos] = n; /* Else link to rel chain, anchored at label. */ *pl = pos; } pos++; break; case DASM_LABEL_LG: pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; case DASM_LABEL_PC: pl = D->pclabels + n; CKPL(pc, PC); putlabel: n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } *pl = -pos; /* Label exists now. */ b[pos++] = ofs; /* Store pass1 offset estimate. */ break; case DASM_IMM: case DASM_IMM16: #ifdef DASM_CHECKS CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); if ((ins & 0x8000)) CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); else CK((n>>((ins>>5)&31)) == 0, RANGE_I); #endif b[pos++] = n; break; case DASM_IMMV8: CK((n & 3) == 0, RANGE_I); n >>= 2; /* fallthrough */ case DASM_IMML8: case DASM_IMML12: CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) : (((-n)>>((ins>>5)&31)) == 0), RANGE_I); b[pos++] = n; break; case DASM_IMM12: CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); b[pos++] = n; break; } } } stop: va_end(ap); sec->pos = pos; sec->ofs = ofs; } #undef CK /* Pass 2: Link sections, shrink aligns, fix label offsets. */ int dasm_link(Dst_DECL, size_t *szp) { dasm_State *D = Dst_REF; int secnum; int ofs = 0; #ifdef DASM_CHECKS *szp = 0; if (D->status != DASM_S_OK) return D->status; { int pc; for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; } #endif { /* Handle globals not defined in this translation unit. */ int idx; for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { int n = D->lglabels[idx]; /* Undefined label: Collapse rel chain and replace with marker (< 0). */ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } } } /* Combine all code sections. No support for data sections (yet). */ for (secnum = 0; secnum < D->maxsection; secnum++) { dasm_Section *sec = D->sections + secnum; int *b = sec->rbuf; int pos = DASM_SEC2POS(secnum); int lastpos = sec->pos; while (pos != lastpos) { dasm_ActList p = D->actionlist + b[pos++]; while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16); switch (action) { case DASM_STOP: case DASM_SECTION: goto stop; case DASM_ESC: p++; break; case DASM_REL_EXT: break; case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; case DASM_REL_LG: case DASM_REL_PC: pos++; break; case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; case DASM_IMM: case DASM_IMM12: case DASM_IMM16: case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break; } } stop: (void)0; } ofs += sec->ofs; /* Next section starts right after current section. */ } D->codesize = ofs; /* Total size of all code sections */ *szp = ofs; return DASM_S_OK; } #ifdef DASM_CHECKS #define CK(x, st) \ do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) #else #define CK(x, st) ((void)0) #endif /* Pass 3: Encode sections. */ int dasm_encode(Dst_DECL, void *buffer) { dasm_State *D = Dst_REF; char *base = (char *)buffer; unsigned int *cp = (unsigned int *)buffer; int secnum; /* Encode all code sections. No support for data sections (yet). */ for (secnum = 0; secnum < D->maxsection; secnum++) { dasm_Section *sec = D->sections + secnum; int *b = sec->buf; int *endb = sec->rbuf + sec->pos; while (b != endb) { dasm_ActList p = D->actionlist + *b++; while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16); int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; switch (action) { case DASM_STOP: case DASM_SECTION: goto stop; case DASM_ESC: *cp++ = *p++; break; case DASM_REL_EXT: n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); goto patchrel; case DASM_ALIGN: ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; break; case DASM_REL_LG: if (n < 0) { n = (int)((ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp - 4); goto patchrel; } /* fallthrough */ case DASM_REL_PC: CK(n >= 0, UNDEF_PC); n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4; patchrel: if ((ins & 0x800) == 0) { CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL); cp[-1] |= ((n >> 2) & 0x00ffffff); } else if ((ins & 0x1000)) { CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL); goto patchimml8; } else if ((ins & 0x2000) == 0) { CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL); goto patchimml; } else { CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL); n >>= 2; goto patchimml; } break; case DASM_LABEL_LG: ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); break; case DASM_LABEL_PC: break; case DASM_IMM: cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); break; case DASM_IMM12: cp[-1] |= dasm_imm12((unsigned int)n); break; case DASM_IMM16: cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff); break; case DASM_IMML8: patchimml8: cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) : ((-n & 0x0f) | ((-n & 0xf0) << 4)); break; case DASM_IMML12: case DASM_IMMV8: patchimml: cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n); break; default: *cp++ = ins; break; } } stop: (void)0; } } if (base + D->codesize != (char *)cp) /* Check for phase errors. */ return DASM_S_PHASE; return DASM_S_OK; } #undef CK /* Get PC label offset. */ int dasm_getpclabel(Dst_DECL, unsigned int pc) { dasm_State *D = Dst_REF; if (pc*sizeof(int) < D->pcsize) { int pos = D->pclabels[pc]; if (pos < 0) return *DASM_POS2PTR(D, -pos); if (pos > 0) return -1; /* Undefined. */ } return -2; /* Unused or out of range. */ } #ifdef DASM_CHECKS /* Optional sanity checker to call between isolated encoding steps. */ int dasm_checkstep(Dst_DECL, int secmatch) { dasm_State *D = Dst_REF; if (D->status == DASM_S_OK) { int i; for (i = 1; i <= 9; i++) { if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } D->lglabels[i] = 0; } } if (D->status == DASM_S_OK && secmatch >= 0 && D->section != &D->sections[secmatch]) D->status = DASM_S_MATCH_SEC|(D->section-D->sections); return D->status; } #endif ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_arm.lua ================================================ ------------------------------------------------------------------------------ -- DynASM ARM module. -- -- Copyright (C) 2005-2022 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------ -- Module information: local _info = { arch = "arm", description = "DynASM ARM module", version = "1.5.0", vernum = 10500, release = "2021-05-02", author = "Mike Pall", license = "MIT", } -- Exported glue functions for the arch-specific module. local _M = { _info = _info } -- Cache library functions. local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs local assert, setmetatable, rawget = assert, setmetatable, rawget local _s = string local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub local concat, sort, insert = table.concat, table.sort, table.insert local bit = bit or require("bit") local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift local ror, tohex = bit.ror, bit.tohex -- Inherited tables and callbacks. local g_opt, g_arch local wline, werror, wfatal, wwarn -- Action name list. -- CHECK: Keep this in sync with the C code! local action_names = { "STOP", "SECTION", "ESC", "REL_EXT", "ALIGN", "REL_LG", "LABEL_LG", "REL_PC", "LABEL_PC", "IMM", "IMM12", "IMM16", "IMML8", "IMML12", "IMMV8", } -- Maximum number of section buffer positions for dasm_put(). -- CHECK: Keep this in sync with the C code! local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. -- Action name -> action number. local map_action = {} for n,name in ipairs(action_names) do map_action[name] = n-1 end -- Action list buffer. local actlist = {} -- Argument list for next dasm_put(). Start with offset 0 into action list. local actargs = { 0 } -- Current number of section buffer positions for dasm_put(). local secpos = 1 ------------------------------------------------------------------------------ -- Dump action names and numbers. local function dumpactions(out) out:write("DynASM encoding engine action codes:\n") for n,name in ipairs(action_names) do local num = map_action[name] out:write(format(" %-10s %02X %d\n", name, num, num)) end out:write("\n") end -- Write action list buffer as a huge static C array. local function writeactions(out, name) local nn = #actlist if nn == 0 then nn = 1; actlist[0] = map_action.STOP end out:write("static const unsigned int ", name, "[", nn, "] = {\n") for i = 1,nn-1 do assert(out:write("0x", tohex(actlist[i]), ",\n")) end assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) end ------------------------------------------------------------------------------ -- Add word to action list. local function wputxw(n) assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") actlist[#actlist+1] = n end -- Add action to list with optional arg. Advance buffer pos, too. local function waction(action, val, a, num) local w = assert(map_action[action], "bad action name `"..action.."'") wputxw(w * 0x10000 + (val or 0)) if a then actargs[#actargs+1] = a end if a or num then secpos = secpos + (num or 1) end end -- Flush action list (intervening C code or buffer pos overflow). local function wflush(term) if #actlist == actargs[1] then return end -- Nothing to flush. if not term then waction("STOP") end -- Terminate action list. wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). secpos = 1 -- The actionlist offset occupies a buffer position, too. end -- Put escaped word. local function wputw(n) if n <= 0x000fffff then waction("ESC") end wputxw(n) end -- Reserve position for word. local function wpos() local pos = #actlist+1 actlist[pos] = "" return pos end -- Store word to reserved position. local function wputpos(pos, n) assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") if n <= 0x000fffff then insert(actlist, pos+1, n) n = map_action.ESC * 0x10000 end actlist[pos] = n end ------------------------------------------------------------------------------ -- Global label name -> global label number. With auto assignment on 1st use. local next_global = 20 local map_global = setmetatable({}, { __index = function(t, name) if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end local n = next_global if n > 2047 then werror("too many global labels") end next_global = n + 1 t[name] = n return n end}) -- Dump global labels. local function dumpglobals(out, lvl) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("Global labels:\n") for i=20,next_global-1 do out:write(format(" %s\n", t[i])) end out:write("\n") end -- Write global label enum. local function writeglobals(out, prefix) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("enum {\n") for i=20,next_global-1 do out:write(" ", prefix, t[i], ",\n") end out:write(" ", prefix, "_MAX\n};\n") end -- Write global label names. local function writeglobalnames(out, name) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("static const char *const ", name, "[] = {\n") for i=20,next_global-1 do out:write(" \"", t[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Extern label name -> extern label number. With auto assignment on 1st use. local next_extern = 0 local map_extern_ = {} local map_extern = setmetatable({}, { __index = function(t, name) -- No restrictions on the name for now. local n = next_extern if n > 2047 then werror("too many extern labels") end next_extern = n + 1 t[name] = n map_extern_[n] = name return n end}) -- Dump extern labels. local function dumpexterns(out, lvl) out:write("Extern labels:\n") for i=0,next_extern-1 do out:write(format(" %s\n", map_extern_[i])) end out:write("\n") end -- Write extern label names. local function writeexternnames(out, name) out:write("static const char *const ", name, "[] = {\n") for i=0,next_extern-1 do out:write(" \"", map_extern_[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Arch-specific maps. -- Ext. register name -> int. name. local map_archdef = { sp = "r13", lr = "r14", pc = "r15", } -- Int. register name -> ext. name. local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", } local map_type = {} -- Type name -> { ctype, reg } local ctypenum = 0 -- Type number (for Dt... macros). -- Reverse defines for registers. function _M.revdef(s) return map_reg_rev[s] or s end local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, } local map_cond = { eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7, hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14, hs = 2, lo = 3, } ------------------------------------------------------------------------------ -- Template strings for ARM instructions. local map_op = { -- Basic data processing instructions. and_3 = "e0000000DNPs", eor_3 = "e0200000DNPs", sub_3 = "e0400000DNPs", rsb_3 = "e0600000DNPs", add_3 = "e0800000DNPs", adc_3 = "e0a00000DNPs", sbc_3 = "e0c00000DNPs", rsc_3 = "e0e00000DNPs", tst_2 = "e1100000NP", teq_2 = "e1300000NP", cmp_2 = "e1500000NP", cmn_2 = "e1700000NP", orr_3 = "e1800000DNPs", mov_2 = "e1a00000DPs", bic_3 = "e1c00000DNPs", mvn_2 = "e1e00000DPs", and_4 = "e0000000DNMps", eor_4 = "e0200000DNMps", sub_4 = "e0400000DNMps", rsb_4 = "e0600000DNMps", add_4 = "e0800000DNMps", adc_4 = "e0a00000DNMps", sbc_4 = "e0c00000DNMps", rsc_4 = "e0e00000DNMps", tst_3 = "e1100000NMp", teq_3 = "e1300000NMp", cmp_3 = "e1500000NMp", cmn_3 = "e1700000NMp", orr_4 = "e1800000DNMps", mov_3 = "e1a00000DMps", bic_4 = "e1c00000DNMps", mvn_3 = "e1e00000DMps", lsl_3 = "e1a00000DMws", lsr_3 = "e1a00020DMws", asr_3 = "e1a00040DMws", ror_3 = "e1a00060DMws", rrx_2 = "e1a00060DMs", -- Multiply and multiply-accumulate. mul_3 = "e0000090NMSs", mla_4 = "e0200090NMSDs", umaal_4 = "e0400090DNMSs", -- v6 mls_4 = "e0600090DNMSs", -- v6T2 umull_4 = "e0800090DNMSs", umlal_4 = "e0a00090DNMSs", smull_4 = "e0c00090DNMSs", smlal_4 = "e0e00090DNMSs", -- Halfword multiply and multiply-accumulate. smlabb_4 = "e1000080NMSD", -- v5TE smlatb_4 = "e10000a0NMSD", -- v5TE smlabt_4 = "e10000c0NMSD", -- v5TE smlatt_4 = "e10000e0NMSD", -- v5TE smlawb_4 = "e1200080NMSD", -- v5TE smulwb_3 = "e12000a0NMS", -- v5TE smlawt_4 = "e12000c0NMSD", -- v5TE smulwt_3 = "e12000e0NMS", -- v5TE smlalbb_4 = "e1400080NMSD", -- v5TE smlaltb_4 = "e14000a0NMSD", -- v5TE smlalbt_4 = "e14000c0NMSD", -- v5TE smlaltt_4 = "e14000e0NMSD", -- v5TE smulbb_3 = "e1600080NMS", -- v5TE smultb_3 = "e16000a0NMS", -- v5TE smulbt_3 = "e16000c0NMS", -- v5TE smultt_3 = "e16000e0NMS", -- v5TE -- Miscellaneous data processing instructions. clz_2 = "e16f0f10DM", -- v5T rev_2 = "e6bf0f30DM", -- v6 rev16_2 = "e6bf0fb0DM", -- v6 revsh_2 = "e6ff0fb0DM", -- v6 sel_3 = "e6800fb0DNM", -- v6 usad8_3 = "e780f010NMS", -- v6 usada8_4 = "e7800010NMSD", -- v6 rbit_2 = "e6ff0f30DM", -- v6T2 movw_2 = "e3000000DW", -- v6T2 movt_2 = "e3400000DW", -- v6T2 -- Note: the X encodes width-1, not width. sbfx_4 = "e7a00050DMvX", -- v6T2 ubfx_4 = "e7e00050DMvX", -- v6T2 -- Note: the X encodes the msb field, not the width. bfc_3 = "e7c0001fDvX", -- v6T2 bfi_4 = "e7c00010DMvX", -- v6T2 -- Packing and unpacking instructions. pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6 pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6 sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6 sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6 sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6 sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6 sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6 sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6 uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6 uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6 uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6 uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6 uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6 uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6 -- Saturating instructions. qadd_3 = "e1000050DMN", -- v5TE qsub_3 = "e1200050DMN", -- v5TE qdadd_3 = "e1400050DMN", -- v5TE qdsub_3 = "e1600050DMN", -- v5TE -- Note: the X for ssat* encodes sat_imm-1, not sat_imm. ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6 usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6 ssat16_3 = "e6a00f30DXM", -- v6 usat16_3 = "e6e00f30DXM", -- v6 -- Parallel addition and subtraction. sadd16_3 = "e6100f10DNM", -- v6 sasx_3 = "e6100f30DNM", -- v6 ssax_3 = "e6100f50DNM", -- v6 ssub16_3 = "e6100f70DNM", -- v6 sadd8_3 = "e6100f90DNM", -- v6 ssub8_3 = "e6100ff0DNM", -- v6 qadd16_3 = "e6200f10DNM", -- v6 qasx_3 = "e6200f30DNM", -- v6 qsax_3 = "e6200f50DNM", -- v6 qsub16_3 = "e6200f70DNM", -- v6 qadd8_3 = "e6200f90DNM", -- v6 qsub8_3 = "e6200ff0DNM", -- v6 shadd16_3 = "e6300f10DNM", -- v6 shasx_3 = "e6300f30DNM", -- v6 shsax_3 = "e6300f50DNM", -- v6 shsub16_3 = "e6300f70DNM", -- v6 shadd8_3 = "e6300f90DNM", -- v6 shsub8_3 = "e6300ff0DNM", -- v6 uadd16_3 = "e6500f10DNM", -- v6 uasx_3 = "e6500f30DNM", -- v6 usax_3 = "e6500f50DNM", -- v6 usub16_3 = "e6500f70DNM", -- v6 uadd8_3 = "e6500f90DNM", -- v6 usub8_3 = "e6500ff0DNM", -- v6 uqadd16_3 = "e6600f10DNM", -- v6 uqasx_3 = "e6600f30DNM", -- v6 uqsax_3 = "e6600f50DNM", -- v6 uqsub16_3 = "e6600f70DNM", -- v6 uqadd8_3 = "e6600f90DNM", -- v6 uqsub8_3 = "e6600ff0DNM", -- v6 uhadd16_3 = "e6700f10DNM", -- v6 uhasx_3 = "e6700f30DNM", -- v6 uhsax_3 = "e6700f50DNM", -- v6 uhsub16_3 = "e6700f70DNM", -- v6 uhadd8_3 = "e6700f90DNM", -- v6 uhsub8_3 = "e6700ff0DNM", -- v6 -- Load/store instructions. str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL", strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL", ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL", ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL", strh_2 = "e00000b0DL", strh_3 = "e00000b0DL", ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL", ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL", strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL", ldm_2 = "e8900000oR", ldmia_2 = "e8900000oR", ldmfd_2 = "e8900000oR", ldmda_2 = "e8100000oR", ldmfa_2 = "e8100000oR", ldmdb_2 = "e9100000oR", ldmea_2 = "e9100000oR", ldmib_2 = "e9900000oR", ldmed_2 = "e9900000oR", stm_2 = "e8800000oR", stmia_2 = "e8800000oR", stmfd_2 = "e8800000oR", stmda_2 = "e8000000oR", stmfa_2 = "e8000000oR", stmdb_2 = "e9000000oR", stmea_2 = "e9000000oR", stmib_2 = "e9800000oR", stmed_2 = "e9800000oR", pop_1 = "e8bd0000R", push_1 = "e92d0000R", -- Branch instructions. b_1 = "ea000000B", bl_1 = "eb000000B", blx_1 = "e12fff30C", bx_1 = "e12fff10M", -- Miscellaneous instructions. nop_0 = "e1a00000", mrs_1 = "e10f0000D", bkpt_1 = "e1200070K", -- v5T svc_1 = "ef000000T", swi_1 = "ef000000T", ud_0 = "e7f001f0", -- VFP instructions. ["vadd.f32_3"] = "ee300a00dnm", ["vadd.f64_3"] = "ee300b00Gdnm", ["vsub.f32_3"] = "ee300a40dnm", ["vsub.f64_3"] = "ee300b40Gdnm", ["vmul.f32_3"] = "ee200a00dnm", ["vmul.f64_3"] = "ee200b00Gdnm", ["vnmul.f32_3"] = "ee200a40dnm", ["vnmul.f64_3"] = "ee200b40Gdnm", ["vmla.f32_3"] = "ee000a00dnm", ["vmla.f64_3"] = "ee000b00Gdnm", ["vmls.f32_3"] = "ee000a40dnm", ["vmls.f64_3"] = "ee000b40Gdnm", ["vnmla.f32_3"] = "ee100a40dnm", ["vnmla.f64_3"] = "ee100b40Gdnm", ["vnmls.f32_3"] = "ee100a00dnm", ["vnmls.f64_3"] = "ee100b00Gdnm", ["vdiv.f32_3"] = "ee800a00dnm", ["vdiv.f64_3"] = "ee800b00Gdnm", ["vabs.f32_2"] = "eeb00ac0dm", ["vabs.f64_2"] = "eeb00bc0Gdm", ["vneg.f32_2"] = "eeb10a40dm", ["vneg.f64_2"] = "eeb10b40Gdm", ["vsqrt.f32_2"] = "eeb10ac0dm", ["vsqrt.f64_2"] = "eeb10bc0Gdm", ["vcmp.f32_2"] = "eeb40a40dm", ["vcmp.f64_2"] = "eeb40b40Gdm", ["vcmpe.f32_2"] = "eeb40ac0dm", ["vcmpe.f64_2"] = "eeb40bc0Gdm", ["vcmpz.f32_1"] = "eeb50a40d", ["vcmpz.f64_1"] = "eeb50b40Gd", ["vcmpze.f32_1"] = "eeb50ac0d", ["vcmpze.f64_1"] = "eeb50bc0Gd", vldr_2 = "ed100a00dl|ed100b00Gdl", vstr_2 = "ed000a00dl|ed000b00Gdl", vldm_2 = "ec900a00or", vldmia_2 = "ec900a00or", vldmdb_2 = "ed100a00or", vpop_1 = "ecbd0a00r", vstm_2 = "ec800a00or", vstmia_2 = "ec800a00or", vstmdb_2 = "ed000a00or", vpush_1 = "ed2d0a00r", ["vmov.f32_2"] = "eeb00a40dm|eeb00a00dY", -- #imm is VFPv3 only ["vmov.f64_2"] = "eeb00b40Gdm|eeb00b00GdY", -- #imm is VFPv3 only vmov_2 = "ee100a10Dn|ee000a10nD", vmov_3 = "ec500a10DNm|ec400a10mDN|ec500b10GDNm|ec400b10GmDN", vmrs_0 = "eef1fa10", vmrs_1 = "eef10a10D", vmsr_1 = "eee10a10D", ["vcvt.s32.f32_2"] = "eebd0ac0dm", ["vcvt.s32.f64_2"] = "eebd0bc0dGm", ["vcvt.u32.f32_2"] = "eebc0ac0dm", ["vcvt.u32.f64_2"] = "eebc0bc0dGm", ["vcvtr.s32.f32_2"] = "eebd0a40dm", ["vcvtr.s32.f64_2"] = "eebd0b40dGm", ["vcvtr.u32.f32_2"] = "eebc0a40dm", ["vcvtr.u32.f64_2"] = "eebc0b40dGm", ["vcvt.f32.s32_2"] = "eeb80ac0dm", ["vcvt.f64.s32_2"] = "eeb80bc0GdFm", ["vcvt.f32.u32_2"] = "eeb80a40dm", ["vcvt.f64.u32_2"] = "eeb80b40GdFm", ["vcvt.f32.f64_2"] = "eeb70bc0dGm", ["vcvt.f64.f32_2"] = "eeb70ac0GdFm", -- VFPv4 only: ["vfma.f32_3"] = "eea00a00dnm", ["vfma.f64_3"] = "eea00b00Gdnm", ["vfms.f32_3"] = "eea00a40dnm", ["vfms.f64_3"] = "eea00b40Gdnm", ["vfnma.f32_3"] = "ee900a40dnm", ["vfnma.f64_3"] = "ee900b40Gdnm", ["vfnms.f32_3"] = "ee900a00dnm", ["vfnms.f64_3"] = "ee900b00Gdnm", -- NYI: Advanced SIMD instructions. -- NYI: I have no need for these instructions right now: -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb -- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2 } -- Add mnemonics for "s" variants. do local t = {} for k,v in pairs(map_op) do if sub(v, -1) == "s" then local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2) t[sub(k, 1, -3).."s"..sub(k, -2)] = v2 end end for k,v in pairs(t) do map_op[k] = v end end ------------------------------------------------------------------------------ local function parse_gpr(expr) local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$") local tp = map_type[tname or expr] if tp then local reg = ovreg or tp.reg if not reg then werror("type `"..(tname or expr).."' needs a register override") end expr = reg end local r = match(expr, "^r(1?[0-9])$") if r then r = tonumber(r) if r <= 15 then return r, tp end end werror("bad register name `"..expr.."'") end local function parse_gpr_pm(expr) local pm, expr2 = match(expr, "^([+-]?)(.*)$") return parse_gpr(expr2), (pm == "-") end local function parse_vr(expr, tp) local t, r = match(expr, "^([sd])([0-9]+)$") if t == tp then r = tonumber(r) if r <= 31 then if t == "s" then return shr(r, 1), band(r, 1) end return band(r, 15), shr(r, 4) end end werror("bad register name `"..expr.."'") end local function parse_reglist(reglist) reglist = match(reglist, "^{%s*([^}]*)}$") if not reglist then werror("register list expected") end local rr = 0 for p in gmatch(reglist..",", "%s*([^,]*),") do local rbit = shl(1, parse_gpr(gsub(p, "%s+$", ""))) if band(rr, rbit) ~= 0 then werror("duplicate register `"..p.."'") end rr = rr + rbit end return rr end local function parse_vrlist(reglist) local ta, ra, tb, rb = match(reglist, "^{%s*([sd])([0-9]+)%s*%-%s*([sd])([0-9]+)%s*}$") ra, rb = tonumber(ra), tonumber(rb) if ta and ta == tb and ra and rb and ra <= 31 and rb <= 31 and ra <= rb then local nr = rb+1 - ra if ta == "s" then return shl(shr(ra,1),12)+shl(band(ra,1),22) + nr else return shl(band(ra,15),12)+shl(shr(ra,4),22) + nr*2 + 0x100 end end werror("register list expected") end local function parse_imm(imm, bits, shift, scale, signed) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = tonumber(imm) if n then local m = sar(n, scale) if shl(m, scale) == n then if signed then local s = sar(m, bits-1) if s == 0 then return shl(m, shift) elseif s == -1 then return shl(m + shl(1, bits), shift) end else if sar(m, bits) == 0 then return shl(m, shift) end end end werror("out of range immediate `"..imm.."'") else waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) return 0 end end local function parse_imm12(imm) local n = tonumber(imm) if n then local m = band(n) for i=0,-15,-1 do if shr(m, 8) == 0 then return m + shl(band(i, 15), 8) end m = ror(m, 2) end werror("out of range immediate `"..imm.."'") else waction("IMM12", 0, imm) return 0 end end local function parse_imm16(imm) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = tonumber(imm) if n then if shr(n, 16) == 0 then return band(n, 0x0fff) + shl(band(n, 0xf000), 4) end werror("out of range immediate `"..imm.."'") else waction("IMM16", 32*16, imm) return 0 end end local function parse_imm_load(imm, ext) local n = tonumber(imm) if n then if ext then if n >= -255 and n <= 255 then local up = 0x00800000 if n < 0 then n = -n; up = 0 end return shl(band(n, 0xf0), 4) + band(n, 0x0f) + up end else if n >= -4095 and n <= 4095 then if n >= 0 then return n+0x00800000 end return -n end end werror("out of range immediate `"..imm.."'") else waction(ext and "IMML8" or "IMML12", 32768 + shl(ext and 8 or 12, 5), imm) return 0 end end local function parse_shift(shift, gprok) if shift == "rrx" then return 3 * 32 else local s, s2 = match(shift, "^(%S+)%s*(.*)$") s = map_shift[s] if not s then werror("expected shift operand") end if sub(s2, 1, 1) == "#" then return parse_imm(s2, 5, 7, 0, false) + shl(s, 5) else if not gprok then werror("expected immediate shift operand") end return shl(parse_gpr(s2), 8) + shl(s, 5) + 16 end end end local function parse_label(label, def) local prefix = sub(label, 1, 2) -- =>label (pc label reference) if prefix == "=>" then return "PC", 0, sub(label, 3) end -- ->name (global label reference) if prefix == "->" then return "LG", map_global[sub(label, 3)] end if def then -- [1-9] (local label definition) if match(label, "^[1-9]$") then return "LG", 10+tonumber(label) end else -- [<>][1-9] (local label reference) local dir, lnum = match(label, "^([<>])([1-9])$") if dir then -- Fwd: 1-9, Bkwd: 11-19. return "LG", lnum + (dir == ">" and 0 or 10) end -- extern label (extern label reference) local extname = match(label, "^extern%s+(%S+)$") if extname then return "EXT", map_extern[extname] end end werror("bad label `"..label.."'") end local function parse_load(params, nparams, n, op) local oplo = band(op, 255) local ext, ldrd = (oplo ~= 0), (oplo == 208) local d if (ldrd or oplo == 240) then d = band(shr(op, 12), 15) if band(d, 1) ~= 0 then werror("odd destination register") end end local pn = params[n] local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") local p2 = params[n+1] if not p1 then if not p2 then if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then local mode, n, s = parse_label(pn, false) waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1) return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0) end local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then local d, tp = parse_gpr(reg) if tp then waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), format(tp.ctypefmt, tailr)) return op + shl(d, 16) + 0x01000000 + (ext and 0x00400000 or 0) end end end werror("expected address operand") end if wb == "!" then op = op + 0x00200000 end if p2 then if wb == "!" then werror("bad use of '!'") end local p3 = params[n+2] op = op + shl(parse_gpr(p1), 16) local imm = match(p2, "^#(.*)$") if imm then local m = parse_imm_load(imm, ext) if p3 then werror("too many parameters") end op = op + m + (ext and 0x00400000 or 0) else local m, neg = parse_gpr_pm(p2) if ldrd and (m == d or m-1 == d) then werror("register conflict") end op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) if p3 then op = op + parse_shift(p3) end end else local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$") op = op + shl(parse_gpr(p1a), 16) + 0x01000000 if p2 ~= "" then local imm = match(p2, "^,%s*#(.*)$") if imm then local m = parse_imm_load(imm, ext) op = op + m + (ext and 0x00400000 or 0) else local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$") local m, neg = parse_gpr_pm(p2a) if ldrd and (m == d or m-1 == d) then werror("register conflict") end op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) if p3 ~= "" then if ext then werror("too many parameters") end op = op + parse_shift(p3) end end else if wb == "!" then werror("bad use of '!'") end op = op + (ext and 0x00c00000 or 0x00800000) end end return op end local function parse_vload(q) local reg, imm = match(q, "^%[%s*([^,%s]*)%s*(.*)%]$") if reg then local d = shl(parse_gpr(reg), 16) if imm == "" then return d end imm = match(imm, "^,%s*#(.*)$") if imm then local n = tonumber(imm) if n then if n >= -1020 and n <= 1020 and n%4 == 0 then return d + (n >= 0 and n/4+0x00800000 or -n/4) end werror("out of range immediate `"..imm.."'") else waction("IMMV8", 32768 + 32*8, imm) return d end end else if match(q, "^[<>=%-]") or match(q, "^extern%s+") then local mode, n, s = parse_label(q, false) waction("REL_"..mode, n + 0x2800, s, 1) return 15 * 65536 end local reg, tailr = match(q, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then local d, tp = parse_gpr(reg) if tp then waction("IMMV8", 32768 + 32*8, format(tp.ctypefmt, tailr)) return shl(d, 16) end end end werror("expected address operand") end ------------------------------------------------------------------------------ -- Handle opcodes defined with template strings. local function parse_template(params, template, nparams, pos) local op = tonumber(sub(template, 1, 8), 16) local n = 1 local vr = "s" -- Process each character. for p in gmatch(sub(template, 9), ".") do local q = params[n] if p == "D" then op = op + shl(parse_gpr(q), 12); n = n + 1 elseif p == "N" then op = op + shl(parse_gpr(q), 16); n = n + 1 elseif p == "S" then op = op + shl(parse_gpr(q), 8); n = n + 1 elseif p == "M" then op = op + parse_gpr(q); n = n + 1 elseif p == "d" then local r,h = parse_vr(q, vr); op = op+shl(r,12)+shl(h,22); n = n + 1 elseif p == "n" then local r,h = parse_vr(q, vr); op = op+shl(r,16)+shl(h,7); n = n + 1 elseif p == "m" then local r,h = parse_vr(q, vr); op = op+r+shl(h,5); n = n + 1 elseif p == "P" then local imm = match(q, "^#(.*)$") if imm then op = op + parse_imm12(imm) + 0x02000000 else op = op + parse_gpr(q) end n = n + 1 elseif p == "p" then op = op + parse_shift(q, true); n = n + 1 elseif p == "L" then op = parse_load(params, nparams, n, op) elseif p == "l" then op = op + parse_vload(q) elseif p == "B" then local mode, n, s = parse_label(q, false) waction("REL_"..mode, n, s, 1) elseif p == "C" then -- blx gpr vs. blx label. if match(q, "^([%w_]+):(r1?[0-9])$") or match(q, "^r(1?[0-9])$") then op = op + parse_gpr(q) else if op < 0xe0000000 then werror("unconditional instruction") end local mode, n, s = parse_label(q, false) waction("REL_"..mode, n, s, 1) op = 0xfa000000 end elseif p == "F" then vr = "s" elseif p == "G" then vr = "d" elseif p == "o" then local r, wb = match(q, "^([^!]*)(!?)$") op = op + shl(parse_gpr(r), 16) + (wb == "!" and 0x00200000 or 0) n = n + 1 elseif p == "R" then op = op + parse_reglist(q); n = n + 1 elseif p == "r" then op = op + parse_vrlist(q); n = n + 1 elseif p == "W" then op = op + parse_imm16(q); n = n + 1 elseif p == "v" then op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 elseif p == "w" then local imm = match(q, "^#(.*)$") if imm then op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 else op = op + shl(parse_gpr(q), 8) + 16 end elseif p == "X" then op = op + parse_imm(q, 5, 16, 0, false); n = n + 1 elseif p == "Y" then local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 if not imm or shr(imm, 8) ~= 0 then werror("bad immediate operand") end op = op + shl(band(imm, 0xf0), 12) + band(imm, 0x0f) elseif p == "K" then local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 if not imm or shr(imm, 16) ~= 0 then werror("bad immediate operand") end op = op + shl(band(imm, 0xfff0), 4) + band(imm, 0x000f) elseif p == "T" then op = op + parse_imm(q, 24, 0, 0, false); n = n + 1 elseif p == "s" then -- Ignored. else assert(false) end end wputpos(pos, op) end map_op[".template__"] = function(params, template, nparams) if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end -- Limit number of section buffer positions used by a single dasm_put(). -- A single opcode needs a maximum of 3 positions. if secpos+3 > maxsecpos then wflush() end local pos = wpos() local lpos, apos, spos = #actlist, #actargs, secpos local ok, err for t in gmatch(template, "[^|]+") do ok, err = pcall(parse_template, params, t, nparams, pos) if ok then return end secpos = spos actlist[lpos+1] = nil actlist[lpos+2] = nil actlist[lpos+3] = nil actargs[apos+1] = nil actargs[apos+2] = nil actargs[apos+3] = nil end error(err, 0) end ------------------------------------------------------------------------------ -- Pseudo-opcode to mark the position where the action list is to be emitted. map_op[".actionlist_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeactions(out, name) end) end -- Pseudo-opcode to mark the position where the global enum is to be emitted. map_op[".globals_1"] = function(params) if not params then return "prefix" end local prefix = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobals(out, prefix) end) end -- Pseudo-opcode to mark the position where the global names are to be emitted. map_op[".globalnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobalnames(out, name) end) end -- Pseudo-opcode to mark the position where the extern names are to be emitted. map_op[".externnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeexternnames(out, name) end) end ------------------------------------------------------------------------------ -- Label pseudo-opcode (converted from trailing colon form). map_op[".label_1"] = function(params) if not params then return "[1-9] | ->global | =>pcexpr" end if secpos+1 > maxsecpos then wflush() end local mode, n, s = parse_label(params[1], true) if mode == "EXT" then werror("bad label definition") end waction("LABEL_"..mode, n, s, 1) end ------------------------------------------------------------------------------ -- Pseudo-opcodes for data storage. map_op[".long_*"] = function(params) if not params then return "imm..." end for _,p in ipairs(params) do local n = tonumber(p) if not n then werror("bad immediate `"..p.."'") end if n < 0 then n = n + 2^32 end wputw(n) if secpos+2 > maxsecpos then wflush() end end end -- Alignment pseudo-opcode. map_op[".align_1"] = function(params) if not params then return "numpow2" end if secpos+1 > maxsecpos then wflush() end local align = tonumber(params[1]) if align then local x = align -- Must be a power of 2 in the range (2 ... 256). for i=1,8 do x = x / 2 if x == 1 then waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. return end end end werror("bad alignment") end ------------------------------------------------------------------------------ -- Pseudo-opcode for (primitive) type definitions (map to C types). map_op[".type_3"] = function(params, nparams) if not params then return nparams == 2 and "name, ctype" or "name, ctype, reg" end local name, ctype, reg = params[1], params[2], params[3] if not match(name, "^[%a_][%w_]*$") then werror("bad type name `"..name.."'") end local tp = map_type[name] if tp then werror("duplicate type `"..name.."'") end -- Add #type to defines. A bit unclean to put it in map_archdef. map_archdef["#"..name] = "sizeof("..ctype..")" -- Add new type and emit shortcut define. local num = ctypenum + 1 map_type[name] = { ctype = ctype, ctypefmt = format("Dt%X(%%s)", num), reg = reg, } wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) ctypenum = num end map_op[".type_2"] = map_op[".type_3"] -- Dump type definitions. local function dumptypes(out, lvl) local t = {} for name in pairs(map_type) do t[#t+1] = name end sort(t) out:write("Type definitions:\n") for _,name in ipairs(t) do local tp = map_type[name] local reg = tp.reg or "" out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) end out:write("\n") end ------------------------------------------------------------------------------ -- Set the current section. function _M.section(num) waction("SECTION", num) wflush(true) -- SECTION is a terminal action. end ------------------------------------------------------------------------------ -- Dump architecture description. function _M.dumparch(out) out:write(format("DynASM %s version %s, released %s\n\n", _info.arch, _info.version, _info.release)) dumpactions(out) end -- Dump all user defined elements. function _M.dumpdef(out, lvl) dumptypes(out, lvl) dumpglobals(out, lvl) dumpexterns(out, lvl) end ------------------------------------------------------------------------------ -- Pass callbacks from/to the DynASM core. function _M.passcb(wl, we, wf, ww) wline, werror, wfatal, wwarn = wl, we, wf, ww return wflush end -- Setup the arch-specific module. function _M.setup(arch, opt) g_arch, g_opt = arch, opt end -- Merge the core maps and the arch-specific maps. function _M.mergemaps(map_coreop, map_def) setmetatable(map_op, { __index = function(t, k) local v = map_coreop[k] if v then return v end local k1, cc, k2 = match(k, "^(.-)(..)([._].*)$") local cv = map_cond[cc] if cv then local v = rawget(t, k1..k2) if type(v) == "string" then local scv = format("%x", cv) return gsub(scv..sub(v, 2), "|e", "|"..scv) end end end }) setmetatable(map_def, { __index = map_archdef }) return map_op, map_def end return _M ------------------------------------------------------------------------------ ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_arm64.h ================================================ /* ** DynASM ARM64 encoding engine. ** Copyright (C) 2005-2022 Mike Pall. All rights reserved. ** Released under the MIT license. See dynasm.lua for full copyright notice. */ #include #include #include #include #define DASM_ARCH "arm64" #ifndef DASM_EXTERN #define DASM_EXTERN(a,b,c,d) 0 #endif /* Action definitions. */ enum { DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, /* The following actions need a buffer position. */ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, /* The following actions also have an argument. */ DASM_REL_PC, DASM_LABEL_PC, DASM_REL_A, DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML, DASM_IMMV, DASM_VREG, DASM__MAX }; /* Maximum number of section buffer positions for a single dasm_put() call. */ #define DASM_MAXSECPOS 25 /* DynASM encoder status codes. Action list offset or number are or'ed in. */ #define DASM_S_OK 0x00000000 #define DASM_S_NOMEM 0x01000000 #define DASM_S_PHASE 0x02000000 #define DASM_S_MATCH_SEC 0x03000000 #define DASM_S_RANGE_I 0x11000000 #define DASM_S_RANGE_SEC 0x12000000 #define DASM_S_RANGE_LG 0x13000000 #define DASM_S_RANGE_PC 0x14000000 #define DASM_S_RANGE_REL 0x15000000 #define DASM_S_RANGE_VREG 0x16000000 #define DASM_S_UNDEF_LG 0x21000000 #define DASM_S_UNDEF_PC 0x22000000 /* Macros to convert positions (8 bit section + 24 bit index). */ #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) #define DASM_POS2BIAS(pos) ((pos)&0xff000000) #define DASM_SEC2POS(sec) ((sec)<<24) #define DASM_POS2SEC(pos) ((pos)>>24) #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) /* Action list type. */ typedef const unsigned int *dasm_ActList; /* Per-section structure. */ typedef struct dasm_Section { int *rbuf; /* Biased buffer pointer (negative section bias). */ int *buf; /* True buffer pointer. */ size_t bsize; /* Buffer size in bytes. */ int pos; /* Biased buffer position. */ int epos; /* End of biased buffer position - max single put. */ int ofs; /* Byte offset into section. */ } dasm_Section; /* Core structure holding the DynASM encoding state. */ struct dasm_State { size_t psize; /* Allocated size of this structure. */ dasm_ActList actionlist; /* Current actionlist pointer. */ int *lglabels; /* Local/global chain/pos ptrs. */ size_t lgsize; int *pclabels; /* PC label chains/pos ptrs. */ size_t pcsize; void **globals; /* Array of globals (bias -10). */ dasm_Section *section; /* Pointer to active section. */ size_t codesize; /* Total size of all code sections. */ int maxsection; /* 0 <= sectionidx < maxsection. */ int status; /* Status code. */ dasm_Section sections[1]; /* All sections. Alloc-extended. */ }; /* The size of the core structure depends on the max. number of sections. */ #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) /* Initialize DynASM state. */ void dasm_init(Dst_DECL, int maxsection) { dasm_State *D; size_t psz = 0; int i; Dst_REF = NULL; DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); D = Dst_REF; D->psize = psz; D->lglabels = NULL; D->lgsize = 0; D->pclabels = NULL; D->pcsize = 0; D->globals = NULL; D->maxsection = maxsection; for (i = 0; i < maxsection; i++) { D->sections[i].buf = NULL; /* Need this for pass3. */ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); D->sections[i].bsize = 0; D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ } } /* Free DynASM state. */ void dasm_free(Dst_DECL) { dasm_State *D = Dst_REF; int i; for (i = 0; i < D->maxsection; i++) if (D->sections[i].buf) DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); DASM_M_FREE(Dst, D, D->psize); } /* Setup global label array. Must be called before dasm_setup(). */ void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) { dasm_State *D = Dst_REF; D->globals = gl - 10; /* Negative bias to compensate for locals. */ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); } /* Grow PC label array. Can be called after dasm_setup(), too. */ void dasm_growpc(Dst_DECL, unsigned int maxpc) { dasm_State *D = Dst_REF; size_t osz = D->pcsize; DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); } /* Setup encoder. */ void dasm_setup(Dst_DECL, const void *actionlist) { dasm_State *D = Dst_REF; int i; D->actionlist = (dasm_ActList)actionlist; D->status = DASM_S_OK; D->section = &D->sections[0]; memset((void *)D->lglabels, 0, D->lgsize); if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); for (i = 0; i < D->maxsection; i++) { D->sections[i].pos = DASM_SEC2POS(i); D->sections[i].ofs = 0; } } #ifdef DASM_CHECKS #define CK(x, st) \ do { if (!(x)) { \ D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0) #define CKPL(kind, st) \ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ D->status = DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0) #else #define CK(x, st) ((void)0) #define CKPL(kind, st) ((void)0) #endif static int dasm_imm12(unsigned int n) { if ((n >> 12) == 0) return n; else if ((n & 0xff000fff) == 0) return (n >> 12) | 0x1000; else return -1; } static int dasm_ffs(unsigned long long x) { int n = -1; while (x) { x >>= 1; n++; } return n; } static int dasm_imm13(int lo, int hi) { int inv = 0, w = 64, s = 0xfff, xa, xb; unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo; unsigned long long m = 1ULL, a, b, c; if (n & 1) { n = ~n; inv = 1; } a = n & (unsigned long long)-(long long)n; b = (n+a)&(unsigned long long)-(long long)(n+a); c = (n+a-b)&(unsigned long long)-(long long)(n+a-b); xa = dasm_ffs(a); xb = dasm_ffs(b); if (c) { w = dasm_ffs(c) - xa; if (w == 32) m = 0x0000000100000001UL; else if (w == 16) m = 0x0001000100010001UL; else if (w == 8) m = 0x0101010101010101UL; else if (w == 4) m = 0x1111111111111111UL; else if (w == 2) m = 0x5555555555555555UL; else return -1; s = (-2*w & 0x3f) - 1; } else if (!a) { return -1; } else if (xb == -1) { xb = 64; } if ((b-a) * m != n) return -1; if (inv) { return ((w - xb) << 6) | (s+w+xa-xb); } else { return ((w - xa) << 6) | (s+xb-xa); } return -1; } /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ void dasm_put(Dst_DECL, int start, ...) { va_list ap; dasm_State *D = Dst_REF; dasm_ActList p = D->actionlist + start; dasm_Section *sec = D->section; int pos = sec->pos, ofs = sec->ofs; int *b; if (pos >= sec->epos) { DASM_M_GROW(Dst, int, sec->buf, sec->bsize, sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); sec->rbuf = sec->buf - DASM_POS2BIAS(pos); sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); } b = sec->rbuf; b[pos++] = start; va_start(ap, start); while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16); if (action >= DASM__MAX) { ofs += 4; } else { int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; switch (action) { case DASM_STOP: goto stop; case DASM_SECTION: n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; goto stop; case DASM_ESC: p++; ofs += 4; break; case DASM_REL_EXT: if ((ins & 0x8000)) ofs += 8; break; case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; case DASM_REL_LG: n = (ins & 2047) - 10; pl = D->lglabels + n; /* Bkwd rel or global. */ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } pl += 10; n = *pl; if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ goto linkrel; case DASM_REL_PC: pl = D->pclabels + n; CKPL(pc, PC); putrel: n = *pl; if (n < 0) { /* Label exists. Get label pos and store it. */ b[pos] = -n; } else { linkrel: b[pos] = n; /* Else link to rel chain, anchored at label. */ *pl = pos; } pos++; if ((ins & 0x8000)) ofs += 8; break; case DASM_REL_A: b[pos++] = n; b[pos++] = va_arg(ap, int); break; case DASM_LABEL_LG: pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; case DASM_LABEL_PC: pl = D->pclabels + n; CKPL(pc, PC); putlabel: n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } *pl = -pos; /* Label exists now. */ b[pos++] = ofs; /* Store pass1 offset estimate. */ break; case DASM_IMM: CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); n >>= ((ins>>10)&31); #ifdef DASM_CHECKS if ((ins & 0x8000)) CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); else CK((n>>((ins>>5)&31)) == 0, RANGE_I); #endif b[pos++] = n; break; case DASM_IMM6: CK((n >> 6) == 0, RANGE_I); b[pos++] = n; break; case DASM_IMM12: CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); b[pos++] = n; break; case DASM_IMM13W: CK(dasm_imm13(n, n) != -1, RANGE_I); b[pos++] = n; break; case DASM_IMM13X: { int m = va_arg(ap, int); CK(dasm_imm13(n, m) != -1, RANGE_I); b[pos++] = n; b[pos++] = m; break; } case DASM_IMML: { #ifdef DASM_CHECKS int scale = (ins & 3); CK((!(n & ((1<>scale) < 4096) || (unsigned int)(n+256) < 512, RANGE_I); #endif b[pos++] = n; break; } case DASM_IMMV: ofs += 4; b[pos++] = n; break; case DASM_VREG: CK(n < 32, RANGE_VREG); b[pos++] = n; break; } } } stop: va_end(ap); sec->pos = pos; sec->ofs = ofs; } #undef CK /* Pass 2: Link sections, shrink aligns, fix label offsets. */ int dasm_link(Dst_DECL, size_t *szp) { dasm_State *D = Dst_REF; int secnum; int ofs = 0; #ifdef DASM_CHECKS *szp = 0; if (D->status != DASM_S_OK) return D->status; { int pc; for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; } #endif { /* Handle globals not defined in this translation unit. */ int idx; for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { int n = D->lglabels[idx]; /* Undefined label: Collapse rel chain and replace with marker (< 0). */ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } } } /* Combine all code sections. No support for data sections (yet). */ for (secnum = 0; secnum < D->maxsection; secnum++) { dasm_Section *sec = D->sections + secnum; int *b = sec->rbuf; int pos = DASM_SEC2POS(secnum); int lastpos = sec->pos; while (pos != lastpos) { dasm_ActList p = D->actionlist + b[pos++]; while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16); switch (action) { case DASM_STOP: case DASM_SECTION: goto stop; case DASM_ESC: p++; break; case DASM_REL_EXT: break; case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; case DASM_REL_LG: case DASM_REL_PC: pos++; break; case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; case DASM_IMM: case DASM_IMM6: case DASM_IMM12: case DASM_IMM13W: case DASM_IMML: case DASM_IMMV: case DASM_VREG: pos++; break; case DASM_IMM13X: case DASM_REL_A: pos += 2; break; } } stop: (void)0; } ofs += sec->ofs; /* Next section starts right after current section. */ } D->codesize = ofs; /* Total size of all code sections */ *szp = ofs; return DASM_S_OK; } #ifdef DASM_CHECKS #define CK(x, st) \ do { if (!(x)) return DASM_S_##st|(int)(p-D->actionlist-1); } while (0) #else #define CK(x, st) ((void)0) #endif /* Pass 3: Encode sections. */ int dasm_encode(Dst_DECL, void *buffer) { dasm_State *D = Dst_REF; char *base = (char *)buffer; unsigned int *cp = (unsigned int *)buffer; int secnum; /* Encode all code sections. No support for data sections (yet). */ for (secnum = 0; secnum < D->maxsection; secnum++) { dasm_Section *sec = D->sections + secnum; int *b = sec->buf; int *endb = sec->rbuf + sec->pos; while (b != endb) { dasm_ActList p = D->actionlist + *b++; while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16); int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; switch (action) { case DASM_STOP: case DASM_SECTION: goto stop; case DASM_ESC: *cp++ = *p++; break; case DASM_REL_EXT: n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); goto patchrel; case DASM_ALIGN: ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xd503201f; break; case DASM_REL_LG: if (n < 0) { ptrdiff_t na = (ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp + 4; n = (int)na; CK((ptrdiff_t)n == na, RANGE_REL); goto patchrel; } /* fallthrough */ case DASM_REL_PC: CK(n >= 0, UNDEF_PC); n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) + 4; patchrel: if (!(ins & 0xf800)) { /* B, BL */ CK((n & 3) == 0 && ((n+0x08000000) >> 28) == 0, RANGE_REL); cp[-1] |= ((n >> 2) & 0x03ffffff); } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */ CK((n & 3) == 0 && ((n+0x00100000) >> 21) == 0, RANGE_REL); cp[-1] |= ((n << 3) & 0x00ffffe0); } else if ((ins & 0x3000) == 0x2000) { /* ADR */ CK(((n+0x00100000) >> 21) == 0, RANGE_REL); cp[-1] |= ((n << 3) & 0x00ffffe0) | ((n & 3) << 29); } else if ((ins & 0x3000) == 0x3000) { /* ADRP */ cp[-1] |= ((n >> 9) & 0x00ffffe0) | (((n >> 12) & 3) << 29); } else if ((ins & 0x1000)) { /* TBZ, TBNZ */ CK((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, RANGE_REL); cp[-1] |= ((n << 3) & 0x0007ffe0); } else if ((ins & 0x8000)) { /* absolute */ cp[0] = (unsigned int)((ptrdiff_t)cp - 4 + n); cp[1] = (unsigned int)(((ptrdiff_t)cp - 4 + n) >> 32); cp += 2; } break; case DASM_REL_A: { ptrdiff_t na = (((ptrdiff_t)(*b++) << 32) | (unsigned int)n); if ((ins & 0x3000) == 0x3000) { /* ADRP */ ins &= ~0x1000; na = (na >> 12) - (((ptrdiff_t)cp - 4) >> 12); } else { na = na - (ptrdiff_t)cp + 4; } n = (int)na; CK((ptrdiff_t)n == na, RANGE_REL); goto patchrel; } case DASM_LABEL_LG: ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); break; case DASM_LABEL_PC: break; case DASM_IMM: cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); break; case DASM_IMM6: cp[-1] |= ((n&31) << 19) | ((n&32) << 26); break; case DASM_IMM12: cp[-1] |= (dasm_imm12((unsigned int)n) << 10); break; case DASM_IMM13W: cp[-1] |= (dasm_imm13(n, n) << 10); break; case DASM_IMM13X: cp[-1] |= (dasm_imm13(n, *b++) << 10); break; case DASM_IMML: { int scale = (ins & 3); cp[-1] |= (!(n & ((1<>scale) < 4096) ? ((n << (10-scale)) | 0x01000000) : ((n & 511) << 12); break; } case DASM_IMMV: *cp++ = n; break; case DASM_VREG: cp[-1] |= (n & 0x1f) << (ins & 0x1f); break; default: *cp++ = ins; break; } } stop: (void)0; } } if (base + D->codesize != (char *)cp) /* Check for phase errors. */ return DASM_S_PHASE; return DASM_S_OK; } #undef CK /* Get PC label offset. */ int dasm_getpclabel(Dst_DECL, unsigned int pc) { dasm_State *D = Dst_REF; if (pc*sizeof(int) < D->pcsize) { int pos = D->pclabels[pc]; if (pos < 0) return *DASM_POS2PTR(D, -pos); if (pos > 0) return -1; /* Undefined. */ } return -2; /* Unused or out of range. */ } #ifdef DASM_CHECKS /* Optional sanity checker to call between isolated encoding steps. */ int dasm_checkstep(Dst_DECL, int secmatch) { dasm_State *D = Dst_REF; if (D->status == DASM_S_OK) { int i; for (i = 1; i <= 9; i++) { if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } D->lglabels[i] = 0; } } if (D->status == DASM_S_OK && secmatch >= 0 && D->section != &D->sections[secmatch]) D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections); return D->status; } #endif ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_arm64.lua ================================================ ------------------------------------------------------------------------------ -- DynASM ARM64 module. -- -- Copyright (C) 2005-2022 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------ -- Module information: local _info = { arch = "arm", description = "DynASM ARM64 module", version = "1.5.0", vernum = 10500, release = "2021-05-02", author = "Mike Pall", license = "MIT", } -- Exported glue functions for the arch-specific module. local _M = { _info = _info } -- Cache library functions. local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs local assert, setmetatable, rawget = assert, setmetatable, rawget local _s = string local format, byte, char = _s.format, _s.byte, _s.char local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub local concat, sort, insert = table.concat, table.sort, table.insert local bit = bit or require("bit") local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift local ror, tohex, tobit = bit.ror, bit.tohex, bit.tobit -- Inherited tables and callbacks. local g_opt, g_arch local wline, werror, wfatal, wwarn -- Action name list. -- CHECK: Keep this in sync with the C code! local action_names = { "STOP", "SECTION", "ESC", "REL_EXT", "ALIGN", "REL_LG", "LABEL_LG", "REL_PC", "LABEL_PC", "REL_A", "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML", "IMMV", "VREG", } -- Maximum number of section buffer positions for dasm_put(). -- CHECK: Keep this in sync with the C code! local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. -- Action name -> action number. local map_action = {} for n,name in ipairs(action_names) do map_action[name] = n-1 end -- Action list buffer. local actlist = {} -- Argument list for next dasm_put(). Start with offset 0 into action list. local actargs = { 0 } -- Current number of section buffer positions for dasm_put(). local secpos = 1 ------------------------------------------------------------------------------ -- Dump action names and numbers. local function dumpactions(out) out:write("DynASM encoding engine action codes:\n") for n,name in ipairs(action_names) do local num = map_action[name] out:write(format(" %-10s %02X %d\n", name, num, num)) end out:write("\n") end -- Write action list buffer as a huge static C array. local function writeactions(out, name) local nn = #actlist if nn == 0 then nn = 1; actlist[0] = map_action.STOP end out:write("static const unsigned int ", name, "[", nn, "] = {\n") for i = 1,nn-1 do assert(out:write("0x", tohex(actlist[i]), ",\n")) end assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) end ------------------------------------------------------------------------------ -- Add word to action list. local function wputxw(n) assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") actlist[#actlist+1] = n end -- Add action to list with optional arg. Advance buffer pos, too. local function waction(action, val, a, num) local w = assert(map_action[action], "bad action name `"..action.."'") wputxw(w * 0x10000 + (val or 0)) if a then actargs[#actargs+1] = a end if a or num then secpos = secpos + (num or 1) end end -- Flush action list (intervening C code or buffer pos overflow). local function wflush(term) if #actlist == actargs[1] then return end -- Nothing to flush. if not term then waction("STOP") end -- Terminate action list. wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). secpos = 1 -- The actionlist offset occupies a buffer position, too. end -- Put escaped word. local function wputw(n) if n <= 0x000fffff then waction("ESC") end wputxw(n) end -- Reserve position for word. local function wpos() local pos = #actlist+1 actlist[pos] = "" return pos end -- Store word to reserved position. local function wputpos(pos, n) assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") if n <= 0x000fffff then insert(actlist, pos+1, n) n = map_action.ESC * 0x10000 end actlist[pos] = n end ------------------------------------------------------------------------------ -- Global label name -> global label number. With auto assignment on 1st use. local next_global = 20 local map_global = setmetatable({}, { __index = function(t, name) if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end local n = next_global if n > 2047 then werror("too many global labels") end next_global = n + 1 t[name] = n return n end}) -- Dump global labels. local function dumpglobals(out, lvl) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("Global labels:\n") for i=20,next_global-1 do out:write(format(" %s\n", t[i])) end out:write("\n") end -- Write global label enum. local function writeglobals(out, prefix) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("enum {\n") for i=20,next_global-1 do out:write(" ", prefix, t[i], ",\n") end out:write(" ", prefix, "_MAX\n};\n") end -- Write global label names. local function writeglobalnames(out, name) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("static const char *const ", name, "[] = {\n") for i=20,next_global-1 do out:write(" \"", t[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Extern label name -> extern label number. With auto assignment on 1st use. local next_extern = 0 local map_extern_ = {} local map_extern = setmetatable({}, { __index = function(t, name) -- No restrictions on the name for now. local n = next_extern if n > 2047 then werror("too many extern labels") end next_extern = n + 1 t[name] = n map_extern_[n] = name return n end}) -- Dump extern labels. local function dumpexterns(out, lvl) out:write("Extern labels:\n") for i=0,next_extern-1 do out:write(format(" %s\n", map_extern_[i])) end out:write("\n") end -- Write extern label names. local function writeexternnames(out, name) out:write("static const char *const ", name, "[] = {\n") for i=0,next_extern-1 do out:write(" \"", map_extern_[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Arch-specific maps. -- Ext. register name -> int. name. local map_archdef = { xzr = "@x31", wzr = "@w31", lr = "x30", } -- Int. register name -> ext. name. local map_reg_rev = { ["@x31"] = "xzr", ["@w31"] = "wzr", x30 = "lr", } local map_type = {} -- Type name -> { ctype, reg } local ctypenum = 0 -- Type number (for Dt... macros). -- Reverse defines for registers. function _M.revdef(s) return map_reg_rev[s] or s end local map_shift = { lsl = 0, lsr = 1, asr = 2, } local map_extend = { uxtb = 0, uxth = 1, uxtw = 2, uxtx = 3, sxtb = 4, sxth = 5, sxtw = 6, sxtx = 7, } local map_cond = { eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7, hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14, hs = 2, lo = 3, } ------------------------------------------------------------------------------ local parse_reg_type local function parse_reg(expr, shift, no_vreg) if not expr then werror("expected register name") end local tname, ovreg = match(expr, "^([%w_]+):(@?%l%d+)$") if not tname then tname, ovreg = match(expr, "^([%w_]+):(R[xwqdshb]%b())$") end local tp = map_type[tname or expr] if tp then local reg = ovreg or tp.reg if not reg then werror("type `"..(tname or expr).."' needs a register override") end expr = reg end local ok31, rt, r = match(expr, "^(@?)([xwqdshb])([123]?[0-9])$") if r then r = tonumber(r) if r <= 30 or (r == 31 and ok31 ~= "" or (rt ~= "w" and rt ~= "x")) then if not parse_reg_type then parse_reg_type = rt elseif parse_reg_type ~= rt then werror("register size mismatch") end return shl(r, shift), tp end end local vrt, vreg = match(expr, "^R([xwqdshb])(%b())$") if vreg then if not parse_reg_type then parse_reg_type = vrt elseif parse_reg_type ~= vrt then werror("register size mismatch") end if not no_vreg then waction("VREG", shift, vreg) end return 0 end werror("bad register name `"..expr.."'") end local function parse_reg_base(expr) if expr == "sp" then return 0x3e0 end local base, tp = parse_reg(expr, 5) if parse_reg_type ~= "x" then werror("bad register type") end parse_reg_type = false return base, tp end local parse_ctx = {} local loadenv = setfenv and function(s) local code = loadstring(s, "") if code then setfenv(code, parse_ctx) end return code end or function(s) return load(s, "", nil, parse_ctx) end -- Try to parse simple arithmetic, too, since some basic ops are aliases. local function parse_number(n) local x = tonumber(n) if x then return x end local code = loadenv("return "..n) if code then local ok, y = pcall(code) if ok and type(y) == "number" then return y end end return nil end local function parse_imm(imm, bits, shift, scale, signed) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = parse_number(imm) if n then local m = sar(n, scale) if shl(m, scale) == n then if signed then local s = sar(m, bits-1) if s == 0 then return shl(m, shift) elseif s == -1 then return shl(m + shl(1, bits), shift) end else if sar(m, bits) == 0 then return shl(m, shift) end end end werror("out of range immediate `"..imm.."'") else waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) return 0 end end local function parse_imm12(imm) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = parse_number(imm) if n then if shr(n, 12) == 0 then return shl(n, 10) elseif band(n, 0xff000fff) == 0 then return shr(n, 2) + 0x00400000 end werror("out of range immediate `"..imm.."'") else waction("IMM12", 0, imm) return 0 end end local function parse_imm13(imm) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = parse_number(imm) local r64 = parse_reg_type == "x" if n and n % 1 == 0 and n >= 0 and n <= 0xffffffff then local inv = false if band(n, 1) == 1 then n = bit.bnot(n); inv = true end local t = {} for i=1,32 do t[i] = band(n, 1); n = shr(n, 1) end local b = table.concat(t) b = b..(r64 and (inv and "1" or "0"):rep(32) or b) local p0, p1, p0a, p1a = b:match("^(0+)(1+)(0*)(1*)") if p0 then local w = p1a == "" and (r64 and 64 or 32) or #p1+#p0a if band(w, w-1) == 0 and b == b:sub(1, w):rep(64/w) then local s = band(-2*w, 0x3f) - 1 if w == 64 then s = s + 0x1000 end if inv then return shl(w-#p1-#p0, 16) + shl(s+w-#p1, 10) else return shl(w-#p0, 16) + shl(s+#p1, 10) end end end werror("out of range immediate `"..imm.."'") elseif r64 then waction("IMM13X", 0, format("(unsigned int)(%s)", imm)) actargs[#actargs+1] = format("(unsigned int)((unsigned long long)(%s)>>32)", imm) return 0 else waction("IMM13W", 0, imm) return 0 end end local function parse_imm6(imm) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = parse_number(imm) if n then if n >= 0 and n <= 63 then return shl(band(n, 0x1f), 19) + (n >= 32 and 0x80000000 or 0) end werror("out of range immediate `"..imm.."'") else waction("IMM6", 0, imm) return 0 end end local function parse_imm_load(imm, scale) local n = parse_number(imm) if n then local m = sar(n, scale) if shl(m, scale) == n and m >= 0 and m < 0x1000 then return shl(m, 10) + 0x01000000 -- Scaled, unsigned 12 bit offset. elseif n >= -256 and n < 256 then return shl(band(n, 511), 12) -- Unscaled, signed 9 bit offset. end werror("out of range immediate `"..imm.."'") else waction("IMML", scale, imm) return 0 end end local function parse_fpimm(imm) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = parse_number(imm) if n then local m, e = math.frexp(n) local s, e2 = 0, band(e-2, 7) if m < 0 then m = -m; s = 0x00100000 end m = m*32-16 if m % 1 == 0 and m >= 0 and m <= 15 and sar(shl(e2, 29), 29)+2 == e then return s + shl(e2, 17) + shl(m, 13) end werror("out of range immediate `"..imm.."'") else werror("NYI fpimm action") end end local function parse_shift(expr) local s, s2 = match(expr, "^(%S+)%s*(.*)$") s = map_shift[s] if not s then werror("expected shift operand") end return parse_imm(s2, 6, 10, 0, false) + shl(s, 22) end local function parse_lslx16(expr) local n = match(expr, "^lsl%s*#(%d+)$") n = tonumber(n) if not n then werror("expected shift operand") end if band(n, parse_reg_type == "x" and 0xffffffcf or 0xffffffef) ~= 0 then werror("bad shift amount") end return shl(n, 17) end local function parse_extend(expr) local s, s2 = match(expr, "^(%S+)%s*(.*)$") if s == "lsl" then s = parse_reg_type == "x" and 3 or 2 else s = map_extend[s] end if not s then werror("expected extend operand") end return (s2 == "" and 0 or parse_imm(s2, 3, 10, 0, false)) + shl(s, 13) end local function parse_cond(expr, inv) local c = map_cond[expr] if not c then werror("expected condition operand") end return shl(bit.bxor(c, inv), 12) end local function parse_load(params, nparams, n, op) if params[n+2] then werror("too many operands") end local scale = shr(op, 30) local pn, p2 = params[n], params[n+1] local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") if not p1 then if not p2 then local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then local base, tp = parse_reg_base(reg) if tp then waction("IMML", scale, format(tp.ctypefmt, tailr)) return op + base end end end werror("expected address operand") end if p2 then if wb == "!" then werror("bad use of '!'") end op = op + parse_reg_base(p1) + parse_imm(p2, 9, 12, 0, true) + 0x400 elseif wb == "!" then local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$") if not p1a then werror("bad use of '!'") end op = op + parse_reg_base(p1a) + parse_imm(p2a, 9, 12, 0, true) + 0xc00 else local p1a, p2a = match(p1, "^([^,%s]*)%s*(.*)$") op = op + parse_reg_base(p1a) if p2a ~= "" then local imm = match(p2a, "^,%s*#(.*)$") if imm then op = op + parse_imm_load(imm, scale) else local p2b, p3b, p3s = match(p2a, "^,%s*([^,%s]*)%s*,?%s*(%S*)%s*(.*)$") op = op + parse_reg(p2b, 16) + 0x00200800 if parse_reg_type ~= "x" and parse_reg_type ~= "w" then werror("bad index register type") end if p3b == "" then if parse_reg_type ~= "x" then werror("bad index register type") end op = op + 0x6000 else if p3s == "" or p3s == "#0" then elseif p3s == "#"..scale then op = op + 0x1000 else werror("bad scale") end if parse_reg_type == "x" then if p3b == "lsl" and p3s ~= "" then op = op + 0x6000 elseif p3b == "sxtx" then op = op + 0xe000 else werror("bad extend/shift specifier") end else if p3b == "uxtw" then op = op + 0x4000 elseif p3b == "sxtw" then op = op + 0xc000 else werror("bad extend/shift specifier") end end end end else if wb == "!" then werror("bad use of '!'") end op = op + 0x01000000 end end return op end local function parse_load_pair(params, nparams, n, op) if params[n+2] then werror("too many operands") end local pn, p2 = params[n], params[n+1] local scale = shr(op, 30) == 0 and 2 or 3 local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") if not p1 then if not p2 then local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then local base, tp = parse_reg_base(reg) if tp then waction("IMM", 32768+7*32+15+scale*1024, format(tp.ctypefmt, tailr)) return op + base + 0x01000000 end end end werror("expected address operand") end if p2 then if wb == "!" then werror("bad use of '!'") end op = op + 0x00800000 else local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$") if p1a then p1, p2 = p1a, p2a else p2 = "#0" end op = op + (wb == "!" and 0x01800000 or 0x01000000) end return op + parse_reg_base(p1) + parse_imm(p2, 7, 15, scale, true) end local function parse_label(label, def) local prefix = label:sub(1, 2) -- =>label (pc label reference) if prefix == "=>" then return "PC", 0, label:sub(3) end -- ->name (global label reference) if prefix == "->" then return "LG", map_global[label:sub(3)] end if def then -- [1-9] (local label definition) if match(label, "^[1-9]$") then return "LG", 10+tonumber(label) end else -- [<>][1-9] (local label reference) local dir, lnum = match(label, "^([<>])([1-9])$") if dir then -- Fwd: 1-9, Bkwd: 11-19. return "LG", lnum + (dir == ">" and 0 or 10) end -- extern label (extern label reference) local extname = match(label, "^extern%s+(%S+)$") if extname then return "EXT", map_extern[extname] end -- &expr (pointer) if label:sub(1, 1) == "&" then return "A", 0, format("(ptrdiff_t)(%s)", label:sub(2)) end end end local function branch_type(op) if band(op, 0x7c000000) == 0x14000000 then return 0 -- B, BL elseif shr(op, 24) == 0x54 or band(op, 0x7e000000) == 0x34000000 or band(op, 0x3b000000) == 0x18000000 then return 0x800 -- B.cond, CBZ, CBNZ, LDR* literal elseif band(op, 0x7e000000) == 0x36000000 then return 0x1000 -- TBZ, TBNZ elseif band(op, 0x9f000000) == 0x10000000 then return 0x2000 -- ADR elseif band(op, 0x9f000000) == band(0x90000000) then return 0x3000 -- ADRP else assert(false, "unknown branch type") end end ------------------------------------------------------------------------------ local map_op, op_template local function op_alias(opname, f) return function(params, nparams) if not params then return "-> "..opname:sub(1, -3) end f(params, nparams) op_template(params, map_op[opname], nparams) end end local function alias_bfx(p) p[4] = "#("..p[3]:sub(2)..")+("..p[4]:sub(2)..")-1" end local function alias_bfiz(p) parse_reg(p[1], 0, true) if parse_reg_type == "w" then p[3] = "#(32-("..p[3]:sub(2).."))%32" p[4] = "#("..p[4]:sub(2)..")-1" else p[3] = "#(64-("..p[3]:sub(2).."))%64" p[4] = "#("..p[4]:sub(2)..")-1" end end local alias_lslimm = op_alias("ubfm_4", function(p) parse_reg(p[1], 0, true) local sh = p[3]:sub(2) if parse_reg_type == "w" then p[3] = "#(32-("..sh.."))%32" p[4] = "#31-("..sh..")" else p[3] = "#(64-("..sh.."))%64" p[4] = "#63-("..sh..")" end end) -- Template strings for ARM instructions. map_op = { -- Basic data processing instructions. add_3 = "0b000000DNMg|11000000pDpNIg|8b206000pDpNMx", add_4 = "0b000000DNMSg|0b200000DNMXg|8b200000pDpNMXx|8b200000pDpNxMwX", adds_3 = "2b000000DNMg|31000000DpNIg|ab206000DpNMx", adds_4 = "2b000000DNMSg|2b200000DNMXg|ab200000DpNMXx|ab200000DpNxMwX", cmn_2 = "2b00001fNMg|3100001fpNIg|ab20601fpNMx", cmn_3 = "2b00001fNMSg|2b20001fNMXg|ab20001fpNMXx|ab20001fpNxMwX", sub_3 = "4b000000DNMg|51000000pDpNIg|cb206000pDpNMx", sub_4 = "4b000000DNMSg|4b200000DNMXg|cb200000pDpNMXx|cb200000pDpNxMwX", subs_3 = "6b000000DNMg|71000000DpNIg|eb206000DpNMx", subs_4 = "6b000000DNMSg|6b200000DNMXg|eb200000DpNMXx|eb200000DpNxMwX", cmp_2 = "6b00001fNMg|7100001fpNIg|eb20601fpNMx", cmp_3 = "6b00001fNMSg|6b20001fNMXg|eb20001fpNMXx|eb20001fpNxMwX", neg_2 = "4b0003e0DMg", neg_3 = "4b0003e0DMSg", negs_2 = "6b0003e0DMg", negs_3 = "6b0003e0DMSg", adc_3 = "1a000000DNMg", adcs_3 = "3a000000DNMg", sbc_3 = "5a000000DNMg", sbcs_3 = "7a000000DNMg", ngc_2 = "5a0003e0DMg", ngcs_2 = "7a0003e0DMg", and_3 = "0a000000DNMg|12000000pDNig", and_4 = "0a000000DNMSg", orr_3 = "2a000000DNMg|32000000pDNig", orr_4 = "2a000000DNMSg", eor_3 = "4a000000DNMg|52000000pDNig", eor_4 = "4a000000DNMSg", ands_3 = "6a000000DNMg|72000000DNig", ands_4 = "6a000000DNMSg", tst_2 = "6a00001fNMg|7200001fNig", tst_3 = "6a00001fNMSg", bic_3 = "0a200000DNMg", bic_4 = "0a200000DNMSg", orn_3 = "2a200000DNMg", orn_4 = "2a200000DNMSg", eon_3 = "4a200000DNMg", eon_4 = "4a200000DNMSg", bics_3 = "6a200000DNMg", bics_4 = "6a200000DNMSg", movn_2 = "12800000DWg", movn_3 = "12800000DWRg", movz_2 = "52800000DWg", movz_3 = "52800000DWRg", movk_2 = "72800000DWg", movk_3 = "72800000DWRg", -- TODO: this doesn't cover all valid immediates for mov reg, #imm. mov_2 = "2a0003e0DMg|52800000DW|320003e0pDig|11000000pDpNg", mov_3 = "2a0003e0DMSg", mvn_2 = "2a2003e0DMg", mvn_3 = "2a2003e0DMSg", adr_2 = "10000000DBx", adrp_2 = "90000000DBx", csel_4 = "1a800000DNMCg", csinc_4 = "1a800400DNMCg", csinv_4 = "5a800000DNMCg", csneg_4 = "5a800400DNMCg", cset_2 = "1a9f07e0Dcg", csetm_2 = "5a9f03e0Dcg", cinc_3 = "1a800400DNmcg", cinv_3 = "5a800000DNmcg", cneg_3 = "5a800400DNmcg", ccmn_4 = "3a400000NMVCg|3a400800N5VCg", ccmp_4 = "7a400000NMVCg|7a400800N5VCg", madd_4 = "1b000000DNMAg", msub_4 = "1b008000DNMAg", mul_3 = "1b007c00DNMg", mneg_3 = "1b00fc00DNMg", smaddl_4 = "9b200000DxNMwAx", smsubl_4 = "9b208000DxNMwAx", smull_3 = "9b207c00DxNMw", smnegl_3 = "9b20fc00DxNMw", smulh_3 = "9b407c00DNMx", umaddl_4 = "9ba00000DxNMwAx", umsubl_4 = "9ba08000DxNMwAx", umull_3 = "9ba07c00DxNMw", umnegl_3 = "9ba0fc00DxNMw", umulh_3 = "9bc07c00DNMx", udiv_3 = "1ac00800DNMg", sdiv_3 = "1ac00c00DNMg", -- Bit operations. sbfm_4 = "13000000DN12w|93400000DN12x", bfm_4 = "33000000DN12w|b3400000DN12x", ubfm_4 = "53000000DN12w|d3400000DN12x", extr_4 = "13800000DNM2w|93c00000DNM2x", sxtb_2 = "13001c00DNw|93401c00DNx", sxth_2 = "13003c00DNw|93403c00DNx", sxtw_2 = "93407c00DxNw", uxtb_2 = "53001c00DNw", uxth_2 = "53003c00DNw", sbfx_4 = op_alias("sbfm_4", alias_bfx), bfxil_4 = op_alias("bfm_4", alias_bfx), ubfx_4 = op_alias("ubfm_4", alias_bfx), sbfiz_4 = op_alias("sbfm_4", alias_bfiz), bfi_4 = op_alias("bfm_4", alias_bfiz), ubfiz_4 = op_alias("ubfm_4", alias_bfiz), lsl_3 = function(params, nparams) if params and params[3]:byte() == 35 then return alias_lslimm(params, nparams) else return op_template(params, "1ac02000DNMg", nparams) end end, lsr_3 = "1ac02400DNMg|53007c00DN1w|d340fc00DN1x", asr_3 = "1ac02800DNMg|13007c00DN1w|9340fc00DN1x", ror_3 = "1ac02c00DNMg|13800000DNm2w|93c00000DNm2x", clz_2 = "5ac01000DNg", cls_2 = "5ac01400DNg", rbit_2 = "5ac00000DNg", rev_2 = "5ac00800DNw|dac00c00DNx", rev16_2 = "5ac00400DNg", rev32_2 = "dac00800DNx", -- Loads and stores. ["strb_*"] = "38000000DwL", ["ldrb_*"] = "38400000DwL", ["ldrsb_*"] = "38c00000DwL|38800000DxL", ["strh_*"] = "78000000DwL", ["ldrh_*"] = "78400000DwL", ["ldrsh_*"] = "78c00000DwL|78800000DxL", ["str_*"] = "b8000000DwL|f8000000DxL|bc000000DsL|fc000000DdL", ["ldr_*"] = "18000000DwB|58000000DxB|1c000000DsB|5c000000DdB|b8400000DwL|f8400000DxL|bc400000DsL|fc400000DdL", ["ldrsw_*"] = "98000000DxB|b8800000DxL", -- NOTE: ldur etc. are handled by ldr et al. ["stp_*"] = "28000000DAwP|a8000000DAxP|2c000000DAsP|6c000000DAdP", ["ldp_*"] = "28400000DAwP|a8400000DAxP|2c400000DAsP|6c400000DAdP", ["ldpsw_*"] = "68400000DAxP", -- Branches. b_1 = "14000000B", bl_1 = "94000000B", blr_1 = "d63f0000Nx", br_1 = "d61f0000Nx", ret_0 = "d65f03c0", ret_1 = "d65f0000Nx", -- b.cond is added below. cbz_2 = "34000000DBg", cbnz_2 = "35000000DBg", tbz_3 = "36000000DTBw|36000000DTBx", tbnz_3 = "37000000DTBw|37000000DTBx", -- Miscellaneous instructions. -- TODO: hlt, hvc, smc, svc, eret, dcps[123], drps, mrs, msr -- TODO: sys, sysl, ic, dc, at, tlbi -- TODO: hint, yield, wfe, wfi, sev, sevl -- TODO: clrex, dsb, dmb, isb nop_0 = "d503201f", brk_0 = "d4200000", brk_1 = "d4200000W", -- Floating point instructions. fmov_2 = "1e204000DNf|1e260000DwNs|1e270000DsNw|9e660000DxNd|9e670000DdNx|1e201000DFf", fabs_2 = "1e20c000DNf", fneg_2 = "1e214000DNf", fsqrt_2 = "1e21c000DNf", fcvt_2 = "1e22c000DdNs|1e624000DsNd", -- TODO: half-precision and fixed-point conversions. fcvtas_2 = "1e240000DwNs|9e240000DxNs|1e640000DwNd|9e640000DxNd", fcvtau_2 = "1e250000DwNs|9e250000DxNs|1e650000DwNd|9e650000DxNd", fcvtms_2 = "1e300000DwNs|9e300000DxNs|1e700000DwNd|9e700000DxNd", fcvtmu_2 = "1e310000DwNs|9e310000DxNs|1e710000DwNd|9e710000DxNd", fcvtns_2 = "1e200000DwNs|9e200000DxNs|1e600000DwNd|9e600000DxNd", fcvtnu_2 = "1e210000DwNs|9e210000DxNs|1e610000DwNd|9e610000DxNd", fcvtps_2 = "1e280000DwNs|9e280000DxNs|1e680000DwNd|9e680000DxNd", fcvtpu_2 = "1e290000DwNs|9e290000DxNs|1e690000DwNd|9e690000DxNd", fcvtzs_2 = "1e380000DwNs|9e380000DxNs|1e780000DwNd|9e780000DxNd", fcvtzu_2 = "1e390000DwNs|9e390000DxNs|1e790000DwNd|9e790000DxNd", scvtf_2 = "1e220000DsNw|9e220000DsNx|1e620000DdNw|9e620000DdNx", ucvtf_2 = "1e230000DsNw|9e230000DsNx|1e630000DdNw|9e630000DdNx", frintn_2 = "1e244000DNf", frintp_2 = "1e24c000DNf", frintm_2 = "1e254000DNf", frintz_2 = "1e25c000DNf", frinta_2 = "1e264000DNf", frintx_2 = "1e274000DNf", frinti_2 = "1e27c000DNf", fadd_3 = "1e202800DNMf", fsub_3 = "1e203800DNMf", fmul_3 = "1e200800DNMf", fnmul_3 = "1e208800DNMf", fdiv_3 = "1e201800DNMf", fmadd_4 = "1f000000DNMAf", fmsub_4 = "1f008000DNMAf", fnmadd_4 = "1f200000DNMAf", fnmsub_4 = "1f208000DNMAf", fmax_3 = "1e204800DNMf", fmaxnm_3 = "1e206800DNMf", fmin_3 = "1e205800DNMf", fminnm_3 = "1e207800DNMf", fcmp_2 = "1e202000NMf|1e202008NZf", fcmpe_2 = "1e202010NMf|1e202018NZf", fccmp_4 = "1e200400NMVCf", fccmpe_4 = "1e200410NMVCf", fcsel_4 = "1e200c00DNMCf", -- TODO: crc32*, aes*, sha*, pmull -- TODO: SIMD instructions. } for cond,c in pairs(map_cond) do map_op["b"..cond.."_1"] = tohex(0x54000000+c).."B" end ------------------------------------------------------------------------------ -- Handle opcodes defined with template strings. local function parse_template(params, template, nparams, pos) local op = tonumber(template:sub(1, 8), 16) local n = 1 local rtt = {} parse_reg_type = false -- Process each character. for p in gmatch(template:sub(9), ".") do local q = params[n] if p == "D" then op = op + parse_reg(q, 0); n = n + 1 elseif p == "N" then op = op + parse_reg(q, 5); n = n + 1 elseif p == "M" then op = op + parse_reg(q, 16); n = n + 1 elseif p == "A" then op = op + parse_reg(q, 10); n = n + 1 elseif p == "m" then op = op + parse_reg(params[n-1], 16) elseif p == "p" then if q == "sp" then params[n] = "@x31" end elseif p == "g" then if parse_reg_type == "x" then op = op + 0x80000000 elseif parse_reg_type ~= "w" then werror("bad register type") end parse_reg_type = false elseif p == "f" then if parse_reg_type == "d" then op = op + 0x00400000 elseif parse_reg_type ~= "s" then werror("bad register type") end parse_reg_type = false elseif p == "x" or p == "w" or p == "d" or p == "s" then if parse_reg_type ~= p then werror("register size mismatch") end parse_reg_type = false elseif p == "L" then op = parse_load(params, nparams, n, op) elseif p == "P" then op = parse_load_pair(params, nparams, n, op) elseif p == "B" then local mode, v, s = parse_label(q, false); n = n + 1 if not mode then werror("bad label `"..q.."'") end local m = branch_type(op) if mode == "A" then waction("REL_"..mode, v+m, format("(unsigned int)(%s)", s)) actargs[#actargs+1] = format("(unsigned int)((%s)>>32)", s) else waction("REL_"..mode, v+m, s, 1) end elseif p == "I" then op = op + parse_imm12(q); n = n + 1 elseif p == "i" then op = op + parse_imm13(q); n = n + 1 elseif p == "W" then op = op + parse_imm(q, 16, 5, 0, false); n = n + 1 elseif p == "T" then op = op + parse_imm6(q); n = n + 1 elseif p == "1" then op = op + parse_imm(q, 6, 16, 0, false); n = n + 1 elseif p == "2" then op = op + parse_imm(q, 6, 10, 0, false); n = n + 1 elseif p == "5" then op = op + parse_imm(q, 5, 16, 0, false); n = n + 1 elseif p == "V" then op = op + parse_imm(q, 4, 0, 0, false); n = n + 1 elseif p == "F" then op = op + parse_fpimm(q); n = n + 1 elseif p == "Z" then if q ~= "#0" and q ~= "#0.0" then werror("expected zero immediate") end n = n + 1 elseif p == "S" then op = op + parse_shift(q); n = n + 1 elseif p == "X" then op = op + parse_extend(q); n = n + 1 elseif p == "R" then op = op + parse_lslx16(q); n = n + 1 elseif p == "C" then op = op + parse_cond(q, 0); n = n + 1 elseif p == "c" then op = op + parse_cond(q, 1); n = n + 1 else assert(false) end end wputpos(pos, op) end function op_template(params, template, nparams) if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end -- Limit number of section buffer positions used by a single dasm_put(). -- A single opcode needs a maximum of 4 positions. if secpos+4 > maxsecpos then wflush() end local pos = wpos() local lpos, apos, spos = #actlist, #actargs, secpos local ok, err for t in gmatch(template, "[^|]+") do ok, err = pcall(parse_template, params, t, nparams, pos) if ok then return end secpos = spos actlist[lpos+1] = nil actlist[lpos+2] = nil actlist[lpos+3] = nil actlist[lpos+4] = nil actargs[apos+1] = nil actargs[apos+2] = nil actargs[apos+3] = nil actargs[apos+4] = nil end error(err, 0) end map_op[".template__"] = op_template ------------------------------------------------------------------------------ -- Pseudo-opcode to mark the position where the action list is to be emitted. map_op[".actionlist_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeactions(out, name) end) end -- Pseudo-opcode to mark the position where the global enum is to be emitted. map_op[".globals_1"] = function(params) if not params then return "prefix" end local prefix = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobals(out, prefix) end) end -- Pseudo-opcode to mark the position where the global names are to be emitted. map_op[".globalnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobalnames(out, name) end) end -- Pseudo-opcode to mark the position where the extern names are to be emitted. map_op[".externnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeexternnames(out, name) end) end ------------------------------------------------------------------------------ -- Label pseudo-opcode (converted from trailing colon form). map_op[".label_1"] = function(params) if not params then return "[1-9] | ->global | =>pcexpr" end if secpos+1 > maxsecpos then wflush() end local mode, n, s = parse_label(params[1], true) if not mode or mode == "EXT" then werror("bad label definition") end waction("LABEL_"..mode, n, s, 1) end ------------------------------------------------------------------------------ -- Pseudo-opcodes for data storage. local function op_data(params) if not params then return "imm..." end local sz = params.op == ".long" and 4 or 8 for _,p in ipairs(params) do local imm = parse_number(p) if imm then local n = tobit(imm) if n == imm or (n < 0 and n + 2^32 == imm) then wputw(n < 0 and n + 2^32 or n) if sz == 8 then wputw(imm < 0 and 0xffffffff or 0) end elseif sz == 4 then werror("bad immediate `"..p.."'") else imm = nil end end if not imm then local mode, v, s = parse_label(p, false) if sz == 4 then if mode then werror("label does not fit into .long") end waction("IMMV", 0, p) elseif mode and mode ~= "A" then waction("REL_"..mode, v+0x8000, s, 1) else if mode == "A" then p = s end waction("IMMV", 0, format("(unsigned int)(%s)", p)) waction("IMMV", 0, format("(unsigned int)((unsigned long long)(%s)>>32)", p)) end end if secpos+2 > maxsecpos then wflush() end end end map_op[".long_*"] = op_data map_op[".quad_*"] = op_data map_op[".addr_*"] = op_data -- Alignment pseudo-opcode. map_op[".align_1"] = function(params) if not params then return "numpow2" end if secpos+1 > maxsecpos then wflush() end local align = tonumber(params[1]) if align then local x = align -- Must be a power of 2 in the range (2 ... 256). for i=1,8 do x = x / 2 if x == 1 then waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. return end end end werror("bad alignment") end ------------------------------------------------------------------------------ -- Pseudo-opcode for (primitive) type definitions (map to C types). map_op[".type_3"] = function(params, nparams) if not params then return nparams == 2 and "name, ctype" or "name, ctype, reg" end local name, ctype, reg = params[1], params[2], params[3] if not match(name, "^[%a_][%w_]*$") then werror("bad type name `"..name.."'") end local tp = map_type[name] if tp then werror("duplicate type `"..name.."'") end -- Add #type to defines. A bit unclean to put it in map_archdef. map_archdef["#"..name] = "sizeof("..ctype..")" -- Add new type and emit shortcut define. local num = ctypenum + 1 map_type[name] = { ctype = ctype, ctypefmt = format("Dt%X(%%s)", num), reg = reg, } wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) ctypenum = num end map_op[".type_2"] = map_op[".type_3"] -- Dump type definitions. local function dumptypes(out, lvl) local t = {} for name in pairs(map_type) do t[#t+1] = name end sort(t) out:write("Type definitions:\n") for _,name in ipairs(t) do local tp = map_type[name] local reg = tp.reg or "" out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) end out:write("\n") end ------------------------------------------------------------------------------ -- Set the current section. function _M.section(num) waction("SECTION", num) wflush(true) -- SECTION is a terminal action. end ------------------------------------------------------------------------------ -- Dump architecture description. function _M.dumparch(out) out:write(format("DynASM %s version %s, released %s\n\n", _info.arch, _info.version, _info.release)) dumpactions(out) end -- Dump all user defined elements. function _M.dumpdef(out, lvl) dumptypes(out, lvl) dumpglobals(out, lvl) dumpexterns(out, lvl) end ------------------------------------------------------------------------------ -- Pass callbacks from/to the DynASM core. function _M.passcb(wl, we, wf, ww) wline, werror, wfatal, wwarn = wl, we, wf, ww return wflush end -- Setup the arch-specific module. function _M.setup(arch, opt) g_arch, g_opt = arch, opt end -- Merge the core maps and the arch-specific maps. function _M.mergemaps(map_coreop, map_def) setmetatable(map_op, { __index = map_coreop }) setmetatable(map_def, { __index = map_archdef }) return map_op, map_def end return _M ------------------------------------------------------------------------------ ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_mips.h ================================================ /* ** DynASM MIPS encoding engine. ** Copyright (C) 2005-2022 Mike Pall. All rights reserved. ** Released under the MIT license. See dynasm.lua for full copyright notice. */ #include #include #include #include #define DASM_ARCH "mips" #ifndef DASM_EXTERN #define DASM_EXTERN(a,b,c,d) 0 #endif /* Action definitions. */ enum { DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, /* The following actions need a buffer position. */ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, /* The following actions also have an argument. */ DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMS, DASM__MAX }; /* Maximum number of section buffer positions for a single dasm_put() call. */ #define DASM_MAXSECPOS 25 /* DynASM encoder status codes. Action list offset or number are or'ed in. */ #define DASM_S_OK 0x00000000 #define DASM_S_NOMEM 0x01000000 #define DASM_S_PHASE 0x02000000 #define DASM_S_MATCH_SEC 0x03000000 #define DASM_S_RANGE_I 0x11000000 #define DASM_S_RANGE_SEC 0x12000000 #define DASM_S_RANGE_LG 0x13000000 #define DASM_S_RANGE_PC 0x14000000 #define DASM_S_RANGE_REL 0x15000000 #define DASM_S_UNDEF_LG 0x21000000 #define DASM_S_UNDEF_PC 0x22000000 /* Macros to convert positions (8 bit section + 24 bit index). */ #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) #define DASM_POS2BIAS(pos) ((pos)&0xff000000) #define DASM_SEC2POS(sec) ((sec)<<24) #define DASM_POS2SEC(pos) ((pos)>>24) #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) /* Action list type. */ typedef const unsigned int *dasm_ActList; /* Per-section structure. */ typedef struct dasm_Section { int *rbuf; /* Biased buffer pointer (negative section bias). */ int *buf; /* True buffer pointer. */ size_t bsize; /* Buffer size in bytes. */ int pos; /* Biased buffer position. */ int epos; /* End of biased buffer position - max single put. */ int ofs; /* Byte offset into section. */ } dasm_Section; /* Core structure holding the DynASM encoding state. */ struct dasm_State { size_t psize; /* Allocated size of this structure. */ dasm_ActList actionlist; /* Current actionlist pointer. */ int *lglabels; /* Local/global chain/pos ptrs. */ size_t lgsize; int *pclabels; /* PC label chains/pos ptrs. */ size_t pcsize; void **globals; /* Array of globals (bias -10). */ dasm_Section *section; /* Pointer to active section. */ size_t codesize; /* Total size of all code sections. */ int maxsection; /* 0 <= sectionidx < maxsection. */ int status; /* Status code. */ dasm_Section sections[1]; /* All sections. Alloc-extended. */ }; /* The size of the core structure depends on the max. number of sections. */ #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) /* Initialize DynASM state. */ void dasm_init(Dst_DECL, int maxsection) { dasm_State *D; size_t psz = 0; int i; Dst_REF = NULL; DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); D = Dst_REF; D->psize = psz; D->lglabels = NULL; D->lgsize = 0; D->pclabels = NULL; D->pcsize = 0; D->globals = NULL; D->maxsection = maxsection; for (i = 0; i < maxsection; i++) { D->sections[i].buf = NULL; /* Need this for pass3. */ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); D->sections[i].bsize = 0; D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ } } /* Free DynASM state. */ void dasm_free(Dst_DECL) { dasm_State *D = Dst_REF; int i; for (i = 0; i < D->maxsection; i++) if (D->sections[i].buf) DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); DASM_M_FREE(Dst, D, D->psize); } /* Setup global label array. Must be called before dasm_setup(). */ void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) { dasm_State *D = Dst_REF; D->globals = gl - 10; /* Negative bias to compensate for locals. */ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); } /* Grow PC label array. Can be called after dasm_setup(), too. */ void dasm_growpc(Dst_DECL, unsigned int maxpc) { dasm_State *D = Dst_REF; size_t osz = D->pcsize; DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); } /* Setup encoder. */ void dasm_setup(Dst_DECL, const void *actionlist) { dasm_State *D = Dst_REF; int i; D->actionlist = (dasm_ActList)actionlist; D->status = DASM_S_OK; D->section = &D->sections[0]; memset((void *)D->lglabels, 0, D->lgsize); if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); for (i = 0; i < D->maxsection; i++) { D->sections[i].pos = DASM_SEC2POS(i); D->sections[i].ofs = 0; } } #ifdef DASM_CHECKS #define CK(x, st) \ do { if (!(x)) { \ D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0) #define CKPL(kind, st) \ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ D->status = DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0) #else #define CK(x, st) ((void)0) #define CKPL(kind, st) ((void)0) #endif /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ void dasm_put(Dst_DECL, int start, ...) { va_list ap; dasm_State *D = Dst_REF; dasm_ActList p = D->actionlist + start; dasm_Section *sec = D->section; int pos = sec->pos, ofs = sec->ofs; int *b; if (pos >= sec->epos) { DASM_M_GROW(Dst, int, sec->buf, sec->bsize, sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); sec->rbuf = sec->buf - DASM_POS2BIAS(pos); sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); } b = sec->rbuf; b[pos++] = start; va_start(ap, start); while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16) - 0xff00; if (action >= DASM__MAX) { ofs += 4; } else { int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; switch (action) { case DASM_STOP: goto stop; case DASM_SECTION: n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; goto stop; case DASM_ESC: p++; ofs += 4; break; case DASM_REL_EXT: break; case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; case DASM_REL_LG: n = (ins & 2047) - 10; pl = D->lglabels + n; /* Bkwd rel or global. */ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } pl += 10; n = *pl; if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ goto linkrel; case DASM_REL_PC: pl = D->pclabels + n; CKPL(pc, PC); putrel: n = *pl; if (n < 0) { /* Label exists. Get label pos and store it. */ b[pos] = -n; } else { linkrel: b[pos] = n; /* Else link to rel chain, anchored at label. */ *pl = pos; } pos++; break; case DASM_LABEL_LG: pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; case DASM_LABEL_PC: pl = D->pclabels + n; CKPL(pc, PC); putlabel: n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } *pl = -pos; /* Label exists now. */ b[pos++] = ofs; /* Store pass1 offset estimate. */ break; case DASM_IMM: case DASM_IMMS: #ifdef DASM_CHECKS CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); #endif n >>= ((ins>>10)&31); #ifdef DASM_CHECKS if (ins & 0x8000) CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); else CK((n>>((ins>>5)&31)) == 0, RANGE_I); #endif b[pos++] = n; break; } } } stop: va_end(ap); sec->pos = pos; sec->ofs = ofs; } #undef CK /* Pass 2: Link sections, shrink aligns, fix label offsets. */ int dasm_link(Dst_DECL, size_t *szp) { dasm_State *D = Dst_REF; int secnum; int ofs = 0; #ifdef DASM_CHECKS *szp = 0; if (D->status != DASM_S_OK) return D->status; { int pc; for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; } #endif { /* Handle globals not defined in this translation unit. */ int idx; for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { int n = D->lglabels[idx]; /* Undefined label: Collapse rel chain and replace with marker (< 0). */ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } } } /* Combine all code sections. No support for data sections (yet). */ for (secnum = 0; secnum < D->maxsection; secnum++) { dasm_Section *sec = D->sections + secnum; int *b = sec->rbuf; int pos = DASM_SEC2POS(secnum); int lastpos = sec->pos; while (pos != lastpos) { dasm_ActList p = D->actionlist + b[pos++]; while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16) - 0xff00; switch (action) { case DASM_STOP: case DASM_SECTION: goto stop; case DASM_ESC: p++; break; case DASM_REL_EXT: break; case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; case DASM_REL_LG: case DASM_REL_PC: pos++; break; case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; case DASM_IMM: case DASM_IMMS: pos++; break; } } stop: (void)0; } ofs += sec->ofs; /* Next section starts right after current section. */ } D->codesize = ofs; /* Total size of all code sections */ *szp = ofs; return DASM_S_OK; } #ifdef DASM_CHECKS #define CK(x, st) \ do { if (!(x)) return DASM_S_##st|(int)(p-D->actionlist-1); } while (0) #else #define CK(x, st) ((void)0) #endif /* Pass 3: Encode sections. */ int dasm_encode(Dst_DECL, void *buffer) { dasm_State *D = Dst_REF; char *base = (char *)buffer; unsigned int *cp = (unsigned int *)buffer; int secnum; /* Encode all code sections. No support for data sections (yet). */ for (secnum = 0; secnum < D->maxsection; secnum++) { dasm_Section *sec = D->sections + secnum; int *b = sec->buf; int *endb = sec->rbuf + sec->pos; while (b != endb) { dasm_ActList p = D->actionlist + *b++; while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16) - 0xff00; int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; switch (action) { case DASM_STOP: case DASM_SECTION: goto stop; case DASM_ESC: *cp++ = *p++; break; case DASM_REL_EXT: n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); goto patchrel; case DASM_ALIGN: ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; break; case DASM_REL_LG: if (n < 0) { n = (int)((ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp); goto patchrel; } /* fallthrough */ case DASM_REL_PC: CK(n >= 0, UNDEF_PC); n = *DASM_POS2PTR(D, n); if (ins & 2048) n = (n + (int)(size_t)base) & 0x0fffffff; else n = n - (int)((char *)cp - base); patchrel: { unsigned int e = 16 + ((ins >> 12) & 15); CK((n & 3) == 0 && ((n + ((ins & 2048) ? 0 : (1<<(e+1)))) >> (e+2)) == 0, RANGE_REL); cp[-1] |= ((n>>2) & ((1<= 20) D->globals[ins-10] = (void *)(base + n); break; case DASM_LABEL_PC: break; case DASM_IMMS: cp[-1] |= ((n>>3) & 4); n &= 0x1f; /* fallthrough */ case DASM_IMM: cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); break; default: *cp++ = ins; break; } } stop: (void)0; } } if (base + D->codesize != (char *)cp) /* Check for phase errors. */ return DASM_S_PHASE; return DASM_S_OK; } #undef CK /* Get PC label offset. */ int dasm_getpclabel(Dst_DECL, unsigned int pc) { dasm_State *D = Dst_REF; if (pc*sizeof(int) < D->pcsize) { int pos = D->pclabels[pc]; if (pos < 0) return *DASM_POS2PTR(D, -pos); if (pos > 0) return -1; /* Undefined. */ } return -2; /* Unused or out of range. */ } #ifdef DASM_CHECKS /* Optional sanity checker to call between isolated encoding steps. */ int dasm_checkstep(Dst_DECL, int secmatch) { dasm_State *D = Dst_REF; if (D->status == DASM_S_OK) { int i; for (i = 1; i <= 9; i++) { if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } D->lglabels[i] = 0; } } if (D->status == DASM_S_OK && secmatch >= 0 && D->section != &D->sections[secmatch]) D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections); return D->status; } #endif ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_mips.lua ================================================ ------------------------------------------------------------------------------ -- DynASM MIPS32/MIPS64 module. -- -- Copyright (C) 2005-2022 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------ local mips64 = mips64 local mipsr6 = _map_def.MIPSR6 -- Module information: local _info = { arch = mips64 and "mips64" or "mips", description = "DynASM MIPS32/MIPS64 module", version = "1.5.0", vernum = 10500, release = "2021-05-02", author = "Mike Pall", license = "MIT", } -- Exported glue functions for the arch-specific module. local _M = { _info = _info } -- Cache library functions. local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs local assert, setmetatable = assert, setmetatable local _s = string local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char local match, gmatch = _s.match, _s.gmatch local concat, sort = table.concat, table.sort local bit = bit or require("bit") local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift local tohex = bit.tohex -- Inherited tables and callbacks. local g_opt, g_arch local wline, werror, wfatal, wwarn -- Action name list. -- CHECK: Keep this in sync with the C code! local action_names = { "STOP", "SECTION", "ESC", "REL_EXT", "ALIGN", "REL_LG", "LABEL_LG", "REL_PC", "LABEL_PC", "IMM", "IMMS", } -- Maximum number of section buffer positions for dasm_put(). -- CHECK: Keep this in sync with the C code! local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. -- Action name -> action number. local map_action = {} for n,name in ipairs(action_names) do map_action[name] = n-1 end -- Action list buffer. local actlist = {} -- Argument list for next dasm_put(). Start with offset 0 into action list. local actargs = { 0 } -- Current number of section buffer positions for dasm_put(). local secpos = 1 ------------------------------------------------------------------------------ -- Dump action names and numbers. local function dumpactions(out) out:write("DynASM encoding engine action codes:\n") for n,name in ipairs(action_names) do local num = map_action[name] out:write(format(" %-10s %02X %d\n", name, num, num)) end out:write("\n") end -- Write action list buffer as a huge static C array. local function writeactions(out, name) local nn = #actlist if nn == 0 then nn = 1; actlist[0] = map_action.STOP end out:write("static const unsigned int ", name, "[", nn, "] = {\n") for i = 1,nn-1 do assert(out:write("0x", tohex(actlist[i]), ",\n")) end assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) end ------------------------------------------------------------------------------ -- Add word to action list. local function wputxw(n) assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") actlist[#actlist+1] = n end -- Add action to list with optional arg. Advance buffer pos, too. local function waction(action, val, a, num) local w = assert(map_action[action], "bad action name `"..action.."'") wputxw(0xff000000 + w * 0x10000 + (val or 0)) if a then actargs[#actargs+1] = a end if a or num then secpos = secpos + (num or 1) end end -- Flush action list (intervening C code or buffer pos overflow). local function wflush(term) if #actlist == actargs[1] then return end -- Nothing to flush. if not term then waction("STOP") end -- Terminate action list. wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). secpos = 1 -- The actionlist offset occupies a buffer position, too. end -- Put escaped word. local function wputw(n) if n >= 0xff000000 then waction("ESC") end wputxw(n) end -- Reserve position for word. local function wpos() local pos = #actlist+1 actlist[pos] = "" return pos end -- Store word to reserved position. local function wputpos(pos, n) assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") actlist[pos] = n end ------------------------------------------------------------------------------ -- Global label name -> global label number. With auto assignment on 1st use. local next_global = 20 local map_global = setmetatable({}, { __index = function(t, name) if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end local n = next_global if n > 2047 then werror("too many global labels") end next_global = n + 1 t[name] = n return n end}) -- Dump global labels. local function dumpglobals(out, lvl) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("Global labels:\n") for i=20,next_global-1 do out:write(format(" %s\n", t[i])) end out:write("\n") end -- Write global label enum. local function writeglobals(out, prefix) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("enum {\n") for i=20,next_global-1 do out:write(" ", prefix, t[i], ",\n") end out:write(" ", prefix, "_MAX\n};\n") end -- Write global label names. local function writeglobalnames(out, name) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("static const char *const ", name, "[] = {\n") for i=20,next_global-1 do out:write(" \"", t[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Extern label name -> extern label number. With auto assignment on 1st use. local next_extern = 0 local map_extern_ = {} local map_extern = setmetatable({}, { __index = function(t, name) -- No restrictions on the name for now. local n = next_extern if n > 2047 then werror("too many extern labels") end next_extern = n + 1 t[name] = n map_extern_[n] = name return n end}) -- Dump extern labels. local function dumpexterns(out, lvl) out:write("Extern labels:\n") for i=0,next_extern-1 do out:write(format(" %s\n", map_extern_[i])) end out:write("\n") end -- Write extern label names. local function writeexternnames(out, name) out:write("static const char *const ", name, "[] = {\n") for i=0,next_extern-1 do out:write(" \"", map_extern_[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Arch-specific maps. local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name. local map_type = {} -- Type name -> { ctype, reg } local ctypenum = 0 -- Type number (for Dt... macros). -- Reverse defines for registers. function _M.revdef(s) if s == "r29" then return "sp" elseif s == "r31" then return "ra" end return s end ------------------------------------------------------------------------------ -- Template strings for MIPS instructions. local map_op = { -- First-level opcodes. j_1 = "08000000J", jal_1 = "0c000000J", b_1 = "10000000B", beqz_2 = "10000000SB", beq_3 = "10000000STB", bnez_2 = "14000000SB", bne_3 = "14000000STB", blez_2 = "18000000SB", bgtz_2 = "1c000000SB", li_2 = "24000000TI", addiu_3 = "24000000TSI", slti_3 = "28000000TSI", sltiu_3 = "2c000000TSI", andi_3 = "30000000TSU", lu_2 = "34000000TU", ori_3 = "34000000TSU", xori_3 = "38000000TSU", lui_2 = "3c000000TU", daddiu_3 = mips64 and "64000000TSI", ldl_2 = mips64 and "68000000TO", ldr_2 = mips64 and "6c000000TO", lb_2 = "80000000TO", lh_2 = "84000000TO", lw_2 = "8c000000TO", lbu_2 = "90000000TO", lhu_2 = "94000000TO", lwu_2 = mips64 and "9c000000TO", sb_2 = "a0000000TO", sh_2 = "a4000000TO", sw_2 = "ac000000TO", lwc1_2 = "c4000000HO", ldc1_2 = "d4000000HO", ld_2 = mips64 and "dc000000TO", swc1_2 = "e4000000HO", sdc1_2 = "f4000000HO", sd_2 = mips64 and "fc000000TO", -- Opcode SPECIAL. nop_0 = "00000000", sll_3 = "00000000DTA", sextw_2 = "00000000DT", srl_3 = "00000002DTA", rotr_3 = "00200002DTA", sra_3 = "00000003DTA", sllv_3 = "00000004DTS", srlv_3 = "00000006DTS", rotrv_3 = "00000046DTS", drotrv_3 = mips64 and "00000056DTS", srav_3 = "00000007DTS", jalr_1 = "0000f809S", jalr_2 = "00000009DS", syscall_0 = "0000000c", syscall_1 = "0000000cY", break_0 = "0000000d", break_1 = "0000000dY", sync_0 = "0000000f", dsllv_3 = mips64 and "00000014DTS", dsrlv_3 = mips64 and "00000016DTS", dsrav_3 = mips64 and "00000017DTS", add_3 = "00000020DST", move_2 = mips64 and "00000025DS" or "00000021DS", addu_3 = "00000021DST", sub_3 = "00000022DST", negu_2 = mips64 and "0000002fDT" or "00000023DT", subu_3 = "00000023DST", and_3 = "00000024DST", or_3 = "00000025DST", xor_3 = "00000026DST", not_2 = "00000027DS", nor_3 = "00000027DST", slt_3 = "0000002aDST", sltu_3 = "0000002bDST", dadd_3 = mips64 and "0000002cDST", daddu_3 = mips64 and "0000002dDST", dsub_3 = mips64 and "0000002eDST", dsubu_3 = mips64 and "0000002fDST", tge_2 = "00000030ST", tge_3 = "00000030STZ", tgeu_2 = "00000031ST", tgeu_3 = "00000031STZ", tlt_2 = "00000032ST", tlt_3 = "00000032STZ", tltu_2 = "00000033ST", tltu_3 = "00000033STZ", teq_2 = "00000034ST", teq_3 = "00000034STZ", tne_2 = "00000036ST", tne_3 = "00000036STZ", dsll_3 = mips64 and "00000038DTa", dsrl_3 = mips64 and "0000003aDTa", drotr_3 = mips64 and "0020003aDTa", dsra_3 = mips64 and "0000003bDTa", dsll32_3 = mips64 and "0000003cDTA", dsrl32_3 = mips64 and "0000003eDTA", drotr32_3 = mips64 and "0020003eDTA", dsra32_3 = mips64 and "0000003fDTA", -- Opcode REGIMM. bltz_2 = "04000000SB", bgez_2 = "04010000SB", bltzl_2 = "04020000SB", bgezl_2 = "04030000SB", bal_1 = "04110000B", synci_1 = "041f0000O", -- Opcode SPECIAL3. ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1 dextm_4 = mips64 and "7c000001TSAM", -- Args: pos | size-1-32 dextu_4 = mips64 and "7c000002TSAM", -- Args: pos-32 | size-1 dext_4 = mips64 and "7c000003TSAM", -- Args: pos | size-1 zextw_2 = mips64 and "7c00f803TS", ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1 dinsm_4 = mips64 and "7c000005TSAM", -- Args: pos | pos+size-33 dinsu_4 = mips64 and "7c000006TSAM", -- Args: pos-32 | pos+size-33 dins_4 = mips64 and "7c000007TSAM", -- Args: pos | pos+size-1 wsbh_2 = "7c0000a0DT", dsbh_2 = mips64 and "7c0000a4DT", dshd_2 = mips64 and "7c000164DT", seb_2 = "7c000420DT", seh_2 = "7c000620DT", rdhwr_2 = "7c00003bTD", -- Opcode COP0. mfc0_2 = "40000000TD", mfc0_3 = "40000000TDW", dmfc0_2 = mips64 and "40200000TD", dmfc0_3 = mips64 and "40200000TDW", mtc0_2 = "40800000TD", mtc0_3 = "40800000TDW", dmtc0_2 = mips64 and "40a00000TD", dmtc0_3 = mips64 and "40a00000TDW", rdpgpr_2 = "41400000DT", di_0 = "41606000", di_1 = "41606000T", ei_0 = "41606020", ei_1 = "41606020T", wrpgpr_2 = "41c00000DT", tlbr_0 = "42000001", tlbwi_0 = "42000002", tlbwr_0 = "42000006", tlbp_0 = "42000008", eret_0 = "42000018", deret_0 = "4200001f", wait_0 = "42000020", -- Opcode COP1. mfc1_2 = "44000000TG", dmfc1_2 = mips64 and "44200000TG", cfc1_2 = "44400000TG", mfhc1_2 = "44600000TG", mtc1_2 = "44800000TG", dmtc1_2 = mips64 and "44a00000TG", ctc1_2 = "44c00000TG", mthc1_2 = "44e00000TG", ["add.s_3"] = "46000000FGH", ["sub.s_3"] = "46000001FGH", ["mul.s_3"] = "46000002FGH", ["div.s_3"] = "46000003FGH", ["sqrt.s_2"] = "46000004FG", ["abs.s_2"] = "46000005FG", ["mov.s_2"] = "46000006FG", ["neg.s_2"] = "46000007FG", ["round.l.s_2"] = "46000008FG", ["trunc.l.s_2"] = "46000009FG", ["ceil.l.s_2"] = "4600000aFG", ["floor.l.s_2"] = "4600000bFG", ["round.w.s_2"] = "4600000cFG", ["trunc.w.s_2"] = "4600000dFG", ["ceil.w.s_2"] = "4600000eFG", ["floor.w.s_2"] = "4600000fFG", ["recip.s_2"] = "46000015FG", ["rsqrt.s_2"] = "46000016FG", ["cvt.d.s_2"] = "46000021FG", ["cvt.w.s_2"] = "46000024FG", ["cvt.l.s_2"] = "46000025FG", ["add.d_3"] = "46200000FGH", ["sub.d_3"] = "46200001FGH", ["mul.d_3"] = "46200002FGH", ["div.d_3"] = "46200003FGH", ["sqrt.d_2"] = "46200004FG", ["abs.d_2"] = "46200005FG", ["mov.d_2"] = "46200006FG", ["neg.d_2"] = "46200007FG", ["round.l.d_2"] = "46200008FG", ["trunc.l.d_2"] = "46200009FG", ["ceil.l.d_2"] = "4620000aFG", ["floor.l.d_2"] = "4620000bFG", ["round.w.d_2"] = "4620000cFG", ["trunc.w.d_2"] = "4620000dFG", ["ceil.w.d_2"] = "4620000eFG", ["floor.w.d_2"] = "4620000fFG", ["recip.d_2"] = "46200015FG", ["rsqrt.d_2"] = "46200016FG", ["cvt.s.d_2"] = "46200020FG", ["cvt.w.d_2"] = "46200024FG", ["cvt.l.d_2"] = "46200025FG", ["cvt.s.w_2"] = "46800020FG", ["cvt.d.w_2"] = "46800021FG", ["cvt.s.l_2"] = "46a00020FG", ["cvt.d.l_2"] = "46a00021FG", } if mipsr6 then -- Instructions added with MIPSR6. for k,v in pairs({ -- Add immediate to upper bits. aui_3 = "3c000000TSI", daui_3 = mips64 and "74000000TSI", dahi_2 = mips64 and "04060000SI", dati_2 = mips64 and "041e0000SI", -- TODO: addiupc, auipc, aluipc, lwpc, lwupc, ldpc. -- Compact branches. blezalc_2 = "18000000TB", -- rt != 0. bgezalc_2 = "18000000T=SB", -- rt != 0. bgtzalc_2 = "1c000000TB", -- rt != 0. bltzalc_2 = "1c000000T=SB", -- rt != 0. blezc_2 = "58000000TB", -- rt != 0. bgezc_2 = "58000000T=SB", -- rt != 0. bgec_3 = "58000000STB", -- rs != rt. blec_3 = "58000000TSB", -- rt != rs. bgtzc_2 = "5c000000TB", -- rt != 0. bltzc_2 = "5c000000T=SB", -- rt != 0. bltc_3 = "5c000000STB", -- rs != rt. bgtc_3 = "5c000000TSB", -- rt != rs. bgeuc_3 = "18000000STB", -- rs != rt. bleuc_3 = "18000000TSB", -- rt != rs. bltuc_3 = "1c000000STB", -- rs != rt. bgtuc_3 = "1c000000TSB", -- rt != rs. beqzalc_2 = "20000000TB", -- rt != 0. bnezalc_2 = "60000000TB", -- rt != 0. beqc_3 = "20000000STB", -- rs < rt. bnec_3 = "60000000STB", -- rs < rt. bovc_3 = "20000000STB", -- rs >= rt. bnvc_3 = "60000000STB", -- rs >= rt. beqzc_2 = "d8000000SK", -- rs != 0. bnezc_2 = "f8000000SK", -- rs != 0. jic_2 = "d8000000TI", jialc_2 = "f8000000TI", bc_1 = "c8000000L", balc_1 = "e8000000L", -- Opcode SPECIAL. jr_1 = "00000009S", sdbbp_0 = "0000000e", sdbbp_1 = "0000000eY", lsa_4 = "00000005DSTA", dlsa_4 = mips64 and "00000015DSTA", seleqz_3 = "00000035DST", selnez_3 = "00000037DST", clz_2 = "00000050DS", clo_2 = "00000051DS", dclz_2 = mips64 and "00000052DS", dclo_2 = mips64 and "00000053DS", mul_3 = "00000098DST", muh_3 = "000000d8DST", mulu_3 = "00000099DST", muhu_3 = "000000d9DST", div_3 = "0000009aDST", mod_3 = "000000daDST", divu_3 = "0000009bDST", modu_3 = "000000dbDST", dmul_3 = mips64 and "0000009cDST", dmuh_3 = mips64 and "000000dcDST", dmulu_3 = mips64 and "0000009dDST", dmuhu_3 = mips64 and "000000ddDST", ddiv_3 = mips64 and "0000009eDST", dmod_3 = mips64 and "000000deDST", ddivu_3 = mips64 and "0000009fDST", dmodu_3 = mips64 and "000000dfDST", -- Opcode SPECIAL3. align_4 = "7c000220DSTA", dalign_4 = mips64 and "7c000224DSTA", bitswap_2 = "7c000020DT", dbitswap_2 = mips64 and "7c000024DT", -- Opcode COP1. bc1eqz_2 = "45200000HB", bc1nez_2 = "45a00000HB", ["sel.s_3"] = "46000010FGH", ["seleqz.s_3"] = "46000014FGH", ["selnez.s_3"] = "46000017FGH", ["maddf.s_3"] = "46000018FGH", ["msubf.s_3"] = "46000019FGH", ["rint.s_2"] = "4600001aFG", ["class.s_2"] = "4600001bFG", ["min.s_3"] = "4600001cFGH", ["mina.s_3"] = "4600001dFGH", ["max.s_3"] = "4600001eFGH", ["maxa.s_3"] = "4600001fFGH", ["cmp.af.s_3"] = "46800000FGH", ["cmp.un.s_3"] = "46800001FGH", ["cmp.or.s_3"] = "46800011FGH", ["cmp.eq.s_3"] = "46800002FGH", ["cmp.une.s_3"] = "46800012FGH", ["cmp.ueq.s_3"] = "46800003FGH", ["cmp.ne.s_3"] = "46800013FGH", ["cmp.lt.s_3"] = "46800004FGH", ["cmp.ult.s_3"] = "46800005FGH", ["cmp.le.s_3"] = "46800006FGH", ["cmp.ule.s_3"] = "46800007FGH", ["cmp.saf.s_3"] = "46800008FGH", ["cmp.sun.s_3"] = "46800009FGH", ["cmp.sor.s_3"] = "46800019FGH", ["cmp.seq.s_3"] = "4680000aFGH", ["cmp.sune.s_3"] = "4680001aFGH", ["cmp.sueq.s_3"] = "4680000bFGH", ["cmp.sne.s_3"] = "4680001bFGH", ["cmp.slt.s_3"] = "4680000cFGH", ["cmp.sult.s_3"] = "4680000dFGH", ["cmp.sle.s_3"] = "4680000eFGH", ["cmp.sule.s_3"] = "4680000fFGH", ["sel.d_3"] = "46200010FGH", ["seleqz.d_3"] = "46200014FGH", ["selnez.d_3"] = "46200017FGH", ["maddf.d_3"] = "46200018FGH", ["msubf.d_3"] = "46200019FGH", ["rint.d_2"] = "4620001aFG", ["class.d_2"] = "4620001bFG", ["min.d_3"] = "4620001cFGH", ["mina.d_3"] = "4620001dFGH", ["max.d_3"] = "4620001eFGH", ["maxa.d_3"] = "4620001fFGH", ["cmp.af.d_3"] = "46a00000FGH", ["cmp.un.d_3"] = "46a00001FGH", ["cmp.or.d_3"] = "46a00011FGH", ["cmp.eq.d_3"] = "46a00002FGH", ["cmp.une.d_3"] = "46a00012FGH", ["cmp.ueq.d_3"] = "46a00003FGH", ["cmp.ne.d_3"] = "46a00013FGH", ["cmp.lt.d_3"] = "46a00004FGH", ["cmp.ult.d_3"] = "46a00005FGH", ["cmp.le.d_3"] = "46a00006FGH", ["cmp.ule.d_3"] = "46a00007FGH", ["cmp.saf.d_3"] = "46a00008FGH", ["cmp.sun.d_3"] = "46a00009FGH", ["cmp.sor.d_3"] = "46a00019FGH", ["cmp.seq.d_3"] = "46a0000aFGH", ["cmp.sune.d_3"] = "46a0001aFGH", ["cmp.sueq.d_3"] = "46a0000bFGH", ["cmp.sne.d_3"] = "46a0001bFGH", ["cmp.slt.d_3"] = "46a0000cFGH", ["cmp.sult.d_3"] = "46a0000dFGH", ["cmp.sle.d_3"] = "46a0000eFGH", ["cmp.sule.d_3"] = "46a0000fFGH", }) do map_op[k] = v end else -- Instructions removed by MIPSR6. for k,v in pairs({ -- Traps, don't use. addi_3 = "20000000TSI", daddi_3 = mips64 and "60000000TSI", -- Branch on likely, don't use. beqzl_2 = "50000000SB", beql_3 = "50000000STB", bnezl_2 = "54000000SB", bnel_3 = "54000000STB", blezl_2 = "58000000SB", bgtzl_2 = "5c000000SB", lwl_2 = "88000000TO", lwr_2 = "98000000TO", swl_2 = "a8000000TO", sdl_2 = mips64 and "b0000000TO", sdr_2 = mips64 and "b1000000TO", swr_2 = "b8000000TO", cache_2 = "bc000000NO", ll_2 = "c0000000TO", pref_2 = "cc000000NO", sc_2 = "e0000000TO", scd_2 = mips64 and "f0000000TO", -- Opcode SPECIAL. movf_2 = "00000001DS", movf_3 = "00000001DSC", movt_2 = "00010001DS", movt_3 = "00010001DSC", jr_1 = "00000008S", movz_3 = "0000000aDST", movn_3 = "0000000bDST", mfhi_1 = "00000010D", mthi_1 = "00000011S", mflo_1 = "00000012D", mtlo_1 = "00000013S", mult_2 = "00000018ST", multu_2 = "00000019ST", div_3 = "0000001aST", divu_3 = "0000001bST", ddiv_3 = mips64 and "0000001eST", ddivu_3 = mips64 and "0000001fST", dmult_2 = mips64 and "0000001cST", dmultu_2 = mips64 and "0000001dST", -- Opcode REGIMM. tgei_2 = "04080000SI", tgeiu_2 = "04090000SI", tlti_2 = "040a0000SI", tltiu_2 = "040b0000SI", teqi_2 = "040c0000SI", tnei_2 = "040e0000SI", bltzal_2 = "04100000SB", bgezal_2 = "04110000SB", bltzall_2 = "04120000SB", bgezall_2 = "04130000SB", -- Opcode SPECIAL2. madd_2 = "70000000ST", maddu_2 = "70000001ST", mul_3 = "70000002DST", msub_2 = "70000004ST", msubu_2 = "70000005ST", clz_2 = "70000020D=TS", clo_2 = "70000021D=TS", dclz_2 = mips64 and "70000024D=TS", dclo_2 = mips64 and "70000025D=TS", sdbbp_0 = "7000003f", sdbbp_1 = "7000003fY", -- Opcode COP1. bc1f_1 = "45000000B", bc1f_2 = "45000000CB", bc1t_1 = "45010000B", bc1t_2 = "45010000CB", bc1fl_1 = "45020000B", bc1fl_2 = "45020000CB", bc1tl_1 = "45030000B", bc1tl_2 = "45030000CB", ["movf.s_2"] = "46000011FG", ["movf.s_3"] = "46000011FGC", ["movt.s_2"] = "46010011FG", ["movt.s_3"] = "46010011FGC", ["movz.s_3"] = "46000012FGT", ["movn.s_3"] = "46000013FGT", ["cvt.ps.s_3"] = "46000026FGH", ["c.f.s_2"] = "46000030GH", ["c.f.s_3"] = "46000030VGH", ["c.un.s_2"] = "46000031GH", ["c.un.s_3"] = "46000031VGH", ["c.eq.s_2"] = "46000032GH", ["c.eq.s_3"] = "46000032VGH", ["c.ueq.s_2"] = "46000033GH", ["c.ueq.s_3"] = "46000033VGH", ["c.olt.s_2"] = "46000034GH", ["c.olt.s_3"] = "46000034VGH", ["c.ult.s_2"] = "46000035GH", ["c.ult.s_3"] = "46000035VGH", ["c.ole.s_2"] = "46000036GH", ["c.ole.s_3"] = "46000036VGH", ["c.ule.s_2"] = "46000037GH", ["c.ule.s_3"] = "46000037VGH", ["c.sf.s_2"] = "46000038GH", ["c.sf.s_3"] = "46000038VGH", ["c.ngle.s_2"] = "46000039GH", ["c.ngle.s_3"] = "46000039VGH", ["c.seq.s_2"] = "4600003aGH", ["c.seq.s_3"] = "4600003aVGH", ["c.ngl.s_2"] = "4600003bGH", ["c.ngl.s_3"] = "4600003bVGH", ["c.lt.s_2"] = "4600003cGH", ["c.lt.s_3"] = "4600003cVGH", ["c.nge.s_2"] = "4600003dGH", ["c.nge.s_3"] = "4600003dVGH", ["c.le.s_2"] = "4600003eGH", ["c.le.s_3"] = "4600003eVGH", ["c.ngt.s_2"] = "4600003fGH", ["c.ngt.s_3"] = "4600003fVGH", ["movf.d_2"] = "46200011FG", ["movf.d_3"] = "46200011FGC", ["movt.d_2"] = "46210011FG", ["movt.d_3"] = "46210011FGC", ["movz.d_3"] = "46200012FGT", ["movn.d_3"] = "46200013FGT", ["c.f.d_2"] = "46200030GH", ["c.f.d_3"] = "46200030VGH", ["c.un.d_2"] = "46200031GH", ["c.un.d_3"] = "46200031VGH", ["c.eq.d_2"] = "46200032GH", ["c.eq.d_3"] = "46200032VGH", ["c.ueq.d_2"] = "46200033GH", ["c.ueq.d_3"] = "46200033VGH", ["c.olt.d_2"] = "46200034GH", ["c.olt.d_3"] = "46200034VGH", ["c.ult.d_2"] = "46200035GH", ["c.ult.d_3"] = "46200035VGH", ["c.ole.d_2"] = "46200036GH", ["c.ole.d_3"] = "46200036VGH", ["c.ule.d_2"] = "46200037GH", ["c.ule.d_3"] = "46200037VGH", ["c.sf.d_2"] = "46200038GH", ["c.sf.d_3"] = "46200038VGH", ["c.ngle.d_2"] = "46200039GH", ["c.ngle.d_3"] = "46200039VGH", ["c.seq.d_2"] = "4620003aGH", ["c.seq.d_3"] = "4620003aVGH", ["c.ngl.d_2"] = "4620003bGH", ["c.ngl.d_3"] = "4620003bVGH", ["c.lt.d_2"] = "4620003cGH", ["c.lt.d_3"] = "4620003cVGH", ["c.nge.d_2"] = "4620003dGH", ["c.nge.d_3"] = "4620003dVGH", ["c.le.d_2"] = "4620003eGH", ["c.le.d_3"] = "4620003eVGH", ["c.ngt.d_2"] = "4620003fGH", ["c.ngt.d_3"] = "4620003fVGH", ["add.ps_3"] = "46c00000FGH", ["sub.ps_3"] = "46c00001FGH", ["mul.ps_3"] = "46c00002FGH", ["abs.ps_2"] = "46c00005FG", ["mov.ps_2"] = "46c00006FG", ["neg.ps_2"] = "46c00007FG", ["movf.ps_2"] = "46c00011FG", ["movf.ps_3"] = "46c00011FGC", ["movt.ps_2"] = "46c10011FG", ["movt.ps_3"] = "46c10011FGC", ["movz.ps_3"] = "46c00012FGT", ["movn.ps_3"] = "46c00013FGT", ["cvt.s.pu_2"] = "46c00020FG", ["cvt.s.pl_2"] = "46c00028FG", ["pll.ps_3"] = "46c0002cFGH", ["plu.ps_3"] = "46c0002dFGH", ["pul.ps_3"] = "46c0002eFGH", ["puu.ps_3"] = "46c0002fFGH", ["c.f.ps_2"] = "46c00030GH", ["c.f.ps_3"] = "46c00030VGH", ["c.un.ps_2"] = "46c00031GH", ["c.un.ps_3"] = "46c00031VGH", ["c.eq.ps_2"] = "46c00032GH", ["c.eq.ps_3"] = "46c00032VGH", ["c.ueq.ps_2"] = "46c00033GH", ["c.ueq.ps_3"] = "46c00033VGH", ["c.olt.ps_2"] = "46c00034GH", ["c.olt.ps_3"] = "46c00034VGH", ["c.ult.ps_2"] = "46c00035GH", ["c.ult.ps_3"] = "46c00035VGH", ["c.ole.ps_2"] = "46c00036GH", ["c.ole.ps_3"] = "46c00036VGH", ["c.ule.ps_2"] = "46c00037GH", ["c.ule.ps_3"] = "46c00037VGH", ["c.sf.ps_2"] = "46c00038GH", ["c.sf.ps_3"] = "46c00038VGH", ["c.ngle.ps_2"] = "46c00039GH", ["c.ngle.ps_3"] = "46c00039VGH", ["c.seq.ps_2"] = "46c0003aGH", ["c.seq.ps_3"] = "46c0003aVGH", ["c.ngl.ps_2"] = "46c0003bGH", ["c.ngl.ps_3"] = "46c0003bVGH", ["c.lt.ps_2"] = "46c0003cGH", ["c.lt.ps_3"] = "46c0003cVGH", ["c.nge.ps_2"] = "46c0003dGH", ["c.nge.ps_3"] = "46c0003dVGH", ["c.le.ps_2"] = "46c0003eGH", ["c.le.ps_3"] = "46c0003eVGH", ["c.ngt.ps_2"] = "46c0003fGH", ["c.ngt.ps_3"] = "46c0003fVGH", -- Opcode COP1X. lwxc1_2 = "4c000000FX", ldxc1_2 = "4c000001FX", luxc1_2 = "4c000005FX", swxc1_2 = "4c000008FX", sdxc1_2 = "4c000009FX", suxc1_2 = "4c00000dFX", prefx_2 = "4c00000fMX", ["alnv.ps_4"] = "4c00001eFGHS", ["madd.s_4"] = "4c000020FRGH", ["madd.d_4"] = "4c000021FRGH", ["madd.ps_4"] = "4c000026FRGH", ["msub.s_4"] = "4c000028FRGH", ["msub.d_4"] = "4c000029FRGH", ["msub.ps_4"] = "4c00002eFRGH", ["nmadd.s_4"] = "4c000030FRGH", ["nmadd.d_4"] = "4c000031FRGH", ["nmadd.ps_4"] = "4c000036FRGH", ["nmsub.s_4"] = "4c000038FRGH", ["nmsub.d_4"] = "4c000039FRGH", ["nmsub.ps_4"] = "4c00003eFRGH", }) do map_op[k] = v end end ------------------------------------------------------------------------------ local function parse_gpr(expr) local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") local tp = map_type[tname or expr] if tp then local reg = ovreg or tp.reg if not reg then werror("type `"..(tname or expr).."' needs a register override") end expr = reg end local r = match(expr, "^r([1-3]?[0-9])$") if r then r = tonumber(r) if r <= 31 then return r, tp end end werror("bad register name `"..expr.."'") end local function parse_fpr(expr) local r = match(expr, "^f([1-3]?[0-9])$") if r then r = tonumber(r) if r <= 31 then return r end end werror("bad register name `"..expr.."'") end local function parse_imm(imm, bits, shift, scale, signed, action) local n = tonumber(imm) if n then local m = sar(n, scale) if shl(m, scale) == n then if signed then local s = sar(m, bits-1) if s == 0 then return shl(m, shift) elseif s == -1 then return shl(m + shl(1, bits), shift) end else if sar(m, bits) == 0 then return shl(m, shift) end end end werror("out of range immediate `"..imm.."'") elseif match(imm, "^[rf]([1-3]?[0-9])$") or match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then werror("expected immediate operand, got register") else waction(action or "IMM", (signed and 32768 or 0)+shl(scale, 10)+shl(bits, 5)+shift, imm) return 0 end end local function parse_disp(disp) local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") if imm then local r = shl(parse_gpr(reg), 21) local extname = match(imm, "^extern%s+(%S+)$") if extname then waction("REL_EXT", map_extern[extname], nil, 1) return r else return r + parse_imm(imm, 16, 0, 0, true) end end local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then local r, tp = parse_gpr(reg) if tp then waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) return shl(r, 21) end end werror("bad displacement `"..disp.."'") end local function parse_index(idx) local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$") if rt then rt = parse_gpr(rt) rs = parse_gpr(rs) return shl(rt, 16) + shl(rs, 21) end werror("bad index `"..idx.."'") end local function parse_label(label, def) local prefix = sub(label, 1, 2) -- =>label (pc label reference) if prefix == "=>" then return "PC", 0, sub(label, 3) end -- ->name (global label reference) if prefix == "->" then return "LG", map_global[sub(label, 3)] end if def then -- [1-9] (local label definition) if match(label, "^[1-9]$") then return "LG", 10+tonumber(label) end else -- [<>][1-9] (local label reference) local dir, lnum = match(label, "^([<>])([1-9])$") if dir then -- Fwd: 1-9, Bkwd: 11-19. return "LG", lnum + (dir == ">" and 0 or 10) end -- extern label (extern label reference) local extname = match(label, "^extern%s+(%S+)$") if extname then return "EXT", map_extern[extname] end end werror("bad label `"..label.."'") end ------------------------------------------------------------------------------ -- Handle opcodes defined with template strings. map_op[".template__"] = function(params, template, nparams) if not params then return sub(template, 9) end local op = tonumber(sub(template, 1, 8), 16) local n = 1 -- Limit number of section buffer positions used by a single dasm_put(). -- A single opcode needs a maximum of 2 positions (ins/ext). if secpos+2 > maxsecpos then wflush() end local pos = wpos() -- Process each character. for p in gmatch(sub(template, 9), ".") do if p == "D" then op = op + shl(parse_gpr(params[n]), 11); n = n + 1 elseif p == "T" then op = op + shl(parse_gpr(params[n]), 16); n = n + 1 elseif p == "S" then op = op + shl(parse_gpr(params[n]), 21); n = n + 1 elseif p == "F" then op = op + shl(parse_fpr(params[n]), 6); n = n + 1 elseif p == "G" then op = op + shl(parse_fpr(params[n]), 11); n = n + 1 elseif p == "H" then op = op + shl(parse_fpr(params[n]), 16); n = n + 1 elseif p == "R" then op = op + shl(parse_fpr(params[n]), 21); n = n + 1 elseif p == "I" then op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 elseif p == "U" then op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 elseif p == "O" then op = op + parse_disp(params[n]); n = n + 1 elseif p == "X" then op = op + parse_index(params[n]); n = n + 1 elseif p == "B" or p == "J" or p == "K" or p == "L" then local mode, m, s = parse_label(params[n], false) if p == "J" then m = m + 0xa800 elseif p == "K" then m = m + 0x5000 elseif p == "L" then m = m + 0xa000 end waction("REL_"..mode, m, s, 1) n = n + 1 elseif p == "A" then op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1 elseif p == "a" then local m = parse_imm(params[n], 6, 6, 0, false, "IMMS"); n = n + 1 op = op + band(m, 0x7c0) + band(shr(m, 9), 4) elseif p == "M" then op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1 elseif p == "N" then op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 elseif p == "C" then op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1 elseif p == "V" then op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1 elseif p == "W" then op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1 elseif p == "Y" then op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1 elseif p == "Z" then op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1 elseif p == "=" then n = n - 1 -- Re-use previous parameter for next template char. else assert(false) end end wputpos(pos, op) end ------------------------------------------------------------------------------ -- Pseudo-opcode to mark the position where the action list is to be emitted. map_op[".actionlist_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeactions(out, name) end) end -- Pseudo-opcode to mark the position where the global enum is to be emitted. map_op[".globals_1"] = function(params) if not params then return "prefix" end local prefix = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobals(out, prefix) end) end -- Pseudo-opcode to mark the position where the global names are to be emitted. map_op[".globalnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobalnames(out, name) end) end -- Pseudo-opcode to mark the position where the extern names are to be emitted. map_op[".externnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeexternnames(out, name) end) end ------------------------------------------------------------------------------ -- Label pseudo-opcode (converted from trailing colon form). map_op[".label_1"] = function(params) if not params then return "[1-9] | ->global | =>pcexpr" end if secpos+1 > maxsecpos then wflush() end local mode, n, s = parse_label(params[1], true) if mode == "EXT" then werror("bad label definition") end waction("LABEL_"..mode, n, s, 1) end ------------------------------------------------------------------------------ -- Pseudo-opcodes for data storage. map_op[".long_*"] = function(params) if not params then return "imm..." end for _,p in ipairs(params) do local n = tonumber(p) if not n then werror("bad immediate `"..p.."'") end if n < 0 then n = n + 2^32 end wputw(n) if secpos+2 > maxsecpos then wflush() end end end -- Alignment pseudo-opcode. map_op[".align_1"] = function(params) if not params then return "numpow2" end if secpos+1 > maxsecpos then wflush() end local align = tonumber(params[1]) if align then local x = align -- Must be a power of 2 in the range (2 ... 256). for i=1,8 do x = x / 2 if x == 1 then waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. return end end end werror("bad alignment") end ------------------------------------------------------------------------------ -- Pseudo-opcode for (primitive) type definitions (map to C types). map_op[".type_3"] = function(params, nparams) if not params then return nparams == 2 and "name, ctype" or "name, ctype, reg" end local name, ctype, reg = params[1], params[2], params[3] if not match(name, "^[%a_][%w_]*$") then werror("bad type name `"..name.."'") end local tp = map_type[name] if tp then werror("duplicate type `"..name.."'") end -- Add #type to defines. A bit unclean to put it in map_archdef. map_archdef["#"..name] = "sizeof("..ctype..")" -- Add new type and emit shortcut define. local num = ctypenum + 1 map_type[name] = { ctype = ctype, ctypefmt = format("Dt%X(%%s)", num), reg = reg, } wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) ctypenum = num end map_op[".type_2"] = map_op[".type_3"] -- Dump type definitions. local function dumptypes(out, lvl) local t = {} for name in pairs(map_type) do t[#t+1] = name end sort(t) out:write("Type definitions:\n") for _,name in ipairs(t) do local tp = map_type[name] local reg = tp.reg or "" out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) end out:write("\n") end ------------------------------------------------------------------------------ -- Set the current section. function _M.section(num) waction("SECTION", num) wflush(true) -- SECTION is a terminal action. end ------------------------------------------------------------------------------ -- Dump architecture description. function _M.dumparch(out) out:write(format("DynASM %s version %s, released %s\n\n", _info.arch, _info.version, _info.release)) dumpactions(out) end -- Dump all user defined elements. function _M.dumpdef(out, lvl) dumptypes(out, lvl) dumpglobals(out, lvl) dumpexterns(out, lvl) end ------------------------------------------------------------------------------ -- Pass callbacks from/to the DynASM core. function _M.passcb(wl, we, wf, ww) wline, werror, wfatal, wwarn = wl, we, wf, ww return wflush end -- Setup the arch-specific module. function _M.setup(arch, opt) g_arch, g_opt = arch, opt end -- Merge the core maps and the arch-specific maps. function _M.mergemaps(map_coreop, map_def) setmetatable(map_op, { __index = map_coreop }) setmetatable(map_def, { __index = map_archdef }) return map_op, map_def end return _M ------------------------------------------------------------------------------ ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_mips64.lua ================================================ ------------------------------------------------------------------------------ -- DynASM MIPS64 module. -- -- Copyright (C) 2005-2022 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------ -- This module just sets 64 bit mode for the combined MIPS/MIPS64 module. -- All the interesting stuff is there. ------------------------------------------------------------------------------ mips64 = true -- Using a global is an ugly, but effective solution. return require("dasm_mips") ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_ppc.h ================================================ /* ** DynASM PPC/PPC64 encoding engine. ** Copyright (C) 2005-2022 Mike Pall. All rights reserved. ** Released under the MIT license. See dynasm.lua for full copyright notice. */ #include #include #include #include #define DASM_ARCH "ppc" #ifndef DASM_EXTERN #define DASM_EXTERN(a,b,c,d) 0 #endif /* Action definitions. */ enum { DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, /* The following actions need a buffer position. */ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, /* The following actions also have an argument. */ DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMSH, DASM__MAX }; /* Maximum number of section buffer positions for a single dasm_put() call. */ #define DASM_MAXSECPOS 25 /* DynASM encoder status codes. Action list offset or number are or'ed in. */ #define DASM_S_OK 0x00000000 #define DASM_S_NOMEM 0x01000000 #define DASM_S_PHASE 0x02000000 #define DASM_S_MATCH_SEC 0x03000000 #define DASM_S_RANGE_I 0x11000000 #define DASM_S_RANGE_SEC 0x12000000 #define DASM_S_RANGE_LG 0x13000000 #define DASM_S_RANGE_PC 0x14000000 #define DASM_S_RANGE_REL 0x15000000 #define DASM_S_UNDEF_LG 0x21000000 #define DASM_S_UNDEF_PC 0x22000000 /* Macros to convert positions (8 bit section + 24 bit index). */ #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) #define DASM_POS2BIAS(pos) ((pos)&0xff000000) #define DASM_SEC2POS(sec) ((sec)<<24) #define DASM_POS2SEC(pos) ((pos)>>24) #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) /* Action list type. */ typedef const unsigned int *dasm_ActList; /* Per-section structure. */ typedef struct dasm_Section { int *rbuf; /* Biased buffer pointer (negative section bias). */ int *buf; /* True buffer pointer. */ size_t bsize; /* Buffer size in bytes. */ int pos; /* Biased buffer position. */ int epos; /* End of biased buffer position - max single put. */ int ofs; /* Byte offset into section. */ } dasm_Section; /* Core structure holding the DynASM encoding state. */ struct dasm_State { size_t psize; /* Allocated size of this structure. */ dasm_ActList actionlist; /* Current actionlist pointer. */ int *lglabels; /* Local/global chain/pos ptrs. */ size_t lgsize; int *pclabels; /* PC label chains/pos ptrs. */ size_t pcsize; void **globals; /* Array of globals (bias -10). */ dasm_Section *section; /* Pointer to active section. */ size_t codesize; /* Total size of all code sections. */ int maxsection; /* 0 <= sectionidx < maxsection. */ int status; /* Status code. */ dasm_Section sections[1]; /* All sections. Alloc-extended. */ }; /* The size of the core structure depends on the max. number of sections. */ #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) /* Initialize DynASM state. */ void dasm_init(Dst_DECL, int maxsection) { dasm_State *D; size_t psz = 0; int i; Dst_REF = NULL; DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); D = Dst_REF; D->psize = psz; D->lglabels = NULL; D->lgsize = 0; D->pclabels = NULL; D->pcsize = 0; D->globals = NULL; D->maxsection = maxsection; for (i = 0; i < maxsection; i++) { D->sections[i].buf = NULL; /* Need this for pass3. */ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); D->sections[i].bsize = 0; D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ } } /* Free DynASM state. */ void dasm_free(Dst_DECL) { dasm_State *D = Dst_REF; int i; for (i = 0; i < D->maxsection; i++) if (D->sections[i].buf) DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); DASM_M_FREE(Dst, D, D->psize); } /* Setup global label array. Must be called before dasm_setup(). */ void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) { dasm_State *D = Dst_REF; D->globals = gl - 10; /* Negative bias to compensate for locals. */ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); } /* Grow PC label array. Can be called after dasm_setup(), too. */ void dasm_growpc(Dst_DECL, unsigned int maxpc) { dasm_State *D = Dst_REF; size_t osz = D->pcsize; DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); } /* Setup encoder. */ void dasm_setup(Dst_DECL, const void *actionlist) { dasm_State *D = Dst_REF; int i; D->actionlist = (dasm_ActList)actionlist; D->status = DASM_S_OK; D->section = &D->sections[0]; memset((void *)D->lglabels, 0, D->lgsize); if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); for (i = 0; i < D->maxsection; i++) { D->sections[i].pos = DASM_SEC2POS(i); D->sections[i].ofs = 0; } } #ifdef DASM_CHECKS #define CK(x, st) \ do { if (!(x)) { \ D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) #define CKPL(kind, st) \ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) #else #define CK(x, st) ((void)0) #define CKPL(kind, st) ((void)0) #endif /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ void dasm_put(Dst_DECL, int start, ...) { va_list ap; dasm_State *D = Dst_REF; dasm_ActList p = D->actionlist + start; dasm_Section *sec = D->section; int pos = sec->pos, ofs = sec->ofs; int *b; if (pos >= sec->epos) { DASM_M_GROW(Dst, int, sec->buf, sec->bsize, sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); sec->rbuf = sec->buf - DASM_POS2BIAS(pos); sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); } b = sec->rbuf; b[pos++] = start; va_start(ap, start); while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16); if (action >= DASM__MAX) { ofs += 4; } else { int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; switch (action) { case DASM_STOP: goto stop; case DASM_SECTION: n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; goto stop; case DASM_ESC: p++; ofs += 4; break; case DASM_REL_EXT: break; case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; case DASM_REL_LG: n = (ins & 2047) - 10; pl = D->lglabels + n; /* Bkwd rel or global. */ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } pl += 10; n = *pl; if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ goto linkrel; case DASM_REL_PC: pl = D->pclabels + n; CKPL(pc, PC); putrel: n = *pl; if (n < 0) { /* Label exists. Get label pos and store it. */ b[pos] = -n; } else { linkrel: b[pos] = n; /* Else link to rel chain, anchored at label. */ *pl = pos; } pos++; break; case DASM_LABEL_LG: pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; case DASM_LABEL_PC: pl = D->pclabels + n; CKPL(pc, PC); putlabel: n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } *pl = -pos; /* Label exists now. */ b[pos++] = ofs; /* Store pass1 offset estimate. */ break; case DASM_IMM: #ifdef DASM_CHECKS CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); #endif n >>= ((ins>>10)&31); #ifdef DASM_CHECKS if (ins & 0x8000) CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); else CK((n>>((ins>>5)&31)) == 0, RANGE_I); #endif b[pos++] = n; break; case DASM_IMMSH: CK((n >> 6) == 0, RANGE_I); b[pos++] = n; break; } } } stop: va_end(ap); sec->pos = pos; sec->ofs = ofs; } #undef CK /* Pass 2: Link sections, shrink aligns, fix label offsets. */ int dasm_link(Dst_DECL, size_t *szp) { dasm_State *D = Dst_REF; int secnum; int ofs = 0; #ifdef DASM_CHECKS *szp = 0; if (D->status != DASM_S_OK) return D->status; { int pc; for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; } #endif { /* Handle globals not defined in this translation unit. */ int idx; for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { int n = D->lglabels[idx]; /* Undefined label: Collapse rel chain and replace with marker (< 0). */ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } } } /* Combine all code sections. No support for data sections (yet). */ for (secnum = 0; secnum < D->maxsection; secnum++) { dasm_Section *sec = D->sections + secnum; int *b = sec->rbuf; int pos = DASM_SEC2POS(secnum); int lastpos = sec->pos; while (pos != lastpos) { dasm_ActList p = D->actionlist + b[pos++]; while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16); switch (action) { case DASM_STOP: case DASM_SECTION: goto stop; case DASM_ESC: p++; break; case DASM_REL_EXT: break; case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; case DASM_REL_LG: case DASM_REL_PC: pos++; break; case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; case DASM_IMM: case DASM_IMMSH: pos++; break; } } stop: (void)0; } ofs += sec->ofs; /* Next section starts right after current section. */ } D->codesize = ofs; /* Total size of all code sections */ *szp = ofs; return DASM_S_OK; } #ifdef DASM_CHECKS #define CK(x, st) \ do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) #else #define CK(x, st) ((void)0) #endif /* Pass 3: Encode sections. */ int dasm_encode(Dst_DECL, void *buffer) { dasm_State *D = Dst_REF; char *base = (char *)buffer; unsigned int *cp = (unsigned int *)buffer; int secnum; /* Encode all code sections. No support for data sections (yet). */ for (secnum = 0; secnum < D->maxsection; secnum++) { dasm_Section *sec = D->sections + secnum; int *b = sec->buf; int *endb = sec->rbuf + sec->pos; while (b != endb) { dasm_ActList p = D->actionlist + *b++; while (1) { unsigned int ins = *p++; unsigned int action = (ins >> 16); int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; switch (action) { case DASM_STOP: case DASM_SECTION: goto stop; case DASM_ESC: *cp++ = *p++; break; case DASM_REL_EXT: n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4; goto patchrel; case DASM_ALIGN: ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; break; case DASM_REL_LG: if (n < 0) { n = (int)((ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp); goto patchrel; } /* fallthrough */ case DASM_REL_PC: CK(n >= 0, UNDEF_PC); n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); patchrel: CK((n & 3) == 0 && (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >> ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL); cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc)); break; case DASM_LABEL_LG: ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); break; case DASM_LABEL_PC: break; case DASM_IMM: cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); break; case DASM_IMMSH: cp[-1] |= (ins & 1) ? ((n&31)<<11)|((n&32)>>4) : ((n&31)<<6)|(n&32); break; default: *cp++ = ins; break; } } stop: (void)0; } } if (base + D->codesize != (char *)cp) /* Check for phase errors. */ return DASM_S_PHASE; return DASM_S_OK; } #undef CK /* Get PC label offset. */ int dasm_getpclabel(Dst_DECL, unsigned int pc) { dasm_State *D = Dst_REF; if (pc*sizeof(int) < D->pcsize) { int pos = D->pclabels[pc]; if (pos < 0) return *DASM_POS2PTR(D, -pos); if (pos > 0) return -1; /* Undefined. */ } return -2; /* Unused or out of range. */ } #ifdef DASM_CHECKS /* Optional sanity checker to call between isolated encoding steps. */ int dasm_checkstep(Dst_DECL, int secmatch) { dasm_State *D = Dst_REF; if (D->status == DASM_S_OK) { int i; for (i = 1; i <= 9; i++) { if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } D->lglabels[i] = 0; } } if (D->status == DASM_S_OK && secmatch >= 0 && D->section != &D->sections[secmatch]) D->status = DASM_S_MATCH_SEC|(D->section-D->sections); return D->status; } #endif ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_ppc.lua ================================================ ------------------------------------------------------------------------------ -- DynASM PPC/PPC64 module. -- -- Copyright (C) 2005-2022 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. -- -- Support for various extensions contributed by Caio Souza Oliveira. ------------------------------------------------------------------------------ -- Module information: local _info = { arch = "ppc", description = "DynASM PPC module", version = "1.5.0", vernum = 10500, release = "2021-05-02", author = "Mike Pall", license = "MIT", } -- Exported glue functions for the arch-specific module. local _M = { _info = _info } -- Cache library functions. local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs local assert, setmetatable = assert, setmetatable local _s = string local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char local match, gmatch = _s.match, _s.gmatch local concat, sort = table.concat, table.sort local bit = bit or require("bit") local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift local tohex = bit.tohex -- Inherited tables and callbacks. local g_opt, g_arch local wline, werror, wfatal, wwarn -- Action name list. -- CHECK: Keep this in sync with the C code! local action_names = { "STOP", "SECTION", "ESC", "REL_EXT", "ALIGN", "REL_LG", "LABEL_LG", "REL_PC", "LABEL_PC", "IMM", "IMMSH" } -- Maximum number of section buffer positions for dasm_put(). -- CHECK: Keep this in sync with the C code! local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. -- Action name -> action number. local map_action = {} for n,name in ipairs(action_names) do map_action[name] = n-1 end -- Action list buffer. local actlist = {} -- Argument list for next dasm_put(). Start with offset 0 into action list. local actargs = { 0 } -- Current number of section buffer positions for dasm_put(). local secpos = 1 ------------------------------------------------------------------------------ -- Dump action names and numbers. local function dumpactions(out) out:write("DynASM encoding engine action codes:\n") for n,name in ipairs(action_names) do local num = map_action[name] out:write(format(" %-10s %02X %d\n", name, num, num)) end out:write("\n") end -- Write action list buffer as a huge static C array. local function writeactions(out, name) local nn = #actlist if nn == 0 then nn = 1; actlist[0] = map_action.STOP end out:write("static const unsigned int ", name, "[", nn, "] = {\n") for i = 1,nn-1 do assert(out:write("0x", tohex(actlist[i]), ",\n")) end assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) end ------------------------------------------------------------------------------ -- Add word to action list. local function wputxw(n) assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") actlist[#actlist+1] = n end -- Add action to list with optional arg. Advance buffer pos, too. local function waction(action, val, a, num) local w = assert(map_action[action], "bad action name `"..action.."'") wputxw(w * 0x10000 + (val or 0)) if a then actargs[#actargs+1] = a end if a or num then secpos = secpos + (num or 1) end end -- Flush action list (intervening C code or buffer pos overflow). local function wflush(term) if #actlist == actargs[1] then return end -- Nothing to flush. if not term then waction("STOP") end -- Terminate action list. wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). secpos = 1 -- The actionlist offset occupies a buffer position, too. end -- Put escaped word. local function wputw(n) if n <= 0xffffff then waction("ESC") end wputxw(n) end -- Reserve position for word. local function wpos() local pos = #actlist+1 actlist[pos] = "" return pos end -- Store word to reserved position. local function wputpos(pos, n) assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") actlist[pos] = n end ------------------------------------------------------------------------------ -- Global label name -> global label number. With auto assignment on 1st use. local next_global = 20 local map_global = setmetatable({}, { __index = function(t, name) if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end local n = next_global if n > 2047 then werror("too many global labels") end next_global = n + 1 t[name] = n return n end}) -- Dump global labels. local function dumpglobals(out, lvl) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("Global labels:\n") for i=20,next_global-1 do out:write(format(" %s\n", t[i])) end out:write("\n") end -- Write global label enum. local function writeglobals(out, prefix) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("enum {\n") for i=20,next_global-1 do out:write(" ", prefix, t[i], ",\n") end out:write(" ", prefix, "_MAX\n};\n") end -- Write global label names. local function writeglobalnames(out, name) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("static const char *const ", name, "[] = {\n") for i=20,next_global-1 do out:write(" \"", t[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Extern label name -> extern label number. With auto assignment on 1st use. local next_extern = 0 local map_extern_ = {} local map_extern = setmetatable({}, { __index = function(t, name) -- No restrictions on the name for now. local n = next_extern if n > 2047 then werror("too many extern labels") end next_extern = n + 1 t[name] = n map_extern_[n] = name return n end}) -- Dump extern labels. local function dumpexterns(out, lvl) out:write("Extern labels:\n") for i=0,next_extern-1 do out:write(format(" %s\n", map_extern_[i])) end out:write("\n") end -- Write extern label names. local function writeexternnames(out, name) out:write("static const char *const ", name, "[] = {\n") for i=0,next_extern-1 do out:write(" \"", map_extern_[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Arch-specific maps. local map_archdef = { sp = "r1" } -- Ext. register name -> int. name. local map_type = {} -- Type name -> { ctype, reg } local ctypenum = 0 -- Type number (for Dt... macros). -- Reverse defines for registers. function _M.revdef(s) if s == "r1" then return "sp" end return s end local map_cond = { lt = 0, gt = 1, eq = 2, so = 3, ge = 4, le = 5, ne = 6, ns = 7, } ------------------------------------------------------------------------------ local map_op, op_template local function op_alias(opname, f) return function(params, nparams) if not params then return "-> "..opname:sub(1, -3) end f(params, nparams) op_template(params, map_op[opname], nparams) end end -- Template strings for PPC instructions. map_op = { tdi_3 = "08000000ARI", twi_3 = "0c000000ARI", mulli_3 = "1c000000RRI", subfic_3 = "20000000RRI", cmplwi_3 = "28000000XRU", cmplwi_2 = "28000000-RU", cmpldi_3 = "28200000XRU", cmpldi_2 = "28200000-RU", cmpwi_3 = "2c000000XRI", cmpwi_2 = "2c000000-RI", cmpdi_3 = "2c200000XRI", cmpdi_2 = "2c200000-RI", addic_3 = "30000000RRI", ["addic._3"] = "34000000RRI", addi_3 = "38000000RR0I", li_2 = "38000000RI", la_2 = "38000000RD", addis_3 = "3c000000RR0I", lis_2 = "3c000000RI", lus_2 = "3c000000RU", bc_3 = "40000000AAK", bcl_3 = "40000001AAK", bdnz_1 = "42000000K", bdz_1 = "42400000K", sc_0 = "44000000", b_1 = "48000000J", bl_1 = "48000001J", rlwimi_5 = "50000000RR~AAA.", rlwinm_5 = "54000000RR~AAA.", rlwnm_5 = "5c000000RR~RAA.", ori_3 = "60000000RR~U", nop_0 = "60000000", oris_3 = "64000000RR~U", xori_3 = "68000000RR~U", xoris_3 = "6c000000RR~U", ["andi._3"] = "70000000RR~U", ["andis._3"] = "74000000RR~U", lwz_2 = "80000000RD", lwzu_2 = "84000000RD", lbz_2 = "88000000RD", lbzu_2 = "8c000000RD", stw_2 = "90000000RD", stwu_2 = "94000000RD", stb_2 = "98000000RD", stbu_2 = "9c000000RD", lhz_2 = "a0000000RD", lhzu_2 = "a4000000RD", lha_2 = "a8000000RD", lhau_2 = "ac000000RD", sth_2 = "b0000000RD", sthu_2 = "b4000000RD", lmw_2 = "b8000000RD", stmw_2 = "bc000000RD", lfs_2 = "c0000000FD", lfsu_2 = "c4000000FD", lfd_2 = "c8000000FD", lfdu_2 = "cc000000FD", stfs_2 = "d0000000FD", stfsu_2 = "d4000000FD", stfd_2 = "d8000000FD", stfdu_2 = "dc000000FD", ld_2 = "e8000000RD", -- NYI: displacement must be divisible by 4. ldu_2 = "e8000001RD", lwa_2 = "e8000002RD", std_2 = "f8000000RD", stdu_2 = "f8000001RD", subi_3 = op_alias("addi_3", function(p) p[3] = "-("..p[3]..")" end), subis_3 = op_alias("addis_3", function(p) p[3] = "-("..p[3]..")" end), subic_3 = op_alias("addic_3", function(p) p[3] = "-("..p[3]..")" end), ["subic._3"] = op_alias("addic._3", function(p) p[3] = "-("..p[3]..")" end), rotlwi_3 = op_alias("rlwinm_5", function(p) p[4] = "0"; p[5] = "31" end), rotrwi_3 = op_alias("rlwinm_5", function(p) p[3] = "32-("..p[3]..")"; p[4] = "0"; p[5] = "31" end), rotlw_3 = op_alias("rlwnm_5", function(p) p[4] = "0"; p[5] = "31" end), slwi_3 = op_alias("rlwinm_5", function(p) p[5] = "31-("..p[3]..")"; p[4] = "0" end), srwi_3 = op_alias("rlwinm_5", function(p) p[4] = p[3]; p[3] = "32-("..p[3]..")"; p[5] = "31" end), clrlwi_3 = op_alias("rlwinm_5", function(p) p[4] = p[3]; p[3] = "0"; p[5] = "31" end), clrrwi_3 = op_alias("rlwinm_5", function(p) p[5] = "31-("..p[3]..")"; p[3] = "0"; p[4] = "0" end), -- Primary opcode 4: mulhhwu_3 = "10000010RRR.", machhwu_3 = "10000018RRR.", mulhhw_3 = "10000050RRR.", nmachhw_3 = "1000005cRRR.", machhwsu_3 = "10000098RRR.", machhws_3 = "100000d8RRR.", nmachhws_3 = "100000dcRRR.", mulchwu_3 = "10000110RRR.", macchwu_3 = "10000118RRR.", mulchw_3 = "10000150RRR.", macchw_3 = "10000158RRR.", nmacchw_3 = "1000015cRRR.", macchwsu_3 = "10000198RRR.", macchws_3 = "100001d8RRR.", nmacchws_3 = "100001dcRRR.", mullhw_3 = "10000350RRR.", maclhw_3 = "10000358RRR.", nmaclhw_3 = "1000035cRRR.", maclhwsu_3 = "10000398RRR.", maclhws_3 = "100003d8RRR.", nmaclhws_3 = "100003dcRRR.", machhwuo_3 = "10000418RRR.", nmachhwo_3 = "1000045cRRR.", machhwsuo_3 = "10000498RRR.", machhwso_3 = "100004d8RRR.", nmachhwso_3 = "100004dcRRR.", macchwuo_3 = "10000518RRR.", macchwo_3 = "10000558RRR.", nmacchwo_3 = "1000055cRRR.", macchwsuo_3 = "10000598RRR.", macchwso_3 = "100005d8RRR.", nmacchwso_3 = "100005dcRRR.", maclhwo_3 = "10000758RRR.", nmaclhwo_3 = "1000075cRRR.", maclhwsuo_3 = "10000798RRR.", maclhwso_3 = "100007d8RRR.", nmaclhwso_3 = "100007dcRRR.", vaddubm_3 = "10000000VVV", vmaxub_3 = "10000002VVV", vrlb_3 = "10000004VVV", vcmpequb_3 = "10000006VVV", vmuloub_3 = "10000008VVV", vaddfp_3 = "1000000aVVV", vmrghb_3 = "1000000cVVV", vpkuhum_3 = "1000000eVVV", vmhaddshs_4 = "10000020VVVV", vmhraddshs_4 = "10000021VVVV", vmladduhm_4 = "10000022VVVV", vmsumubm_4 = "10000024VVVV", vmsummbm_4 = "10000025VVVV", vmsumuhm_4 = "10000026VVVV", vmsumuhs_4 = "10000027VVVV", vmsumshm_4 = "10000028VVVV", vmsumshs_4 = "10000029VVVV", vsel_4 = "1000002aVVVV", vperm_4 = "1000002bVVVV", vsldoi_4 = "1000002cVVVP", vpermxor_4 = "1000002dVVVV", vmaddfp_4 = "1000002eVVVV~", vnmsubfp_4 = "1000002fVVVV~", vaddeuqm_4 = "1000003cVVVV", vaddecuq_4 = "1000003dVVVV", vsubeuqm_4 = "1000003eVVVV", vsubecuq_4 = "1000003fVVVV", vadduhm_3 = "10000040VVV", vmaxuh_3 = "10000042VVV", vrlh_3 = "10000044VVV", vcmpequh_3 = "10000046VVV", vmulouh_3 = "10000048VVV", vsubfp_3 = "1000004aVVV", vmrghh_3 = "1000004cVVV", vpkuwum_3 = "1000004eVVV", vadduwm_3 = "10000080VVV", vmaxuw_3 = "10000082VVV", vrlw_3 = "10000084VVV", vcmpequw_3 = "10000086VVV", vmulouw_3 = "10000088VVV", vmuluwm_3 = "10000089VVV", vmrghw_3 = "1000008cVVV", vpkuhus_3 = "1000008eVVV", vaddudm_3 = "100000c0VVV", vmaxud_3 = "100000c2VVV", vrld_3 = "100000c4VVV", vcmpeqfp_3 = "100000c6VVV", vcmpequd_3 = "100000c7VVV", vpkuwus_3 = "100000ceVVV", vadduqm_3 = "10000100VVV", vmaxsb_3 = "10000102VVV", vslb_3 = "10000104VVV", vmulosb_3 = "10000108VVV", vrefp_2 = "1000010aV-V", vmrglb_3 = "1000010cVVV", vpkshus_3 = "1000010eVVV", vaddcuq_3 = "10000140VVV", vmaxsh_3 = "10000142VVV", vslh_3 = "10000144VVV", vmulosh_3 = "10000148VVV", vrsqrtefp_2 = "1000014aV-V", vmrglh_3 = "1000014cVVV", vpkswus_3 = "1000014eVVV", vaddcuw_3 = "10000180VVV", vmaxsw_3 = "10000182VVV", vslw_3 = "10000184VVV", vmulosw_3 = "10000188VVV", vexptefp_2 = "1000018aV-V", vmrglw_3 = "1000018cVVV", vpkshss_3 = "1000018eVVV", vmaxsd_3 = "100001c2VVV", vsl_3 = "100001c4VVV", vcmpgefp_3 = "100001c6VVV", vlogefp_2 = "100001caV-V", vpkswss_3 = "100001ceVVV", vadduhs_3 = "10000240VVV", vminuh_3 = "10000242VVV", vsrh_3 = "10000244VVV", vcmpgtuh_3 = "10000246VVV", vmuleuh_3 = "10000248VVV", vrfiz_2 = "1000024aV-V", vsplth_3 = "1000024cVV3", vupkhsh_2 = "1000024eV-V", vminuw_3 = "10000282VVV", vminud_3 = "100002c2VVV", vcmpgtud_3 = "100002c7VVV", vrfim_2 = "100002caV-V", vcmpgtsb_3 = "10000306VVV", vcfux_3 = "1000030aVVA~", vaddshs_3 = "10000340VVV", vminsh_3 = "10000342VVV", vsrah_3 = "10000344VVV", vcmpgtsh_3 = "10000346VVV", vmulesh_3 = "10000348VVV", vcfsx_3 = "1000034aVVA~", vspltish_2 = "1000034cVS", vupkhpx_2 = "1000034eV-V", vaddsws_3 = "10000380VVV", vminsw_3 = "10000382VVV", vsraw_3 = "10000384VVV", vcmpgtsw_3 = "10000386VVV", vmulesw_3 = "10000388VVV", vctuxs_3 = "1000038aVVA~", vspltisw_2 = "1000038cVS", vminsd_3 = "100003c2VVV", vsrad_3 = "100003c4VVV", vcmpbfp_3 = "100003c6VVV", vcmpgtsd_3 = "100003c7VVV", vctsxs_3 = "100003caVVA~", vupklpx_2 = "100003ceV-V", vsububm_3 = "10000400VVV", ["bcdadd._4"] = "10000401VVVy.", vavgub_3 = "10000402VVV", vand_3 = "10000404VVV", ["vcmpequb._3"] = "10000406VVV", vmaxfp_3 = "1000040aVVV", vsubuhm_3 = "10000440VVV", ["bcdsub._4"] = "10000441VVVy.", vavguh_3 = "10000442VVV", vandc_3 = "10000444VVV", ["vcmpequh._3"] = "10000446VVV", vminfp_3 = "1000044aVVV", vpkudum_3 = "1000044eVVV", vsubuwm_3 = "10000480VVV", vavguw_3 = "10000482VVV", vor_3 = "10000484VVV", ["vcmpequw._3"] = "10000486VVV", vpmsumw_3 = "10000488VVV", ["vcmpeqfp._3"] = "100004c6VVV", ["vcmpequd._3"] = "100004c7VVV", vpkudus_3 = "100004ceVVV", vavgsb_3 = "10000502VVV", vavgsh_3 = "10000542VVV", vorc_3 = "10000544VVV", vbpermq_3 = "1000054cVVV", vpksdus_3 = "1000054eVVV", vavgsw_3 = "10000582VVV", vsld_3 = "100005c4VVV", ["vcmpgefp._3"] = "100005c6VVV", vpksdss_3 = "100005ceVVV", vsububs_3 = "10000600VVV", mfvscr_1 = "10000604V--", vsum4ubs_3 = "10000608VVV", vsubuhs_3 = "10000640VVV", mtvscr_1 = "10000644--V", ["vcmpgtuh._3"] = "10000646VVV", vsum4shs_3 = "10000648VVV", vupkhsw_2 = "1000064eV-V", vsubuws_3 = "10000680VVV", vshasigmaw_4 = "10000682VVYp", veqv_3 = "10000684VVV", vsum2sws_3 = "10000688VVV", vmrgow_3 = "1000068cVVV", vshasigmad_4 = "100006c2VVYp", vsrd_3 = "100006c4VVV", ["vcmpgtud._3"] = "100006c7VVV", vupklsw_2 = "100006ceV-V", vupkslw_2 = "100006ceV-V", vsubsbs_3 = "10000700VVV", vclzb_2 = "10000702V-V", vpopcntb_2 = "10000703V-V", ["vcmpgtsb._3"] = "10000706VVV", vsum4sbs_3 = "10000708VVV", vsubshs_3 = "10000740VVV", vclzh_2 = "10000742V-V", vpopcnth_2 = "10000743V-V", ["vcmpgtsh._3"] = "10000746VVV", vsubsws_3 = "10000780VVV", vclzw_2 = "10000782V-V", vpopcntw_2 = "10000783V-V", ["vcmpgtsw._3"] = "10000786VVV", vsumsws_3 = "10000788VVV", vmrgew_3 = "1000078cVVV", vclzd_2 = "100007c2V-V", vpopcntd_2 = "100007c3V-V", ["vcmpbfp._3"] = "100007c6VVV", ["vcmpgtsd._3"] = "100007c7VVV", -- Primary opcode 19: mcrf_2 = "4c000000XX", isync_0 = "4c00012c", crnor_3 = "4c000042CCC", crnot_2 = "4c000042CC=", crandc_3 = "4c000102CCC", crxor_3 = "4c000182CCC", crclr_1 = "4c000182C==", crnand_3 = "4c0001c2CCC", crand_3 = "4c000202CCC", creqv_3 = "4c000242CCC", crset_1 = "4c000242C==", crorc_3 = "4c000342CCC", cror_3 = "4c000382CCC", crmove_2 = "4c000382CC=", bclr_2 = "4c000020AA", bclrl_2 = "4c000021AA", bcctr_2 = "4c000420AA", bcctrl_2 = "4c000421AA", bctar_2 = "4c000460AA", bctarl_2 = "4c000461AA", blr_0 = "4e800020", blrl_0 = "4e800021", bctr_0 = "4e800420", bctrl_0 = "4e800421", -- Primary opcode 31: cmpw_3 = "7c000000XRR", cmpw_2 = "7c000000-RR", cmpd_3 = "7c200000XRR", cmpd_2 = "7c200000-RR", tw_3 = "7c000008ARR", lvsl_3 = "7c00000cVRR", subfc_3 = "7c000010RRR.", subc_3 = "7c000010RRR~.", mulhdu_3 = "7c000012RRR.", addc_3 = "7c000014RRR.", mulhwu_3 = "7c000016RRR.", isel_4 = "7c00001eRRRC", isellt_3 = "7c00001eRRR", iselgt_3 = "7c00005eRRR", iseleq_3 = "7c00009eRRR", mfcr_1 = "7c000026R", mfocrf_2 = "7c100026RG", mtcrf_2 = "7c000120GR", mtocrf_2 = "7c100120GR", lwarx_3 = "7c000028RR0R", ldx_3 = "7c00002aRR0R", lwzx_3 = "7c00002eRR0R", slw_3 = "7c000030RR~R.", cntlzw_2 = "7c000034RR~", sld_3 = "7c000036RR~R.", and_3 = "7c000038RR~R.", cmplw_3 = "7c000040XRR", cmplw_2 = "7c000040-RR", cmpld_3 = "7c200040XRR", cmpld_2 = "7c200040-RR", lvsr_3 = "7c00004cVRR", subf_3 = "7c000050RRR.", sub_3 = "7c000050RRR~.", lbarx_3 = "7c000068RR0R", ldux_3 = "7c00006aRR0R", dcbst_2 = "7c00006c-RR", lwzux_3 = "7c00006eRR0R", cntlzd_2 = "7c000074RR~", andc_3 = "7c000078RR~R.", td_3 = "7c000088ARR", lvewx_3 = "7c00008eVRR", mulhd_3 = "7c000092RRR.", addg6s_3 = "7c000094RRR", mulhw_3 = "7c000096RRR.", dlmzb_3 = "7c00009cRR~R.", ldarx_3 = "7c0000a8RR0R", dcbf_2 = "7c0000ac-RR", lbzx_3 = "7c0000aeRR0R", lvx_3 = "7c0000ceVRR", neg_2 = "7c0000d0RR.", lharx_3 = "7c0000e8RR0R", lbzux_3 = "7c0000eeRR0R", popcntb_2 = "7c0000f4RR~", not_2 = "7c0000f8RR~%.", nor_3 = "7c0000f8RR~R.", stvebx_3 = "7c00010eVRR", subfe_3 = "7c000110RRR.", sube_3 = "7c000110RRR~.", adde_3 = "7c000114RRR.", stdx_3 = "7c00012aRR0R", ["stwcx._3"] = "7c00012dRR0R.", stwx_3 = "7c00012eRR0R", prtyw_2 = "7c000134RR~", stvehx_3 = "7c00014eVRR", stdux_3 = "7c00016aRR0R", ["stqcx._3"] = "7c00016dR:R0R.", stwux_3 = "7c00016eRR0R", prtyd_2 = "7c000174RR~", stvewx_3 = "7c00018eVRR", subfze_2 = "7c000190RR.", addze_2 = "7c000194RR.", ["stdcx._3"] = "7c0001adRR0R.", stbx_3 = "7c0001aeRR0R", stvx_3 = "7c0001ceVRR", subfme_2 = "7c0001d0RR.", mulld_3 = "7c0001d2RRR.", addme_2 = "7c0001d4RR.", mullw_3 = "7c0001d6RRR.", dcbtst_2 = "7c0001ec-RR", stbux_3 = "7c0001eeRR0R", bpermd_3 = "7c0001f8RR~R", lvepxl_3 = "7c00020eVRR", add_3 = "7c000214RRR.", lqarx_3 = "7c000228R:R0R", dcbt_2 = "7c00022c-RR", lhzx_3 = "7c00022eRR0R", cdtbcd_2 = "7c000234RR~", eqv_3 = "7c000238RR~R.", lvepx_3 = "7c00024eVRR", eciwx_3 = "7c00026cRR0R", lhzux_3 = "7c00026eRR0R", cbcdtd_2 = "7c000274RR~", xor_3 = "7c000278RR~R.", mfspefscr_1 = "7c0082a6R", mfxer_1 = "7c0102a6R", mflr_1 = "7c0802a6R", mfctr_1 = "7c0902a6R", lwax_3 = "7c0002aaRR0R", lhax_3 = "7c0002aeRR0R", mftb_1 = "7c0c42e6R", mftbu_1 = "7c0d42e6R", lvxl_3 = "7c0002ceVRR", lwaux_3 = "7c0002eaRR0R", lhaux_3 = "7c0002eeRR0R", popcntw_2 = "7c0002f4RR~", divdeu_3 = "7c000312RRR.", divweu_3 = "7c000316RRR.", sthx_3 = "7c00032eRR0R", orc_3 = "7c000338RR~R.", ecowx_3 = "7c00036cRR0R", sthux_3 = "7c00036eRR0R", or_3 = "7c000378RR~R.", mr_2 = "7c000378RR~%.", divdu_3 = "7c000392RRR.", divwu_3 = "7c000396RRR.", mtspefscr_1 = "7c0083a6R", mtxer_1 = "7c0103a6R", mtlr_1 = "7c0803a6R", mtctr_1 = "7c0903a6R", dcbi_2 = "7c0003ac-RR", nand_3 = "7c0003b8RR~R.", dsn_2 = "7c0003c6-RR", stvxl_3 = "7c0003ceVRR", divd_3 = "7c0003d2RRR.", divw_3 = "7c0003d6RRR.", popcntd_2 = "7c0003f4RR~", cmpb_3 = "7c0003f8RR~R.", mcrxr_1 = "7c000400X", lbdx_3 = "7c000406RRR", subfco_3 = "7c000410RRR.", subco_3 = "7c000410RRR~.", addco_3 = "7c000414RRR.", ldbrx_3 = "7c000428RR0R", lswx_3 = "7c00042aRR0R", lwbrx_3 = "7c00042cRR0R", lfsx_3 = "7c00042eFR0R", srw_3 = "7c000430RR~R.", srd_3 = "7c000436RR~R.", lhdx_3 = "7c000446RRR", subfo_3 = "7c000450RRR.", subo_3 = "7c000450RRR~.", lfsux_3 = "7c00046eFR0R", lwdx_3 = "7c000486RRR", lswi_3 = "7c0004aaRR0A", sync_0 = "7c0004ac", lwsync_0 = "7c2004ac", ptesync_0 = "7c4004ac", lfdx_3 = "7c0004aeFR0R", lddx_3 = "7c0004c6RRR", nego_2 = "7c0004d0RR.", lfdux_3 = "7c0004eeFR0R", stbdx_3 = "7c000506RRR", subfeo_3 = "7c000510RRR.", subeo_3 = "7c000510RRR~.", addeo_3 = "7c000514RRR.", stdbrx_3 = "7c000528RR0R", stswx_3 = "7c00052aRR0R", stwbrx_3 = "7c00052cRR0R", stfsx_3 = "7c00052eFR0R", sthdx_3 = "7c000546RRR", ["stbcx._3"] = "7c00056dRRR", stfsux_3 = "7c00056eFR0R", stwdx_3 = "7c000586RRR", subfzeo_2 = "7c000590RR.", addzeo_2 = "7c000594RR.", stswi_3 = "7c0005aaRR0A", ["sthcx._3"] = "7c0005adRRR", stfdx_3 = "7c0005aeFR0R", stddx_3 = "7c0005c6RRR", subfmeo_2 = "7c0005d0RR.", mulldo_3 = "7c0005d2RRR.", addmeo_2 = "7c0005d4RR.", mullwo_3 = "7c0005d6RRR.", dcba_2 = "7c0005ec-RR", stfdux_3 = "7c0005eeFR0R", stvepxl_3 = "7c00060eVRR", addo_3 = "7c000614RRR.", lhbrx_3 = "7c00062cRR0R", lfdpx_3 = "7c00062eF:RR", sraw_3 = "7c000630RR~R.", srad_3 = "7c000634RR~R.", lfddx_3 = "7c000646FRR", stvepx_3 = "7c00064eVRR", srawi_3 = "7c000670RR~A.", sradi_3 = "7c000674RR~H.", eieio_0 = "7c0006ac", lfiwax_3 = "7c0006aeFR0R", divdeuo_3 = "7c000712RRR.", divweuo_3 = "7c000716RRR.", sthbrx_3 = "7c00072cRR0R", stfdpx_3 = "7c00072eF:RR", extsh_2 = "7c000734RR~.", stfddx_3 = "7c000746FRR", divdeo_3 = "7c000752RRR.", divweo_3 = "7c000756RRR.", extsb_2 = "7c000774RR~.", divduo_3 = "7c000792RRR.", divwou_3 = "7c000796RRR.", icbi_2 = "7c0007ac-RR", stfiwx_3 = "7c0007aeFR0R", extsw_2 = "7c0007b4RR~.", divdo_3 = "7c0007d2RRR.", divwo_3 = "7c0007d6RRR.", dcbz_2 = "7c0007ec-RR", ["tbegin._1"] = "7c00051d1", ["tbegin._0"] = "7c00051d", ["tend._1"] = "7c00055dY", ["tend._0"] = "7c00055d", ["tendall._0"] = "7e00055d", tcheck_1 = "7c00059cX", ["tsr._1"] = "7c0005dd1", ["tsuspend._0"] = "7c0005dd", ["tresume._0"] = "7c2005dd", ["tabortwc._3"] = "7c00061dARR", ["tabortdc._3"] = "7c00065dARR", ["tabortwci._3"] = "7c00069dARS", ["tabortdci._3"] = "7c0006ddARS", ["tabort._1"] = "7c00071d-R-", ["treclaim._1"] = "7c00075d-R", ["trechkpt._0"] = "7c0007dd", lxsiwzx_3 = "7c000018QRR", lxsiwax_3 = "7c000098QRR", mfvsrd_2 = "7c000066-Rq", mfvsrwz_2 = "7c0000e6-Rq", stxsiwx_3 = "7c000118QRR", mtvsrd_2 = "7c000166QR", mtvsrwa_2 = "7c0001a6QR", lxvdsx_3 = "7c000298QRR", lxsspx_3 = "7c000418QRR", lxsdx_3 = "7c000498QRR", stxsspx_3 = "7c000518QRR", stxsdx_3 = "7c000598QRR", lxvw4x_3 = "7c000618QRR", lxvd2x_3 = "7c000698QRR", stxvw4x_3 = "7c000718QRR", stxvd2x_3 = "7c000798QRR", -- Primary opcode 30: rldicl_4 = "78000000RR~HM.", rldicr_4 = "78000004RR~HM.", rldic_4 = "78000008RR~HM.", rldimi_4 = "7800000cRR~HM.", rldcl_4 = "78000010RR~RM.", rldcr_4 = "78000012RR~RM.", rotldi_3 = op_alias("rldicl_4", function(p) p[4] = "0" end), rotrdi_3 = op_alias("rldicl_4", function(p) p[3] = "64-("..p[3]..")"; p[4] = "0" end), rotld_3 = op_alias("rldcl_4", function(p) p[4] = "0" end), sldi_3 = op_alias("rldicr_4", function(p) p[4] = "63-("..p[3]..")" end), srdi_3 = op_alias("rldicl_4", function(p) p[4] = p[3]; p[3] = "64-("..p[3]..")" end), clrldi_3 = op_alias("rldicl_4", function(p) p[4] = p[3]; p[3] = "0" end), clrrdi_3 = op_alias("rldicr_4", function(p) p[4] = "63-("..p[3]..")"; p[3] = "0" end), -- Primary opcode 56: lq_2 = "e0000000R:D", -- NYI: displacement must be divisible by 8. -- Primary opcode 57: lfdp_2 = "e4000000F:D", -- NYI: displacement must be divisible by 4. -- Primary opcode 59: fdivs_3 = "ec000024FFF.", fsubs_3 = "ec000028FFF.", fadds_3 = "ec00002aFFF.", fsqrts_2 = "ec00002cF-F.", fres_2 = "ec000030F-F.", fmuls_3 = "ec000032FF-F.", frsqrtes_2 = "ec000034F-F.", fmsubs_4 = "ec000038FFFF~.", fmadds_4 = "ec00003aFFFF~.", fnmsubs_4 = "ec00003cFFFF~.", fnmadds_4 = "ec00003eFFFF~.", fcfids_2 = "ec00069cF-F.", fcfidus_2 = "ec00079cF-F.", dadd_3 = "ec000004FFF.", dqua_4 = "ec000006FFFZ.", dmul_3 = "ec000044FFF.", drrnd_4 = "ec000046FFFZ.", dscli_3 = "ec000084FF6.", dquai_4 = "ec000086SF~FZ.", dscri_3 = "ec0000c4FF6.", drintx_4 = "ec0000c61F~FZ.", dcmpo_3 = "ec000104XFF", dtstex_3 = "ec000144XFF", dtstdc_3 = "ec000184XF6", dtstdg_3 = "ec0001c4XF6", drintn_4 = "ec0001c61F~FZ.", dctdp_2 = "ec000204F-F.", dctfix_2 = "ec000244F-F.", ddedpd_3 = "ec000284ZF~F.", dxex_2 = "ec0002c4F-F.", dsub_3 = "ec000404FFF.", ddiv_3 = "ec000444FFF.", dcmpu_3 = "ec000504XFF", dtstsf_3 = "ec000544XFF", drsp_2 = "ec000604F-F.", dcffix_2 = "ec000644F-F.", denbcd_3 = "ec000684YF~F.", diex_3 = "ec0006c4FFF.", -- Primary opcode 60: xsaddsp_3 = "f0000000QQQ", xsmaddasp_3 = "f0000008QQQ", xxsldwi_4 = "f0000010QQQz", xsrsqrtesp_2 = "f0000028Q-Q", xssqrtsp_2 = "f000002cQ-Q", xxsel_4 = "f0000030QQQQ", xssubsp_3 = "f0000040QQQ", xsmaddmsp_3 = "f0000048QQQ", xxpermdi_4 = "f0000050QQQz", xsresp_2 = "f0000068Q-Q", xsmulsp_3 = "f0000080QQQ", xsmsubasp_3 = "f0000088QQQ", xxmrghw_3 = "f0000090QQQ", xsdivsp_3 = "f00000c0QQQ", xsmsubmsp_3 = "f00000c8QQQ", xsadddp_3 = "f0000100QQQ", xsmaddadp_3 = "f0000108QQQ", xscmpudp_3 = "f0000118XQQ", xscvdpuxws_2 = "f0000120Q-Q", xsrdpi_2 = "f0000124Q-Q", xsrsqrtedp_2 = "f0000128Q-Q", xssqrtdp_2 = "f000012cQ-Q", xssubdp_3 = "f0000140QQQ", xsmaddmdp_3 = "f0000148QQQ", xscmpodp_3 = "f0000158XQQ", xscvdpsxws_2 = "f0000160Q-Q", xsrdpiz_2 = "f0000164Q-Q", xsredp_2 = "f0000168Q-Q", xsmuldp_3 = "f0000180QQQ", xsmsubadp_3 = "f0000188QQQ", xxmrglw_3 = "f0000190QQQ", xsrdpip_2 = "f00001a4Q-Q", xstsqrtdp_2 = "f00001a8X-Q", xsrdpic_2 = "f00001acQ-Q", xsdivdp_3 = "f00001c0QQQ", xsmsubmdp_3 = "f00001c8QQQ", xsrdpim_2 = "f00001e4Q-Q", xstdivdp_3 = "f00001e8XQQ", xvaddsp_3 = "f0000200QQQ", xvmaddasp_3 = "f0000208QQQ", xvcmpeqsp_3 = "f0000218QQQ", xvcvspuxws_2 = "f0000220Q-Q", xvrspi_2 = "f0000224Q-Q", xvrsqrtesp_2 = "f0000228Q-Q", xvsqrtsp_2 = "f000022cQ-Q", xvsubsp_3 = "f0000240QQQ", xvmaddmsp_3 = "f0000248QQQ", xvcmpgtsp_3 = "f0000258QQQ", xvcvspsxws_2 = "f0000260Q-Q", xvrspiz_2 = "f0000264Q-Q", xvresp_2 = "f0000268Q-Q", xvmulsp_3 = "f0000280QQQ", xvmsubasp_3 = "f0000288QQQ", xxspltw_3 = "f0000290QQg~", xvcmpgesp_3 = "f0000298QQQ", xvcvuxwsp_2 = "f00002a0Q-Q", xvrspip_2 = "f00002a4Q-Q", xvtsqrtsp_2 = "f00002a8X-Q", xvrspic_2 = "f00002acQ-Q", xvdivsp_3 = "f00002c0QQQ", xvmsubmsp_3 = "f00002c8QQQ", xvcvsxwsp_2 = "f00002e0Q-Q", xvrspim_2 = "f00002e4Q-Q", xvtdivsp_3 = "f00002e8XQQ", xvadddp_3 = "f0000300QQQ", xvmaddadp_3 = "f0000308QQQ", xvcmpeqdp_3 = "f0000318QQQ", xvcvdpuxws_2 = "f0000320Q-Q", xvrdpi_2 = "f0000324Q-Q", xvrsqrtedp_2 = "f0000328Q-Q", xvsqrtdp_2 = "f000032cQ-Q", xvsubdp_3 = "f0000340QQQ", xvmaddmdp_3 = "f0000348QQQ", xvcmpgtdp_3 = "f0000358QQQ", xvcvdpsxws_2 = "f0000360Q-Q", xvrdpiz_2 = "f0000364Q-Q", xvredp_2 = "f0000368Q-Q", xvmuldp_3 = "f0000380QQQ", xvmsubadp_3 = "f0000388QQQ", xvcmpgedp_3 = "f0000398QQQ", xvcvuxwdp_2 = "f00003a0Q-Q", xvrdpip_2 = "f00003a4Q-Q", xvtsqrtdp_2 = "f00003a8X-Q", xvrdpic_2 = "f00003acQ-Q", xvdivdp_3 = "f00003c0QQQ", xvmsubmdp_3 = "f00003c8QQQ", xvcvsxwdp_2 = "f00003e0Q-Q", xvrdpim_2 = "f00003e4Q-Q", xvtdivdp_3 = "f00003e8XQQ", xsnmaddasp_3 = "f0000408QQQ", xxland_3 = "f0000410QQQ", xscvdpsp_2 = "f0000424Q-Q", xscvdpspn_2 = "f000042cQ-Q", xsnmaddmsp_3 = "f0000448QQQ", xxlandc_3 = "f0000450QQQ", xsrsp_2 = "f0000464Q-Q", xsnmsubasp_3 = "f0000488QQQ", xxlor_3 = "f0000490QQQ", xscvuxdsp_2 = "f00004a0Q-Q", xsnmsubmsp_3 = "f00004c8QQQ", xxlxor_3 = "f00004d0QQQ", xscvsxdsp_2 = "f00004e0Q-Q", xsmaxdp_3 = "f0000500QQQ", xsnmaddadp_3 = "f0000508QQQ", xxlnor_3 = "f0000510QQQ", xscvdpuxds_2 = "f0000520Q-Q", xscvspdp_2 = "f0000524Q-Q", xscvspdpn_2 = "f000052cQ-Q", xsmindp_3 = "f0000540QQQ", xsnmaddmdp_3 = "f0000548QQQ", xxlorc_3 = "f0000550QQQ", xscvdpsxds_2 = "f0000560Q-Q", xsabsdp_2 = "f0000564Q-Q", xscpsgndp_3 = "f0000580QQQ", xsnmsubadp_3 = "f0000588QQQ", xxlnand_3 = "f0000590QQQ", xscvuxddp_2 = "f00005a0Q-Q", xsnabsdp_2 = "f00005a4Q-Q", xsnmsubmdp_3 = "f00005c8QQQ", xxleqv_3 = "f00005d0QQQ", xscvsxddp_2 = "f00005e0Q-Q", xsnegdp_2 = "f00005e4Q-Q", xvmaxsp_3 = "f0000600QQQ", xvnmaddasp_3 = "f0000608QQQ", ["xvcmpeqsp._3"] = "f0000618QQQ", xvcvspuxds_2 = "f0000620Q-Q", xvcvdpsp_2 = "f0000624Q-Q", xvminsp_3 = "f0000640QQQ", xvnmaddmsp_3 = "f0000648QQQ", ["xvcmpgtsp._3"] = "f0000658QQQ", xvcvspsxds_2 = "f0000660Q-Q", xvabssp_2 = "f0000664Q-Q", xvcpsgnsp_3 = "f0000680QQQ", xvnmsubasp_3 = "f0000688QQQ", ["xvcmpgesp._3"] = "f0000698QQQ", xvcvuxdsp_2 = "f00006a0Q-Q", xvnabssp_2 = "f00006a4Q-Q", xvnmsubmsp_3 = "f00006c8QQQ", xvcvsxdsp_2 = "f00006e0Q-Q", xvnegsp_2 = "f00006e4Q-Q", xvmaxdp_3 = "f0000700QQQ", xvnmaddadp_3 = "f0000708QQQ", ["xvcmpeqdp._3"] = "f0000718QQQ", xvcvdpuxds_2 = "f0000720Q-Q", xvcvspdp_2 = "f0000724Q-Q", xvmindp_3 = "f0000740QQQ", xvnmaddmdp_3 = "f0000748QQQ", ["xvcmpgtdp._3"] = "f0000758QQQ", xvcvdpsxds_2 = "f0000760Q-Q", xvabsdp_2 = "f0000764Q-Q", xvcpsgndp_3 = "f0000780QQQ", xvnmsubadp_3 = "f0000788QQQ", ["xvcmpgedp._3"] = "f0000798QQQ", xvcvuxddp_2 = "f00007a0Q-Q", xvnabsdp_2 = "f00007a4Q-Q", xvnmsubmdp_3 = "f00007c8QQQ", xvcvsxddp_2 = "f00007e0Q-Q", xvnegdp_2 = "f00007e4Q-Q", -- Primary opcode 61: stfdp_2 = "f4000000F:D", -- NYI: displacement must be divisible by 4. -- Primary opcode 62: stq_2 = "f8000002R:D", -- NYI: displacement must be divisible by 8. -- Primary opcode 63: fdiv_3 = "fc000024FFF.", fsub_3 = "fc000028FFF.", fadd_3 = "fc00002aFFF.", fsqrt_2 = "fc00002cF-F.", fsel_4 = "fc00002eFFFF~.", fre_2 = "fc000030F-F.", fmul_3 = "fc000032FF-F.", frsqrte_2 = "fc000034F-F.", fmsub_4 = "fc000038FFFF~.", fmadd_4 = "fc00003aFFFF~.", fnmsub_4 = "fc00003cFFFF~.", fnmadd_4 = "fc00003eFFFF~.", fcmpu_3 = "fc000000XFF", fcpsgn_3 = "fc000010FFF.", fcmpo_3 = "fc000040XFF", mtfsb1_1 = "fc00004cA", fneg_2 = "fc000050F-F.", mcrfs_2 = "fc000080XX", mtfsb0_1 = "fc00008cA", fmr_2 = "fc000090F-F.", frsp_2 = "fc000018F-F.", fctiw_2 = "fc00001cF-F.", fctiwz_2 = "fc00001eF-F.", ftdiv_2 = "fc000100X-F.", fctiwu_2 = "fc00011cF-F.", fctiwuz_2 = "fc00011eF-F.", mtfsfi_2 = "fc00010cAA", -- NYI: upshift. fnabs_2 = "fc000110F-F.", ftsqrt_2 = "fc000140X-F.", fabs_2 = "fc000210F-F.", frin_2 = "fc000310F-F.", friz_2 = "fc000350F-F.", frip_2 = "fc000390F-F.", frim_2 = "fc0003d0F-F.", mffs_1 = "fc00048eF.", -- NYI: mtfsf, mtfsb0, mtfsb1. fctid_2 = "fc00065cF-F.", fctidz_2 = "fc00065eF-F.", fmrgow_3 = "fc00068cFFF", fcfid_2 = "fc00069cF-F.", fctidu_2 = "fc00075cF-F.", fctiduz_2 = "fc00075eF-F.", fmrgew_3 = "fc00078cFFF", fcfidu_2 = "fc00079cF-F.", daddq_3 = "fc000004F:F:F:.", dquaq_4 = "fc000006F:F:F:Z.", dmulq_3 = "fc000044F:F:F:.", drrndq_4 = "fc000046F:F:F:Z.", dscliq_3 = "fc000084F:F:6.", dquaiq_4 = "fc000086SF:~F:Z.", dscriq_3 = "fc0000c4F:F:6.", drintxq_4 = "fc0000c61F:~F:Z.", dcmpoq_3 = "fc000104XF:F:", dtstexq_3 = "fc000144XF:F:", dtstdcq_3 = "fc000184XF:6", dtstdgq_3 = "fc0001c4XF:6", drintnq_4 = "fc0001c61F:~F:Z.", dctqpq_2 = "fc000204F:-F:.", dctfixq_2 = "fc000244F:-F:.", ddedpdq_3 = "fc000284ZF:~F:.", dxexq_2 = "fc0002c4F:-F:.", dsubq_3 = "fc000404F:F:F:.", ddivq_3 = "fc000444F:F:F:.", dcmpuq_3 = "fc000504XF:F:", dtstsfq_3 = "fc000544XF:F:", drdpq_2 = "fc000604F:-F:.", dcffixq_2 = "fc000644F:-F:.", denbcdq_3 = "fc000684YF:~F:.", diexq_3 = "fc0006c4F:FF:.", -- Primary opcode 4, SPE APU extension: evaddw_3 = "10000200RRR", evaddiw_3 = "10000202RAR~", evsubw_3 = "10000204RRR~", evsubiw_3 = "10000206RAR~", evabs_2 = "10000208RR", evneg_2 = "10000209RR", evextsb_2 = "1000020aRR", evextsh_2 = "1000020bRR", evrndw_2 = "1000020cRR", evcntlzw_2 = "1000020dRR", evcntlsw_2 = "1000020eRR", brinc_3 = "1000020fRRR", evand_3 = "10000211RRR", evandc_3 = "10000212RRR", evxor_3 = "10000216RRR", evor_3 = "10000217RRR", evmr_2 = "10000217RR=", evnor_3 = "10000218RRR", evnot_2 = "10000218RR=", eveqv_3 = "10000219RRR", evorc_3 = "1000021bRRR", evnand_3 = "1000021eRRR", evsrwu_3 = "10000220RRR", evsrws_3 = "10000221RRR", evsrwiu_3 = "10000222RRA", evsrwis_3 = "10000223RRA", evslw_3 = "10000224RRR", evslwi_3 = "10000226RRA", evrlw_3 = "10000228RRR", evsplati_2 = "10000229RS", evrlwi_3 = "1000022aRRA", evsplatfi_2 = "1000022bRS", evmergehi_3 = "1000022cRRR", evmergelo_3 = "1000022dRRR", evcmpgtu_3 = "10000230XRR", evcmpgtu_2 = "10000230-RR", evcmpgts_3 = "10000231XRR", evcmpgts_2 = "10000231-RR", evcmpltu_3 = "10000232XRR", evcmpltu_2 = "10000232-RR", evcmplts_3 = "10000233XRR", evcmplts_2 = "10000233-RR", evcmpeq_3 = "10000234XRR", evcmpeq_2 = "10000234-RR", evsel_4 = "10000278RRRW", evsel_3 = "10000278RRR", evfsadd_3 = "10000280RRR", evfssub_3 = "10000281RRR", evfsabs_2 = "10000284RR", evfsnabs_2 = "10000285RR", evfsneg_2 = "10000286RR", evfsmul_3 = "10000288RRR", evfsdiv_3 = "10000289RRR", evfscmpgt_3 = "1000028cXRR", evfscmpgt_2 = "1000028c-RR", evfscmplt_3 = "1000028dXRR", evfscmplt_2 = "1000028d-RR", evfscmpeq_3 = "1000028eXRR", evfscmpeq_2 = "1000028e-RR", evfscfui_2 = "10000290R-R", evfscfsi_2 = "10000291R-R", evfscfuf_2 = "10000292R-R", evfscfsf_2 = "10000293R-R", evfsctui_2 = "10000294R-R", evfsctsi_2 = "10000295R-R", evfsctuf_2 = "10000296R-R", evfsctsf_2 = "10000297R-R", evfsctuiz_2 = "10000298R-R", evfsctsiz_2 = "1000029aR-R", evfststgt_3 = "1000029cXRR", evfststgt_2 = "1000029c-RR", evfststlt_3 = "1000029dXRR", evfststlt_2 = "1000029d-RR", evfststeq_3 = "1000029eXRR", evfststeq_2 = "1000029e-RR", efsadd_3 = "100002c0RRR", efssub_3 = "100002c1RRR", efsabs_2 = "100002c4RR", efsnabs_2 = "100002c5RR", efsneg_2 = "100002c6RR", efsmul_3 = "100002c8RRR", efsdiv_3 = "100002c9RRR", efscmpgt_3 = "100002ccXRR", efscmpgt_2 = "100002cc-RR", efscmplt_3 = "100002cdXRR", efscmplt_2 = "100002cd-RR", efscmpeq_3 = "100002ceXRR", efscmpeq_2 = "100002ce-RR", efscfd_2 = "100002cfR-R", efscfui_2 = "100002d0R-R", efscfsi_2 = "100002d1R-R", efscfuf_2 = "100002d2R-R", efscfsf_2 = "100002d3R-R", efsctui_2 = "100002d4R-R", efsctsi_2 = "100002d5R-R", efsctuf_2 = "100002d6R-R", efsctsf_2 = "100002d7R-R", efsctuiz_2 = "100002d8R-R", efsctsiz_2 = "100002daR-R", efststgt_3 = "100002dcXRR", efststgt_2 = "100002dc-RR", efststlt_3 = "100002ddXRR", efststlt_2 = "100002dd-RR", efststeq_3 = "100002deXRR", efststeq_2 = "100002de-RR", efdadd_3 = "100002e0RRR", efdsub_3 = "100002e1RRR", efdcfuid_2 = "100002e2R-R", efdcfsid_2 = "100002e3R-R", efdabs_2 = "100002e4RR", efdnabs_2 = "100002e5RR", efdneg_2 = "100002e6RR", efdmul_3 = "100002e8RRR", efddiv_3 = "100002e9RRR", efdctuidz_2 = "100002eaR-R", efdctsidz_2 = "100002ebR-R", efdcmpgt_3 = "100002ecXRR", efdcmpgt_2 = "100002ec-RR", efdcmplt_3 = "100002edXRR", efdcmplt_2 = "100002ed-RR", efdcmpeq_3 = "100002eeXRR", efdcmpeq_2 = "100002ee-RR", efdcfs_2 = "100002efR-R", efdcfui_2 = "100002f0R-R", efdcfsi_2 = "100002f1R-R", efdcfuf_2 = "100002f2R-R", efdcfsf_2 = "100002f3R-R", efdctui_2 = "100002f4R-R", efdctsi_2 = "100002f5R-R", efdctuf_2 = "100002f6R-R", efdctsf_2 = "100002f7R-R", efdctuiz_2 = "100002f8R-R", efdctsiz_2 = "100002faR-R", efdtstgt_3 = "100002fcXRR", efdtstgt_2 = "100002fc-RR", efdtstlt_3 = "100002fdXRR", efdtstlt_2 = "100002fd-RR", efdtsteq_3 = "100002feXRR", efdtsteq_2 = "100002fe-RR", evlddx_3 = "10000300RR0R", evldd_2 = "10000301R8", evldwx_3 = "10000302RR0R", evldw_2 = "10000303R8", evldhx_3 = "10000304RR0R", evldh_2 = "10000305R8", evlwhex_3 = "10000310RR0R", evlwhe_2 = "10000311R4", evlwhoux_3 = "10000314RR0R", evlwhou_2 = "10000315R4", evlwhosx_3 = "10000316RR0R", evlwhos_2 = "10000317R4", evstddx_3 = "10000320RR0R", evstdd_2 = "10000321R8", evstdwx_3 = "10000322RR0R", evstdw_2 = "10000323R8", evstdhx_3 = "10000324RR0R", evstdh_2 = "10000325R8", evstwhex_3 = "10000330RR0R", evstwhe_2 = "10000331R4", evstwhox_3 = "10000334RR0R", evstwho_2 = "10000335R4", evstwwex_3 = "10000338RR0R", evstwwe_2 = "10000339R4", evstwwox_3 = "1000033cRR0R", evstwwo_2 = "1000033dR4", evmhessf_3 = "10000403RRR", evmhossf_3 = "10000407RRR", evmheumi_3 = "10000408RRR", evmhesmi_3 = "10000409RRR", evmhesmf_3 = "1000040bRRR", evmhoumi_3 = "1000040cRRR", evmhosmi_3 = "1000040dRRR", evmhosmf_3 = "1000040fRRR", evmhessfa_3 = "10000423RRR", evmhossfa_3 = "10000427RRR", evmheumia_3 = "10000428RRR", evmhesmia_3 = "10000429RRR", evmhesmfa_3 = "1000042bRRR", evmhoumia_3 = "1000042cRRR", evmhosmia_3 = "1000042dRRR", evmhosmfa_3 = "1000042fRRR", evmwhssf_3 = "10000447RRR", evmwlumi_3 = "10000448RRR", evmwhumi_3 = "1000044cRRR", evmwhsmi_3 = "1000044dRRR", evmwhsmf_3 = "1000044fRRR", evmwssf_3 = "10000453RRR", evmwumi_3 = "10000458RRR", evmwsmi_3 = "10000459RRR", evmwsmf_3 = "1000045bRRR", evmwhssfa_3 = "10000467RRR", evmwlumia_3 = "10000468RRR", evmwhumia_3 = "1000046cRRR", evmwhsmia_3 = "1000046dRRR", evmwhsmfa_3 = "1000046fRRR", evmwssfa_3 = "10000473RRR", evmwumia_3 = "10000478RRR", evmwsmia_3 = "10000479RRR", evmwsmfa_3 = "1000047bRRR", evmra_2 = "100004c4RR", evdivws_3 = "100004c6RRR", evdivwu_3 = "100004c7RRR", evmwssfaa_3 = "10000553RRR", evmwumiaa_3 = "10000558RRR", evmwsmiaa_3 = "10000559RRR", evmwsmfaa_3 = "1000055bRRR", evmwssfan_3 = "100005d3RRR", evmwumian_3 = "100005d8RRR", evmwsmian_3 = "100005d9RRR", evmwsmfan_3 = "100005dbRRR", evmergehilo_3 = "1000022eRRR", evmergelohi_3 = "1000022fRRR", evlhhesplatx_3 = "10000308RR0R", evlhhesplat_2 = "10000309R2", evlhhousplatx_3 = "1000030cRR0R", evlhhousplat_2 = "1000030dR2", evlhhossplatx_3 = "1000030eRR0R", evlhhossplat_2 = "1000030fR2", evlwwsplatx_3 = "10000318RR0R", evlwwsplat_2 = "10000319R4", evlwhsplatx_3 = "1000031cRR0R", evlwhsplat_2 = "1000031dR4", evaddusiaaw_2 = "100004c0RR", evaddssiaaw_2 = "100004c1RR", evsubfusiaaw_2 = "100004c2RR", evsubfssiaaw_2 = "100004c3RR", evaddumiaaw_2 = "100004c8RR", evaddsmiaaw_2 = "100004c9RR", evsubfumiaaw_2 = "100004caRR", evsubfsmiaaw_2 = "100004cbRR", evmheusiaaw_3 = "10000500RRR", evmhessiaaw_3 = "10000501RRR", evmhessfaaw_3 = "10000503RRR", evmhousiaaw_3 = "10000504RRR", evmhossiaaw_3 = "10000505RRR", evmhossfaaw_3 = "10000507RRR", evmheumiaaw_3 = "10000508RRR", evmhesmiaaw_3 = "10000509RRR", evmhesmfaaw_3 = "1000050bRRR", evmhoumiaaw_3 = "1000050cRRR", evmhosmiaaw_3 = "1000050dRRR", evmhosmfaaw_3 = "1000050fRRR", evmhegumiaa_3 = "10000528RRR", evmhegsmiaa_3 = "10000529RRR", evmhegsmfaa_3 = "1000052bRRR", evmhogumiaa_3 = "1000052cRRR", evmhogsmiaa_3 = "1000052dRRR", evmhogsmfaa_3 = "1000052fRRR", evmwlusiaaw_3 = "10000540RRR", evmwlssiaaw_3 = "10000541RRR", evmwlumiaaw_3 = "10000548RRR", evmwlsmiaaw_3 = "10000549RRR", evmheusianw_3 = "10000580RRR", evmhessianw_3 = "10000581RRR", evmhessfanw_3 = "10000583RRR", evmhousianw_3 = "10000584RRR", evmhossianw_3 = "10000585RRR", evmhossfanw_3 = "10000587RRR", evmheumianw_3 = "10000588RRR", evmhesmianw_3 = "10000589RRR", evmhesmfanw_3 = "1000058bRRR", evmhoumianw_3 = "1000058cRRR", evmhosmianw_3 = "1000058dRRR", evmhosmfanw_3 = "1000058fRRR", evmhegumian_3 = "100005a8RRR", evmhegsmian_3 = "100005a9RRR", evmhegsmfan_3 = "100005abRRR", evmhogumian_3 = "100005acRRR", evmhogsmian_3 = "100005adRRR", evmhogsmfan_3 = "100005afRRR", evmwlusianw_3 = "100005c0RRR", evmwlssianw_3 = "100005c1RRR", evmwlumianw_3 = "100005c8RRR", evmwlsmianw_3 = "100005c9RRR", -- NYI: Book E instructions. } -- Add mnemonics for "." variants. do local t = {} for k,v in pairs(map_op) do if type(v) == "string" and sub(v, -1) == "." then local v2 = sub(v, 1, 7)..char(byte(v, 8)+1)..sub(v, 9, -2) t[sub(k, 1, -3).."."..sub(k, -2)] = v2 end end for k,v in pairs(t) do map_op[k] = v end end -- Add more branch mnemonics. for cond,c in pairs(map_cond) do local b1 = "b"..cond local c1 = shl(band(c, 3), 16) + (c < 4 and 0x01000000 or 0) -- bX[l] map_op[b1.."_1"] = tohex(0x40800000 + c1).."K" map_op[b1.."y_1"] = tohex(0x40a00000 + c1).."K" map_op[b1.."l_1"] = tohex(0x40800001 + c1).."K" map_op[b1.."_2"] = tohex(0x40800000 + c1).."-XK" map_op[b1.."y_2"] = tohex(0x40a00000 + c1).."-XK" map_op[b1.."l_2"] = tohex(0x40800001 + c1).."-XK" -- bXlr[l] map_op[b1.."lr_0"] = tohex(0x4c800020 + c1) map_op[b1.."lrl_0"] = tohex(0x4c800021 + c1) map_op[b1.."ctr_0"] = tohex(0x4c800420 + c1) map_op[b1.."ctrl_0"] = tohex(0x4c800421 + c1) -- bXctr[l] map_op[b1.."lr_1"] = tohex(0x4c800020 + c1).."-X" map_op[b1.."lrl_1"] = tohex(0x4c800021 + c1).."-X" map_op[b1.."ctr_1"] = tohex(0x4c800420 + c1).."-X" map_op[b1.."ctrl_1"] = tohex(0x4c800421 + c1).."-X" end ------------------------------------------------------------------------------ local function parse_gpr(expr) local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") local tp = map_type[tname or expr] if tp then local reg = ovreg or tp.reg if not reg then werror("type `"..(tname or expr).."' needs a register override") end expr = reg end local r = match(expr, "^r([1-3]?[0-9])$") if r then r = tonumber(r) if r <= 31 then return r, tp end end werror("bad register name `"..expr.."'") end local function parse_fpr(expr) local r = match(expr, "^f([1-3]?[0-9])$") if r then r = tonumber(r) if r <= 31 then return r end end werror("bad register name `"..expr.."'") end local function parse_vr(expr) local r = match(expr, "^v([1-3]?[0-9])$") if r then r = tonumber(r) if r <= 31 then return r end end werror("bad register name `"..expr.."'") end local function parse_vs(expr) local r = match(expr, "^vs([1-6]?[0-9])$") if r then r = tonumber(r) if r <= 63 then return r end end werror("bad register name `"..expr.."'") end local function parse_cr(expr) local r = match(expr, "^cr([0-7])$") if r then return tonumber(r) end werror("bad condition register name `"..expr.."'") end local function parse_cond(expr) local r, cond = match(expr, "^4%*cr([0-7])%+(%w%w)$") if r then r = tonumber(r) local c = map_cond[cond] if c and c < 4 then return r*4+c end end werror("bad condition bit name `"..expr.."'") end local parse_ctx = {} local loadenv = setfenv and function(s) local code = loadstring(s, "") if code then setfenv(code, parse_ctx) end return code end or function(s) return load(s, "", nil, parse_ctx) end -- Try to parse simple arithmetic, too, since some basic ops are aliases. local function parse_number(n) local x = tonumber(n) if x then return x end local code = loadenv("return "..n) if code then local ok, y = pcall(code) if ok then return y end end return nil end local function parse_imm(imm, bits, shift, scale, signed) local n = parse_number(imm) if n then local m = sar(n, scale) if shl(m, scale) == n then if signed then local s = sar(m, bits-1) if s == 0 then return shl(m, shift) elseif s == -1 then return shl(m + shl(1, bits), shift) end else if sar(m, bits) == 0 then return shl(m, shift) end end end werror("out of range immediate `"..imm.."'") elseif match(imm, "^[rfv]([1-3]?[0-9])$") or match(imm, "^vs([1-6]?[0-9])$") or match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then werror("expected immediate operand, got register") else waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) return 0 end end local function parse_shiftmask(imm, isshift) local n = parse_number(imm) if n then if shr(n, 6) == 0 then local lsb = band(n, 31) local msb = n - lsb return isshift and (shl(lsb, 11)+shr(msb, 4)) or (shl(lsb, 6)+msb) end werror("out of range immediate `"..imm.."'") elseif match(imm, "^r([1-3]?[0-9])$") or match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then werror("expected immediate operand, got register") else waction("IMMSH", isshift and 1 or 0, imm) return 0; end end local function parse_disp(disp) local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") if imm then local r = parse_gpr(reg) if r == 0 then werror("cannot use r0 in displacement") end return shl(r, 16) + parse_imm(imm, 16, 0, 0, true) end local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then local r, tp = parse_gpr(reg) if r == 0 then werror("cannot use r0 in displacement") end if tp then waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) return shl(r, 16) end end werror("bad displacement `"..disp.."'") end local function parse_u5disp(disp, scale) local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") if imm then local r = parse_gpr(reg) if r == 0 then werror("cannot use r0 in displacement") end return shl(r, 16) + parse_imm(imm, 5, 11, scale, false) end local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then local r, tp = parse_gpr(reg) if r == 0 then werror("cannot use r0 in displacement") end if tp then waction("IMM", scale*1024+5*32+11, format(tp.ctypefmt, tailr)) return shl(r, 16) end end werror("bad displacement `"..disp.."'") end local function parse_label(label, def) local prefix = sub(label, 1, 2) -- =>label (pc label reference) if prefix == "=>" then return "PC", 0, sub(label, 3) end -- ->name (global label reference) if prefix == "->" then return "LG", map_global[sub(label, 3)] end if def then -- [1-9] (local label definition) if match(label, "^[1-9]$") then return "LG", 10+tonumber(label) end else -- [<>][1-9] (local label reference) local dir, lnum = match(label, "^([<>])([1-9])$") if dir then -- Fwd: 1-9, Bkwd: 11-19. return "LG", lnum + (dir == ">" and 0 or 10) end -- extern label (extern label reference) local extname = match(label, "^extern%s+(%S+)$") if extname then return "EXT", map_extern[extname] end end werror("bad label `"..label.."'") end ------------------------------------------------------------------------------ -- Handle opcodes defined with template strings. op_template = function(params, template, nparams) if not params then return sub(template, 9) end local op = tonumber(sub(template, 1, 8), 16) local n, rs = 1, 26 -- Limit number of section buffer positions used by a single dasm_put(). -- A single opcode needs a maximum of 3 positions (rlwinm). if secpos+3 > maxsecpos then wflush() end local pos = wpos() -- Process each character. for p in gmatch(sub(template, 9), ".") do if p == "R" then rs = rs - 5; op = op + shl(parse_gpr(params[n]), rs); n = n + 1 elseif p == "F" then rs = rs - 5; op = op + shl(parse_fpr(params[n]), rs); n = n + 1 elseif p == "V" then rs = rs - 5; op = op + shl(parse_vr(params[n]), rs); n = n + 1 elseif p == "Q" then local vs = parse_vs(params[n]); n = n + 1; rs = rs - 5 local sh = rs == 6 and 2 or 3 + band(shr(rs, 1), 3) op = op + shl(band(vs, 31), rs) + shr(band(vs, 32), sh) elseif p == "q" then local vs = parse_vs(params[n]); n = n + 1 op = op + shl(band(vs, 31), 21) + shr(band(vs, 32), 5) elseif p == "A" then rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, false); n = n + 1 elseif p == "S" then rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, true); n = n + 1 elseif p == "I" then op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 elseif p == "U" then op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 elseif p == "D" then op = op + parse_disp(params[n]); n = n + 1 elseif p == "2" then op = op + parse_u5disp(params[n], 1); n = n + 1 elseif p == "4" then op = op + parse_u5disp(params[n], 2); n = n + 1 elseif p == "8" then op = op + parse_u5disp(params[n], 3); n = n + 1 elseif p == "C" then rs = rs - 5; op = op + shl(parse_cond(params[n]), rs); n = n + 1 elseif p == "X" then rs = rs - 5; op = op + shl(parse_cr(params[n]), rs+2); n = n + 1 elseif p == "1" then rs = rs - 5; op = op + parse_imm(params[n], 1, rs, 0, false); n = n + 1 elseif p == "g" then rs = rs - 5; op = op + parse_imm(params[n], 2, rs, 0, false); n = n + 1 elseif p == "3" then rs = rs - 5; op = op + parse_imm(params[n], 3, rs, 0, false); n = n + 1 elseif p == "P" then rs = rs - 5; op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1 elseif p == "p" then op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1 elseif p == "6" then rs = rs - 6; op = op + parse_imm(params[n], 6, rs, 0, false); n = n + 1 elseif p == "Y" then rs = rs - 5; op = op + parse_imm(params[n], 1, rs+4, 0, false); n = n + 1 elseif p == "y" then rs = rs - 5; op = op + parse_imm(params[n], 1, rs+3, 0, false); n = n + 1 elseif p == "Z" then rs = rs - 5; op = op + parse_imm(params[n], 2, rs+3, 0, false); n = n + 1 elseif p == "z" then rs = rs - 5; op = op + parse_imm(params[n], 2, rs+2, 0, false); n = n + 1 elseif p == "W" then op = op + parse_cr(params[n]); n = n + 1 elseif p == "G" then op = op + parse_imm(params[n], 8, 12, 0, false); n = n + 1 elseif p == "H" then op = op + parse_shiftmask(params[n], true); n = n + 1 elseif p == "M" then op = op + parse_shiftmask(params[n], false); n = n + 1 elseif p == "J" or p == "K" then local mode, m, s = parse_label(params[n], false) if p == "K" then m = m + 2048 end waction("REL_"..mode, m, s, 1) n = n + 1 elseif p == "0" then if band(shr(op, rs), 31) == 0 then werror("cannot use r0") end elseif p == "=" or p == "%" then local t = band(shr(op, p == "%" and rs+5 or rs), 31) rs = rs - 5 op = op + shl(t, rs) elseif p == "~" then local mm = shl(31, rs) local lo = band(op, mm) local hi = band(op, shl(mm, 5)) op = op - lo - hi + shl(lo, 5) + shr(hi, 5) elseif p == ":" then if band(shr(op, rs), 1) ~= 0 then werror("register pair expected") end elseif p == "-" then rs = rs - 5 elseif p == "." then -- Ignored. else assert(false) end end wputpos(pos, op) end map_op[".template__"] = op_template ------------------------------------------------------------------------------ -- Pseudo-opcode to mark the position where the action list is to be emitted. map_op[".actionlist_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeactions(out, name) end) end -- Pseudo-opcode to mark the position where the global enum is to be emitted. map_op[".globals_1"] = function(params) if not params then return "prefix" end local prefix = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobals(out, prefix) end) end -- Pseudo-opcode to mark the position where the global names are to be emitted. map_op[".globalnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobalnames(out, name) end) end -- Pseudo-opcode to mark the position where the extern names are to be emitted. map_op[".externnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeexternnames(out, name) end) end ------------------------------------------------------------------------------ -- Label pseudo-opcode (converted from trailing colon form). map_op[".label_1"] = function(params) if not params then return "[1-9] | ->global | =>pcexpr" end if secpos+1 > maxsecpos then wflush() end local mode, n, s = parse_label(params[1], true) if mode == "EXT" then werror("bad label definition") end waction("LABEL_"..mode, n, s, 1) end ------------------------------------------------------------------------------ -- Pseudo-opcodes for data storage. map_op[".long_*"] = function(params) if not params then return "imm..." end for _,p in ipairs(params) do local n = tonumber(p) if not n then werror("bad immediate `"..p.."'") end if n < 0 then n = n + 2^32 end wputw(n) if secpos+2 > maxsecpos then wflush() end end end -- Alignment pseudo-opcode. map_op[".align_1"] = function(params) if not params then return "numpow2" end if secpos+1 > maxsecpos then wflush() end local align = tonumber(params[1]) if align then local x = align -- Must be a power of 2 in the range (2 ... 256). for i=1,8 do x = x / 2 if x == 1 then waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. return end end end werror("bad alignment") end ------------------------------------------------------------------------------ -- Pseudo-opcode for (primitive) type definitions (map to C types). map_op[".type_3"] = function(params, nparams) if not params then return nparams == 2 and "name, ctype" or "name, ctype, reg" end local name, ctype, reg = params[1], params[2], params[3] if not match(name, "^[%a_][%w_]*$") then werror("bad type name `"..name.."'") end local tp = map_type[name] if tp then werror("duplicate type `"..name.."'") end -- Add #type to defines. A bit unclean to put it in map_archdef. map_archdef["#"..name] = "sizeof("..ctype..")" -- Add new type and emit shortcut define. local num = ctypenum + 1 map_type[name] = { ctype = ctype, ctypefmt = format("Dt%X(%%s)", num), reg = reg, } wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) ctypenum = num end map_op[".type_2"] = map_op[".type_3"] -- Dump type definitions. local function dumptypes(out, lvl) local t = {} for name in pairs(map_type) do t[#t+1] = name end sort(t) out:write("Type definitions:\n") for _,name in ipairs(t) do local tp = map_type[name] local reg = tp.reg or "" out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) end out:write("\n") end ------------------------------------------------------------------------------ -- Set the current section. function _M.section(num) waction("SECTION", num) wflush(true) -- SECTION is a terminal action. end ------------------------------------------------------------------------------ -- Dump architecture description. function _M.dumparch(out) out:write(format("DynASM %s version %s, released %s\n\n", _info.arch, _info.version, _info.release)) dumpactions(out) end -- Dump all user defined elements. function _M.dumpdef(out, lvl) dumptypes(out, lvl) dumpglobals(out, lvl) dumpexterns(out, lvl) end ------------------------------------------------------------------------------ -- Pass callbacks from/to the DynASM core. function _M.passcb(wl, we, wf, ww) wline, werror, wfatal, wwarn = wl, we, wf, ww return wflush end -- Setup the arch-specific module. function _M.setup(arch, opt) g_arch, g_opt = arch, opt end -- Merge the core maps and the arch-specific maps. function _M.mergemaps(map_coreop, map_def) setmetatable(map_op, { __index = map_coreop }) setmetatable(map_def, { __index = map_archdef }) return map_op, map_def end return _M ------------------------------------------------------------------------------ ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_proto.h ================================================ /* ** DynASM encoding engine prototypes. ** Copyright (C) 2005-2022 Mike Pall. All rights reserved. ** Released under the MIT license. See dynasm.lua for full copyright notice. */ #ifndef _DASM_PROTO_H #define _DASM_PROTO_H #include #include #define DASM_IDENT "DynASM 1.5.0" #define DASM_VERSION 10500 /* 1.5.0 */ #ifndef Dst_DECL #define Dst_DECL dasm_State **Dst #endif #ifndef Dst_REF #define Dst_REF (*Dst) #endif #ifndef DASM_FDEF #define DASM_FDEF extern #endif #ifndef DASM_M_GROW #define DASM_M_GROW(ctx, t, p, sz, need) \ do { \ size_t _sz = (sz), _need = (need); \ if (_sz < _need) { \ if (_sz < 16) _sz = 16; \ while (_sz < _need) _sz += _sz; \ (p) = (t *)realloc((p), _sz); \ if ((p) == NULL) exit(1); \ (sz) = _sz; \ } \ } while(0) #endif #ifndef DASM_M_FREE #define DASM_M_FREE(ctx, p, sz) free(p) #endif /* Internal DynASM encoder state. */ typedef struct dasm_State dasm_State; /* Initialize and free DynASM state. */ DASM_FDEF void dasm_init(Dst_DECL, int maxsection); DASM_FDEF void dasm_free(Dst_DECL); /* Setup global array. Must be called before dasm_setup(). */ DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl); /* Grow PC label array. Can be called after dasm_setup(), too. */ DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc); /* Setup encoder. */ DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist); /* Feed encoder with actions. Calls are generated by pre-processor. */ DASM_FDEF void dasm_put(Dst_DECL, int start, ...); /* Link sections and return the resulting size. */ DASM_FDEF int dasm_link(Dst_DECL, size_t *szp); /* Encode sections into buffer. */ DASM_FDEF int dasm_encode(Dst_DECL, void *buffer); /* Get PC label offset. */ DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc); #ifdef DASM_CHECKS /* Optional sanity checker to call between isolated encoding steps. */ DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch); #else #define dasm_checkstep(a, b) 0 #endif #endif /* _DASM_PROTO_H */ ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_x64.lua ================================================ ------------------------------------------------------------------------------ -- DynASM x64 module. -- -- Copyright (C) 2005-2022 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------ -- This module just sets 64 bit mode for the combined x86/x64 module. -- All the interesting stuff is there. ------------------------------------------------------------------------------ x64 = true -- Using a global is an ugly, but effective solution. return require("dasm_x86") ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_x86.h ================================================ /* ** DynASM x86 encoding engine. ** Copyright (C) 2005-2022 Mike Pall. All rights reserved. ** Released under the MIT license. See dynasm.lua for full copyright notice. */ #include #include #include #include #define DASM_ARCH "x86" #ifndef DASM_EXTERN #define DASM_EXTERN(a,b,c,d) 0 #endif /* Action definitions. DASM_STOP must be 255. */ enum { DASM_DISP = 233, DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB, DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC, DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN, DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP }; /* Maximum number of section buffer positions for a single dasm_put() call. */ #define DASM_MAXSECPOS 25 /* DynASM encoder status codes. Action list offset or number are or'ed in. */ #define DASM_S_OK 0x00000000 #define DASM_S_NOMEM 0x01000000 #define DASM_S_PHASE 0x02000000 #define DASM_S_MATCH_SEC 0x03000000 #define DASM_S_RANGE_I 0x11000000 #define DASM_S_RANGE_SEC 0x12000000 #define DASM_S_RANGE_LG 0x13000000 #define DASM_S_RANGE_PC 0x14000000 #define DASM_S_RANGE_VREG 0x15000000 #define DASM_S_UNDEF_L 0x21000000 #define DASM_S_UNDEF_PC 0x22000000 /* Macros to convert positions (8 bit section + 24 bit index). */ #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) #define DASM_POS2BIAS(pos) ((pos)&0xff000000) #define DASM_SEC2POS(sec) ((sec)<<24) #define DASM_POS2SEC(pos) ((pos)>>24) #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) /* Action list type. */ typedef const unsigned char *dasm_ActList; /* Per-section structure. */ typedef struct dasm_Section { int *rbuf; /* Biased buffer pointer (negative section bias). */ int *buf; /* True buffer pointer. */ size_t bsize; /* Buffer size in bytes. */ int pos; /* Biased buffer position. */ int epos; /* End of biased buffer position - max single put. */ int ofs; /* Byte offset into section. */ } dasm_Section; /* Core structure holding the DynASM encoding state. */ struct dasm_State { size_t psize; /* Allocated size of this structure. */ dasm_ActList actionlist; /* Current actionlist pointer. */ int *lglabels; /* Local/global chain/pos ptrs. */ size_t lgsize; int *pclabels; /* PC label chains/pos ptrs. */ size_t pcsize; void **globals; /* Array of globals (bias -10). */ dasm_Section *section; /* Pointer to active section. */ size_t codesize; /* Total size of all code sections. */ int maxsection; /* 0 <= sectionidx < maxsection. */ int status; /* Status code. */ dasm_Section sections[1]; /* All sections. Alloc-extended. */ }; /* The size of the core structure depends on the max. number of sections. */ #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) /* Initialize DynASM state. */ void dasm_init(Dst_DECL, int maxsection) { dasm_State *D; size_t psz = 0; int i; Dst_REF = NULL; DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); D = Dst_REF; D->psize = psz; D->lglabels = NULL; D->lgsize = 0; D->pclabels = NULL; D->pcsize = 0; D->globals = NULL; D->maxsection = maxsection; for (i = 0; i < maxsection; i++) { D->sections[i].buf = NULL; /* Need this for pass3. */ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); D->sections[i].bsize = 0; D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ } } /* Free DynASM state. */ void dasm_free(Dst_DECL) { dasm_State *D = Dst_REF; int i; for (i = 0; i < D->maxsection; i++) if (D->sections[i].buf) DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); DASM_M_FREE(Dst, D, D->psize); } /* Setup global label array. Must be called before dasm_setup(). */ void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) { dasm_State *D = Dst_REF; D->globals = gl - 10; /* Negative bias to compensate for locals. */ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); } /* Grow PC label array. Can be called after dasm_setup(), too. */ void dasm_growpc(Dst_DECL, unsigned int maxpc) { dasm_State *D = Dst_REF; size_t osz = D->pcsize; DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); } /* Setup encoder. */ void dasm_setup(Dst_DECL, const void *actionlist) { dasm_State *D = Dst_REF; int i; D->actionlist = (dasm_ActList)actionlist; D->status = DASM_S_OK; D->section = &D->sections[0]; memset((void *)D->lglabels, 0, D->lgsize); if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); for (i = 0; i < D->maxsection; i++) { D->sections[i].pos = DASM_SEC2POS(i); D->sections[i].ofs = 0; } } #ifdef DASM_CHECKS #define CK(x, st) \ do { if (!(x)) { \ D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0) #define CKPL(kind, st) \ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0) #else #define CK(x, st) ((void)0) #define CKPL(kind, st) ((void)0) #endif /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ void dasm_put(Dst_DECL, int start, ...) { va_list ap; dasm_State *D = Dst_REF; dasm_ActList p = D->actionlist + start; dasm_Section *sec = D->section; int pos = sec->pos, ofs = sec->ofs, mrm = -1; int *b; if (pos >= sec->epos) { DASM_M_GROW(Dst, int, sec->buf, sec->bsize, sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); sec->rbuf = sec->buf - DASM_POS2BIAS(pos); sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); } b = sec->rbuf; b[pos++] = start; va_start(ap, start); while (1) { int action = *p++; if (action < DASM_DISP) { ofs++; } else if (action <= DASM_REL_A) { int n = va_arg(ap, int); b[pos++] = n; switch (action) { case DASM_DISP: if (n == 0) { if (mrm < 0) mrm = p[-2]; if ((mrm&7) != 5) break; } /* fallthrough */ case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; /* fallthrough */ case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */ case DASM_IMM_D: ofs += 4; break; case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob; case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break; case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; /* fallthrough */ case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break; case DASM_SPACE: p++; ofs += n; break; case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */ case DASM_VREG: CK((n&-16) == 0 && (n != 4 || (*p>>5) != 2), RANGE_VREG); if (*p < 0x40 && p[1] == DASM_DISP) mrm = n; if (*p < 0x20 && (n&7) == 4) ofs++; switch ((*p++ >> 3) & 3) { case 3: n |= b[pos-3]; /* fallthrough */ case 2: n |= b[pos-2]; /* fallthrough */ case 1: if (n <= 7) { b[pos-1] |= 0x10; ofs--; } } continue; } mrm = -1; } else { int *pl, n; switch (action) { case DASM_REL_LG: case DASM_IMM_LG: n = *p++; pl = D->lglabels + n; /* Bkwd rel or global. */ if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } pl -= 246; n = *pl; if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ goto linkrel; case DASM_REL_PC: case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); putrel: n = *pl; if (n < 0) { /* Label exists. Get label pos and store it. */ b[pos] = -n; } else { linkrel: b[pos] = n; /* Else link to rel chain, anchored at label. */ *pl = pos; } pos++; ofs += 4; /* Maximum offset needed. */ if (action == DASM_REL_LG || action == DASM_REL_PC) { b[pos++] = ofs; /* Store pass1 offset estimate. */ } else if (sizeof(ptrdiff_t) == 8) { ofs += 4; } break; case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel; case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); putlabel: n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } *pl = -pos; /* Label exists now. */ b[pos++] = ofs; /* Store pass1 offset estimate. */ break; case DASM_ALIGN: ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */ b[pos++] = ofs; /* Store pass1 offset estimate. */ break; case DASM_EXTERN: p += 2; ofs += 4; break; case DASM_ESC: p++; ofs++; break; case DASM_MARK: mrm = p[-2]; break; case DASM_SECTION: n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; case DASM_STOP: goto stop; } } } stop: va_end(ap); sec->pos = pos; sec->ofs = ofs; } #undef CK /* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */ int dasm_link(Dst_DECL, size_t *szp) { dasm_State *D = Dst_REF; int secnum; int ofs = 0; #ifdef DASM_CHECKS *szp = 0; if (D->status != DASM_S_OK) return D->status; { int pc; for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; } #endif { /* Handle globals not defined in this translation unit. */ int idx; for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { int n = D->lglabels[idx]; /* Undefined label: Collapse rel chain and replace with marker (< 0). */ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } } } /* Combine all code sections. No support for data sections (yet). */ for (secnum = 0; secnum < D->maxsection; secnum++) { dasm_Section *sec = D->sections + secnum; int *b = sec->rbuf; int pos = DASM_SEC2POS(secnum); int lastpos = sec->pos; while (pos != lastpos) { dasm_ActList p = D->actionlist + b[pos++]; int op = 0; while (1) { int action = *p++; switch (action) { case DASM_REL_LG: p++; /* fallthrough */ case DASM_REL_PC: { int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0); if (shrink) { /* Shrinkable branch opcode? */ int lofs, lpos = b[pos]; if (lpos < 0) goto noshrink; /* Ext global? */ lofs = *DASM_POS2PTR(D, lpos); if (lpos > pos) { /* Fwd label: add cumulative section offsets. */ int i; for (i = secnum; i < DASM_POS2SEC(lpos); i++) lofs += D->sections[i].ofs; } else { lofs -= ofs; /* Bkwd label: unfix offset. */ } lofs -= b[pos+1]; /* Short branch ok? */ if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */ else { noshrink: shrink = 0; } /* No, cannot shrink op. */ } b[pos+1] = shrink; pos += 2; break; } /* fallthrough */ case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++; /* fallthrough */ case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W: case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB: case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break; case DASM_LABEL_LG: p++; /* fallthrough */ case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */ case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */ case DASM_EXTERN: p += 2; break; case DASM_ESC: op = *p++; break; case DASM_MARK: break; case DASM_SECTION: case DASM_STOP: goto stop; default: op = action; break; } } stop: (void)0; } ofs += sec->ofs; /* Next section starts right after current section. */ } D->codesize = ofs; /* Total size of all code sections */ *szp = ofs; return DASM_S_OK; } #define dasmb(x) *cp++ = (unsigned char)(x) #ifndef DASM_ALIGNED_WRITES #define dasmw(x) \ do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0) #define dasmd(x) \ do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0) #define dasmq(x) \ do { *((unsigned long long *)cp) = (unsigned long long)(x); cp+=8; } while (0) #else #define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0) #define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0) #define dasmq(x) do { dasmd(x); dasmd((x)>>32); } while (0) #endif static unsigned char *dasma_(unsigned char *cp, ptrdiff_t x) { if (sizeof(ptrdiff_t) == 8) dasmq((unsigned long long)x); else dasmd((unsigned int)x); return cp; } #define dasma(x) (cp = dasma_(cp, (x))) /* Pass 3: Encode sections. */ int dasm_encode(Dst_DECL, void *buffer) { dasm_State *D = Dst_REF; unsigned char *base = (unsigned char *)buffer; unsigned char *cp = base; int secnum; /* Encode all code sections. No support for data sections (yet). */ for (secnum = 0; secnum < D->maxsection; secnum++) { dasm_Section *sec = D->sections + secnum; int *b = sec->buf; int *endb = sec->rbuf + sec->pos; while (b != endb) { dasm_ActList p = D->actionlist + *b++; unsigned char *mark = NULL; while (1) { int action = *p++; int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0; switch (action) { case DASM_DISP: if (!mark) mark = cp; { unsigned char *mm = mark; if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL; if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7; if (mrm != 5) { mm[-1] -= 0x80; break; } } if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40; } /* fallthrough */ case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break; case DASM_IMM_DB: if (((n+128)&-256) == 0) { db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb; } else mark = NULL; /* fallthrough */ case DASM_IMM_D: wd: dasmd(n); break; case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL; /* fallthrough */ case DASM_IMM_W: dasmw(n); break; case DASM_VREG: { int t = *p++; unsigned char *ex = cp - (t&7); if ((n & 8) && t < 0xa0) { if (*ex & 0x80) ex[1] ^= 0x20 << (t>>6); else *ex ^= 1 << (t>>6); n &= 7; } else if (n & 0x10) { if (*ex & 0x80) { *ex = 0xc5; ex[1] = (ex[1] & 0x80) | ex[2]; ex += 2; } while (++ex < cp) ex[-1] = *ex; if (mark) mark--; cp--; n &= 7; } if (t >= 0xc0) n <<= 4; else if (t >= 0x40) n <<= 3; else if (n == 4 && t < 0x20) { cp[-1] ^= n; *cp++ = 0x20; } cp[-1] ^= n; break; } case DASM_REL_LG: p++; if (n >= 0) goto rel_pc; b++; n = (int)(ptrdiff_t)D->globals[-n]; /* fallthrough */ case DASM_REL_A: rel_a: n -= (unsigned int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */ case DASM_REL_PC: rel_pc: { int shrink = *b++; int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; } n = *pb - ((int)(cp-base) + 4-shrink); if (shrink == 0) goto wd; if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb; goto wb; } case DASM_IMM_LG: p++; if (n < 0) { dasma((ptrdiff_t)D->globals[-n]); break; } /* fallthrough */ case DASM_IMM_PC: { int *pb = DASM_POS2PTR(D, n); dasma(*pb < 0 ? (ptrdiff_t)pb[1] : (*pb + (ptrdiff_t)base)); break; } case DASM_LABEL_LG: { int idx = *p++; if (idx >= 10) D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n)); break; } case DASM_LABEL_PC: case DASM_SETLABEL: break; case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; } case DASM_ALIGN: n = *p++; while (((cp-base) & n)) *cp++ = 0x90; /* nop */ break; case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd; case DASM_MARK: mark = cp; break; case DASM_ESC: action = *p++; /* fallthrough */ default: *cp++ = action; break; case DASM_SECTION: case DASM_STOP: goto stop; } } stop: (void)0; } } if (base + D->codesize != cp) /* Check for phase errors. */ return DASM_S_PHASE; return DASM_S_OK; } /* Get PC label offset. */ int dasm_getpclabel(Dst_DECL, unsigned int pc) { dasm_State *D = Dst_REF; if (pc*sizeof(int) < D->pcsize) { int pos = D->pclabels[pc]; if (pos < 0) return *DASM_POS2PTR(D, -pos); if (pos > 0) return -1; /* Undefined. */ } return -2; /* Unused or out of range. */ } #ifdef DASM_CHECKS /* Optional sanity checker to call between isolated encoding steps. */ int dasm_checkstep(Dst_DECL, int secmatch) { dasm_State *D = Dst_REF; if (D->status == DASM_S_OK) { int i; for (i = 1; i <= 9; i++) { if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; } D->lglabels[i] = 0; } } if (D->status == DASM_S_OK && secmatch >= 0 && D->section != &D->sections[secmatch]) D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections); return D->status; } #endif ================================================ FILE: third_party/luajit/luajit/dynasm/dasm_x86.lua ================================================ ------------------------------------------------------------------------------ -- DynASM x86/x64 module. -- -- Copyright (C) 2005-2022 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------ local x64 = x64 -- Module information: local _info = { arch = x64 and "x64" or "x86", description = "DynASM x86/x64 module", version = "1.5.0", vernum = 10500, release = "2021-05-02", author = "Mike Pall", license = "MIT", } -- Exported glue functions for the arch-specific module. local _M = { _info = _info } -- Cache library functions. local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs local assert, unpack, setmetatable = assert, unpack or table.unpack, setmetatable local _s = string local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char local find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsub local concat, sort, remove = table.concat, table.sort, table.remove local bit = bit or require("bit") local band, bxor, shl, shr = bit.band, bit.bxor, bit.lshift, bit.rshift -- Inherited tables and callbacks. local g_opt, g_arch local wline, werror, wfatal, wwarn -- Action name list. -- CHECK: Keep this in sync with the C code! local action_names = { -- int arg, 1 buffer pos: "DISP", "IMM_S", "IMM_B", "IMM_W", "IMM_D", "IMM_WB", "IMM_DB", -- action arg (1 byte), int arg, 1 buffer pos (reg/num): "VREG", "SPACE", -- ptrdiff_t arg, 1 buffer pos (address): !x64 "SETLABEL", "REL_A", -- action arg (1 byte) or int arg, 2 buffer pos (link, offset): "REL_LG", "REL_PC", -- action arg (1 byte) or int arg, 1 buffer pos (link): "IMM_LG", "IMM_PC", -- action arg (1 byte) or int arg, 1 buffer pos (offset): "LABEL_LG", "LABEL_PC", -- action arg (1 byte), 1 buffer pos (offset): "ALIGN", -- action args (2 bytes), no buffer pos. "EXTERN", -- action arg (1 byte), no buffer pos. "ESC", -- no action arg, no buffer pos. "MARK", -- action arg (1 byte), no buffer pos, terminal action: "SECTION", -- no args, no buffer pos, terminal action: "STOP" } -- Maximum number of section buffer positions for dasm_put(). -- CHECK: Keep this in sync with the C code! local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. -- Action name -> action number (dynamically generated below). local map_action = {} -- First action number. Everything below does not need to be escaped. local actfirst = 256-#action_names -- Action list buffer and string (only used to remove dupes). local actlist = {} local actstr = "" -- Argument list for next dasm_put(). Start with offset 0 into action list. local actargs = { 0 } -- Current number of section buffer positions for dasm_put(). local secpos = 1 -- VREG kind encodings, pre-shifted by 5 bits. local map_vreg = { ["modrm.rm.m"] = 0x00, ["modrm.rm.r"] = 0x20, ["opcode"] = 0x20, ["sib.base"] = 0x20, ["sib.index"] = 0x40, ["modrm.reg"] = 0x80, ["vex.v"] = 0xa0, ["imm.hi"] = 0xc0, } -- Current number of VREG actions contributing to REX/VEX shrinkage. local vreg_shrink_count = 0 ------------------------------------------------------------------------------ -- Compute action numbers for action names. for n,name in ipairs(action_names) do local num = actfirst + n - 1 map_action[name] = num end -- Dump action names and numbers. local function dumpactions(out) out:write("DynASM encoding engine action codes:\n") for n,name in ipairs(action_names) do local num = map_action[name] out:write(format(" %-10s %02X %d\n", name, num, num)) end out:write("\n") end -- Write action list buffer as a huge static C array. local function writeactions(out, name) local nn = #actlist local last = actlist[nn] or 255 actlist[nn] = nil -- Remove last byte. if nn == 0 then nn = 1 end out:write("static const unsigned char ", name, "[", nn, "] = {\n") local s = " " for n,b in ipairs(actlist) do s = s..b.."," if #s >= 75 then assert(out:write(s, "\n")) s = " " end end out:write(s, last, "\n};\n\n") -- Add last byte back. end ------------------------------------------------------------------------------ -- Add byte to action list. local function wputxb(n) assert(n >= 0 and n <= 255 and n % 1 == 0, "byte out of range") actlist[#actlist+1] = n end -- Add action to list with optional arg. Advance buffer pos, too. local function waction(action, a, num) wputxb(assert(map_action[action], "bad action name `"..action.."'")) if a then actargs[#actargs+1] = a end if a or num then secpos = secpos + (num or 1) end end -- Optionally add a VREG action. local function wvreg(kind, vreg, psz, sk, defer) if not vreg then return end waction("VREG", vreg) local b = assert(map_vreg[kind], "bad vreg kind `"..vreg.."'") if b < (sk or 0) then vreg_shrink_count = vreg_shrink_count + 1 end if not defer then b = b + vreg_shrink_count * 8 vreg_shrink_count = 0 end wputxb(b + (psz or 0)) end -- Add call to embedded DynASM C code. local function wcall(func, args) wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true) end -- Delete duplicate action list chunks. A tad slow, but so what. local function dedupechunk(offset) local al, as = actlist, actstr local chunk = char(unpack(al, offset+1, #al)) local orig = find(as, chunk, 1, true) if orig then actargs[1] = orig-1 -- Replace with original offset. for i=offset+1,#al do al[i] = nil end -- Kill dupe. else actstr = as..chunk end end -- Flush action list (intervening C code or buffer pos overflow). local function wflush(term) local offset = actargs[1] if #actlist == offset then return end -- Nothing to flush. if not term then waction("STOP") end -- Terminate action list. dedupechunk(offset) wcall("put", actargs) -- Add call to dasm_put(). actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). secpos = 1 -- The actionlist offset occupies a buffer position, too. end -- Put escaped byte. local function wputb(n) if n >= actfirst then waction("ESC") end -- Need to escape byte. wputxb(n) end ------------------------------------------------------------------------------ -- Global label name -> global label number. With auto assignment on 1st use. local next_global = 10 local map_global = setmetatable({}, { __index = function(t, name) if not match(name, "^[%a_][%w_@]*$") then werror("bad global label") end local n = next_global if n > 246 then werror("too many global labels") end next_global = n + 1 t[name] = n return n end}) -- Dump global labels. local function dumpglobals(out, lvl) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("Global labels:\n") for i=10,next_global-1 do out:write(format(" %s\n", t[i])) end out:write("\n") end -- Write global label enum. local function writeglobals(out, prefix) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("enum {\n") for i=10,next_global-1 do out:write(" ", prefix, gsub(t[i], "@.*", ""), ",\n") end out:write(" ", prefix, "_MAX\n};\n") end -- Write global label names. local function writeglobalnames(out, name) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("static const char *const ", name, "[] = {\n") for i=10,next_global-1 do out:write(" \"", t[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Extern label name -> extern label number. With auto assignment on 1st use. local next_extern = -1 local map_extern = setmetatable({}, { __index = function(t, name) -- No restrictions on the name for now. local n = next_extern if n < -256 then werror("too many extern labels") end next_extern = n - 1 t[name] = n return n end}) -- Dump extern labels. local function dumpexterns(out, lvl) local t = {} for name, n in pairs(map_extern) do t[-n] = name end out:write("Extern labels:\n") for i=1,-next_extern-1 do out:write(format(" %s\n", t[i])) end out:write("\n") end -- Write extern label names. local function writeexternnames(out, name) local t = {} for name, n in pairs(map_extern) do t[-n] = name end out:write("static const char *const ", name, "[] = {\n") for i=1,-next_extern-1 do out:write(" \"", t[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Arch-specific maps. local map_archdef = {} -- Ext. register name -> int. name. local map_reg_rev = {} -- Int. register name -> ext. name. local map_reg_num = {} -- Int. register name -> register number. local map_reg_opsize = {} -- Int. register name -> operand size. local map_reg_valid_base = {} -- Int. register name -> valid base register? local map_reg_valid_index = {} -- Int. register name -> valid index register? local map_reg_needrex = {} -- Int. register name -> need rex vs. no rex. local reg_list = {} -- Canonical list of int. register names. local map_type = {} -- Type name -> { ctype, reg } local ctypenum = 0 -- Type number (for _PTx macros). local addrsize = x64 and "q" or "d" -- Size for address operands. -- Helper functions to fill register maps. local function mkrmap(sz, cl, names) local cname = format("@%s", sz) reg_list[#reg_list+1] = cname map_archdef[cl] = cname map_reg_rev[cname] = cl map_reg_num[cname] = -1 map_reg_opsize[cname] = sz if sz == addrsize or sz == "d" then map_reg_valid_base[cname] = true map_reg_valid_index[cname] = true end if names then for n,name in ipairs(names) do local iname = format("@%s%x", sz, n-1) reg_list[#reg_list+1] = iname map_archdef[name] = iname map_reg_rev[iname] = name map_reg_num[iname] = n-1 map_reg_opsize[iname] = sz if sz == "b" and n > 4 then map_reg_needrex[iname] = false end if sz == addrsize or sz == "d" then map_reg_valid_base[iname] = true map_reg_valid_index[iname] = true end end end for i=0,(x64 and sz ~= "f") and 15 or 7 do local needrex = sz == "b" and i > 3 local iname = format("@%s%x%s", sz, i, needrex and "R" or "") if needrex then map_reg_needrex[iname] = true end local name if sz == "o" or sz == "y" then name = format("%s%d", cl, i) elseif sz == "f" then name = format("st%d", i) else name = format("r%d%s", i, sz == addrsize and "" or sz) end map_archdef[name] = iname if not map_reg_rev[iname] then reg_list[#reg_list+1] = iname map_reg_rev[iname] = name map_reg_num[iname] = i map_reg_opsize[iname] = sz if sz == addrsize or sz == "d" then map_reg_valid_base[iname] = true map_reg_valid_index[iname] = true end end end reg_list[#reg_list+1] = "" end -- Integer registers (qword, dword, word and byte sized). if x64 then mkrmap("q", "Rq", {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"}) end mkrmap("d", "Rd", {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"}) mkrmap("w", "Rw", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"}) mkrmap("b", "Rb", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"}) map_reg_valid_index[map_archdef.esp] = false if x64 then map_reg_valid_index[map_archdef.rsp] = false end if x64 then map_reg_needrex[map_archdef.Rb] = true end map_archdef["Ra"] = "@"..addrsize -- FP registers (internally tword sized, but use "f" as operand size). mkrmap("f", "Rf") -- SSE registers (oword sized, but qword and dword accessible). mkrmap("o", "xmm") -- AVX registers (yword sized, but oword, qword and dword accessible). mkrmap("y", "ymm") -- Operand size prefixes to codes. local map_opsize = { byte = "b", word = "w", dword = "d", qword = "q", oword = "o", yword = "y", tword = "t", aword = addrsize, } -- Operand size code to number. local map_opsizenum = { b = 1, w = 2, d = 4, q = 8, o = 16, y = 32, t = 10, } -- Operand size code to name. local map_opsizename = { b = "byte", w = "word", d = "dword", q = "qword", o = "oword", y = "yword", t = "tword", f = "fpword", } -- Valid index register scale factors. local map_xsc = { ["1"] = 0, ["2"] = 1, ["4"] = 2, ["8"] = 3, } -- Condition codes. local map_cc = { o = 0, no = 1, b = 2, nb = 3, e = 4, ne = 5, be = 6, nbe = 7, s = 8, ns = 9, p = 10, np = 11, l = 12, nl = 13, le = 14, nle = 15, c = 2, nae = 2, nc = 3, ae = 3, z = 4, nz = 5, na = 6, a = 7, pe = 10, po = 11, nge = 12, ge = 13, ng = 14, g = 15, } -- Reverse defines for registers. function _M.revdef(s) return gsub(s, "@%w+", map_reg_rev) end -- Dump register names and numbers local function dumpregs(out) out:write("Register names, sizes and internal numbers:\n") for _,reg in ipairs(reg_list) do if reg == "" then out:write("\n") else local name = map_reg_rev[reg] local num = map_reg_num[reg] local opsize = map_opsizename[map_reg_opsize[reg]] out:write(format(" %-5s %-8s %s\n", name, opsize, num < 0 and "(variable)" or num)) end end end ------------------------------------------------------------------------------ -- Put action for label arg (IMM_LG, IMM_PC, REL_LG, REL_PC). local function wputlabel(aprefix, imm, num) if type(imm) == "number" then if imm < 0 then waction("EXTERN") wputxb(aprefix == "IMM_" and 0 or 1) imm = -imm-1 else waction(aprefix.."LG", nil, num); end wputxb(imm) else waction(aprefix.."PC", imm, num) end end -- Put signed byte or arg. local function wputsbarg(n) if type(n) == "number" then if n < -128 or n > 127 then werror("signed immediate byte out of range") end if n < 0 then n = n + 256 end wputb(n) else waction("IMM_S", n) end end -- Put unsigned byte or arg. local function wputbarg(n) if type(n) == "number" then if n < 0 or n > 255 then werror("unsigned immediate byte out of range") end wputb(n) else waction("IMM_B", n) end end -- Put unsigned word or arg. local function wputwarg(n) if type(n) == "number" then if shr(n, 16) ~= 0 then werror("unsigned immediate word out of range") end wputb(band(n, 255)); wputb(shr(n, 8)); else waction("IMM_W", n) end end -- Put signed or unsigned dword or arg. local function wputdarg(n) local tn = type(n) if tn == "number" then wputb(band(n, 255)) wputb(band(shr(n, 8), 255)) wputb(band(shr(n, 16), 255)) wputb(shr(n, 24)) elseif tn == "table" then wputlabel("IMM_", n[1], 1) else waction("IMM_D", n) end end -- Put signed or unsigned qword or arg. local function wputqarg(n) local tn = type(n) if tn == "number" then -- This is only used for numbers from -2^31..2^32-1. wputb(band(n, 255)) wputb(band(shr(n, 8), 255)) wputb(band(shr(n, 16), 255)) wputb(shr(n, 24)) local sign = n < 0 and 255 or 0 wputb(sign); wputb(sign); wputb(sign); wputb(sign) else waction("IMM_D", format("(unsigned int)(%s)", n)) waction("IMM_D", format("(unsigned int)((unsigned long long)(%s)>>32)", n)) end end -- Put operand-size dependent number or arg (defaults to dword). local function wputszarg(sz, n) if not sz or sz == "d" or sz == "q" then wputdarg(n) elseif sz == "w" then wputwarg(n) elseif sz == "b" then wputbarg(n) elseif sz == "s" then wputsbarg(n) else werror("bad operand size") end end -- Put multi-byte opcode with operand-size dependent modifications. local function wputop(sz, op, rex, vex, vregr, vregxb) local psz, sk = 0, nil if vex then local tail if vex.m == 1 and band(rex, 11) == 0 then if x64 and vregxb then sk = map_vreg["modrm.reg"] else wputb(0xc5) tail = shl(bxor(band(rex, 4), 4), 5) psz = 3 end end if not tail then wputb(0xc4) wputb(shl(bxor(band(rex, 7), 7), 5) + vex.m) tail = shl(band(rex, 8), 4) psz = 4 end local reg, vreg = 0, nil if vex.v then reg = vex.v.reg if not reg then werror("bad vex operand") end if reg < 0 then reg = 0; vreg = vex.v.vreg end end if sz == "y" or vex.l then tail = tail + 4 end wputb(tail + shl(bxor(reg, 15), 3) + vex.p) wvreg("vex.v", vreg) rex = 0 if op >= 256 then werror("bad vex opcode") end else if rex ~= 0 then if not x64 then werror("bad operand size") end elseif (vregr or vregxb) and x64 then rex = 0x10 sk = map_vreg["vex.v"] end end local r if sz == "w" then wputb(102) end -- Needs >32 bit numbers, but only for crc32 eax, word [ebx] if op >= 4294967296 then r = op%4294967296 wputb((op-r)/4294967296) op = r end if op >= 16777216 then wputb(shr(op, 24)); op = band(op, 0xffffff) end if op >= 65536 then if rex ~= 0 then local opc3 = band(op, 0xffff00) if opc3 == 0x0f3a00 or opc3 == 0x0f3800 then wputb(64 + band(rex, 15)); rex = 0; psz = 2 end end wputb(shr(op, 16)); op = band(op, 0xffff); psz = psz + 1 end if op >= 256 then local b = shr(op, 8) if b == 15 and rex ~= 0 then wputb(64 + band(rex, 15)); rex = 0; psz = 2 end wputb(b); op = band(op, 255); psz = psz + 1 end if rex ~= 0 then wputb(64 + band(rex, 15)); psz = 2 end if sz == "b" then op = op - 1 end wputb(op) return psz, sk end -- Put ModRM or SIB formatted byte. local function wputmodrm(m, s, rm, vs, vrm) assert(m < 4 and s < 16 and rm < 16, "bad modrm operands") wputb(shl(m, 6) + shl(band(s, 7), 3) + band(rm, 7)) end -- Put ModRM/SIB plus optional displacement. local function wputmrmsib(t, imark, s, vsreg, psz, sk) local vreg, vxreg local reg, xreg = t.reg, t.xreg if reg and reg < 0 then reg = 0; vreg = t.vreg end if xreg and xreg < 0 then xreg = 0; vxreg = t.vxreg end if s < 0 then s = 0 end -- Register mode. if sub(t.mode, 1, 1) == "r" then wputmodrm(3, s, reg) wvreg("modrm.reg", vsreg, psz+1, sk, vreg) wvreg("modrm.rm.r", vreg, psz+1, sk) return end local disp = t.disp local tdisp = type(disp) -- No base register? if not reg then local riprel = false if xreg then -- Indexed mode with index register only. -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp) wputmodrm(0, s, 4) if imark == "I" then waction("MARK") end wvreg("modrm.reg", vsreg, psz+1, sk, vxreg) wputmodrm(t.xsc, xreg, 5) wvreg("sib.index", vxreg, psz+2, sk) else -- Pure 32 bit displacement. if x64 and tdisp ~= "table" then wputmodrm(0, s, 4) -- [disp] -> (0, s, esp) (0, esp, ebp) wvreg("modrm.reg", vsreg, psz+1, sk) if imark == "I" then waction("MARK") end wputmodrm(0, 4, 5) else riprel = x64 wputmodrm(0, s, 5) -- [disp|rip-label] -> (0, s, ebp) wvreg("modrm.reg", vsreg, psz+1, sk) if imark == "I" then waction("MARK") end end end if riprel then -- Emit rip-relative displacement. if match("UWSiI", imark) then werror("NYI: rip-relative displacement followed by immediate") end -- The previous byte in the action buffer cannot be 0xe9 or 0x80-0x8f. wputlabel("REL_", disp[1], 2) else wputdarg(disp) end return end local m if tdisp == "number" then -- Check displacement size at assembly time. if disp == 0 and band(reg, 7) ~= 5 then -- [ebp] -> [ebp+0] (in SIB, too) if not vreg then m = 0 end -- Force DISP to allow [Rd(5)] -> [ebp+0] elseif disp >= -128 and disp <= 127 then m = 1 else m = 2 end elseif tdisp == "table" then m = 2 end -- Index register present or esp as base register: need SIB encoding. if xreg or band(reg, 7) == 4 then wputmodrm(m or 2, s, 4) -- ModRM. if m == nil or imark == "I" then waction("MARK") end wvreg("modrm.reg", vsreg, psz+1, sk, vxreg or vreg) wputmodrm(t.xsc or 0, xreg or 4, reg) -- SIB. wvreg("sib.index", vxreg, psz+2, sk, vreg) wvreg("sib.base", vreg, psz+2, sk) else wputmodrm(m or 2, s, reg) -- ModRM. if (imark == "I" and (m == 1 or m == 2)) or (m == nil and (vsreg or vreg)) then waction("MARK") end wvreg("modrm.reg", vsreg, psz+1, sk, vreg) wvreg("modrm.rm.m", vreg, psz+1, sk) end -- Put displacement. if m == 1 then wputsbarg(disp) elseif m == 2 then wputdarg(disp) elseif m == nil then waction("DISP", disp) end end ------------------------------------------------------------------------------ -- Return human-readable operand mode string. local function opmodestr(op, args) local m = {} for i=1,#args do local a = args[i] m[#m+1] = sub(a.mode, 1, 1)..(a.opsize or "?") end return op.." "..concat(m, ",") end -- Convert number to valid integer or nil. local function toint(expr, isqword) local n = tonumber(expr) if n then if n % 1 ~= 0 then werror("not an integer number `"..expr.."'") elseif isqword then if n < -2147483648 or n > 2147483647 then n = nil -- Handle it as an expression to avoid precision loss. end elseif n < -2147483648 or n > 4294967295 then werror("bad integer number `"..expr.."'") end return n end end -- Parse immediate expression. local function immexpr(expr) -- &expr (pointer) if sub(expr, 1, 1) == "&" then return "iPJ", format("(ptrdiff_t)(%s)", sub(expr,2)) end local prefix = sub(expr, 1, 2) -- =>expr (pc label reference) if prefix == "=>" then return "iJ", sub(expr, 3) end -- ->name (global label reference) if prefix == "->" then return "iJ", map_global[sub(expr, 3)] end -- [<>][1-9] (local label reference) local dir, lnum = match(expr, "^([<>])([1-9])$") if dir then -- Fwd: 247-255, Bkwd: 1-9. return "iJ", lnum + (dir == ">" and 246 or 0) end local extname = match(expr, "^extern%s+(%S+)$") if extname then return "iJ", map_extern[extname] end -- expr (interpreted as immediate) return "iI", expr end -- Parse displacement expression: +-num, +-expr, +-opsize*num local function dispexpr(expr) local disp = expr == "" and 0 or toint(expr) if disp then return disp end local c, dispt = match(expr, "^([+-])%s*(.+)$") if c == "+" then expr = dispt elseif not c then werror("bad displacement expression `"..expr.."'") end local opsize, tailops = match(dispt, "^(%w+)%s*%*%s*(.+)$") local ops, imm = map_opsize[opsize], toint(tailops) if ops and imm then if c == "-" then imm = -imm end return imm*map_opsizenum[ops] end local mode, iexpr = immexpr(dispt) if mode == "iJ" then if c == "-" then werror("cannot invert label reference") end return { iexpr } end return expr -- Need to return original signed expression. end -- Parse register or type expression. local function rtexpr(expr) if not expr then return end local tname, ovreg = match(expr, "^([%w_]+):(@[%w_]+)$") local tp = map_type[tname or expr] if tp then local reg = ovreg or tp.reg local rnum = map_reg_num[reg] if not rnum then werror("type `"..(tname or expr).."' needs a register override") end if not map_reg_valid_base[reg] then werror("bad base register override `"..(map_reg_rev[reg] or reg).."'") end return reg, rnum, tp end return expr, map_reg_num[expr] end -- Parse operand and return { mode, opsize, reg, xreg, xsc, disp, imm }. local function parseoperand(param, isqword) local t = {} local expr = param local opsize, tailops = match(param, "^(%w+)%s*(.+)$") if opsize then t.opsize = map_opsize[opsize] if t.opsize then expr = tailops end end local br = match(expr, "^%[%s*(.-)%s*%]$") repeat if br then t.mode = "xm" -- [disp] t.disp = toint(br) if t.disp then t.mode = x64 and "xm" or "xmO" break end -- [reg...] local tp local reg, tailr = match(br, "^([@%w_:]+)%s*(.*)$") reg, t.reg, tp = rtexpr(reg) if not t.reg then -- [expr] t.mode = x64 and "xm" or "xmO" t.disp = dispexpr("+"..br) break end if t.reg == -1 then t.vreg, tailr = match(tailr, "^(%b())(.*)$") if not t.vreg then werror("bad variable register expression") end end -- [xreg*xsc] or [xreg*xsc+-disp] or [xreg*xsc+-expr] local xsc, tailsc = match(tailr, "^%*%s*([1248])%s*(.*)$") if xsc then if not map_reg_valid_index[reg] then werror("bad index register `"..map_reg_rev[reg].."'") end t.xsc = map_xsc[xsc] t.xreg = t.reg t.vxreg = t.vreg t.reg = nil t.vreg = nil t.disp = dispexpr(tailsc) break end if not map_reg_valid_base[reg] then werror("bad base register `"..map_reg_rev[reg].."'") end -- [reg] or [reg+-disp] t.disp = toint(tailr) or (tailr == "" and 0) if t.disp then break end -- [reg+xreg...] local xreg, tailx = match(tailr, "^%+%s*([@%w_:]+)%s*(.*)$") xreg, t.xreg, tp = rtexpr(xreg) if not t.xreg then -- [reg+-expr] t.disp = dispexpr(tailr) break end if not map_reg_valid_index[xreg] then werror("bad index register `"..map_reg_rev[xreg].."'") end if t.xreg == -1 then t.vxreg, tailx = match(tailx, "^(%b())(.*)$") if not t.vxreg then werror("bad variable register expression") end end -- [reg+xreg*xsc...] local xsc, tailsc = match(tailx, "^%*%s*([1248])%s*(.*)$") if xsc then t.xsc = map_xsc[xsc] tailx = tailsc end -- [...] or [...+-disp] or [...+-expr] t.disp = dispexpr(tailx) else -- imm or opsize*imm local imm = toint(expr, isqword) if not imm and sub(expr, 1, 1) == "*" and t.opsize then imm = toint(sub(expr, 2)) if imm then imm = imm * map_opsizenum[t.opsize] t.opsize = nil end end if imm then if t.opsize then werror("bad operand size override") end local m = "i" if imm == 1 then m = m.."1" end if imm >= 4294967168 and imm <= 4294967295 then imm = imm-4294967296 end if imm >= -128 and imm <= 127 then m = m.."S" end t.imm = imm t.mode = m break end local tp local reg, tailr = match(expr, "^([@%w_:]+)%s*(.*)$") reg, t.reg, tp = rtexpr(reg) if t.reg then if t.reg == -1 then t.vreg, tailr = match(tailr, "^(%b())(.*)$") if not t.vreg then werror("bad variable register expression") end end -- reg if tailr == "" then if t.opsize then werror("bad operand size override") end t.opsize = map_reg_opsize[reg] if t.opsize == "f" then t.mode = t.reg == 0 and "fF" or "f" else if reg == "@w4" or (x64 and reg == "@d4") then wwarn("bad idea, try again with `"..(x64 and "rsp'" or "esp'")) end t.mode = t.reg == 0 and "rmR" or (reg == "@b1" and "rmC" or "rm") end t.needrex = map_reg_needrex[reg] break end -- type[idx], type[idx].field, type->field -> [reg+offset_expr] if not tp then werror("bad operand `"..param.."'") end t.mode = "xm" t.disp = format(tp.ctypefmt, tailr) else t.mode, t.imm = immexpr(expr) if sub(t.mode, -1) == "J" then if t.opsize and t.opsize ~= addrsize then werror("bad operand size override") end t.opsize = addrsize end end end until true return t end ------------------------------------------------------------------------------ -- x86 Template String Description -- =============================== -- -- Each template string is a list of [match:]pattern pairs, -- separated by "|". The first match wins. No match means a -- bad or unsupported combination of operand modes or sizes. -- -- The match part and the ":" is omitted if the operation has -- no operands. Otherwise the first N characters are matched -- against the mode strings of each of the N operands. -- -- The mode string for each operand type is (see parseoperand()): -- Integer register: "rm", +"R" for eax, ax, al, +"C" for cl -- FP register: "f", +"F" for st0 -- Index operand: "xm", +"O" for [disp] (pure offset) -- Immediate: "i", +"S" for signed 8 bit, +"1" for 1, -- +"I" for arg, +"P" for pointer -- Any: +"J" for valid jump targets -- -- So a match character "m" (mixed) matches both an integer register -- and an index operand (to be encoded with the ModRM/SIB scheme). -- But "r" matches only a register and "x" only an index operand -- (e.g. for FP memory access operations). -- -- The operand size match string starts right after the mode match -- characters and ends before the ":". "dwb" or "qdwb" is assumed, if empty. -- The effective data size of the operation is matched against this list. -- -- If only the regular "b", "w", "d", "q", "t" operand sizes are -- present, then all operands must be the same size. Unspecified sizes -- are ignored, but at least one operand must have a size or the pattern -- won't match (use the "byte", "word", "dword", "qword", "tword" -- operand size overrides. E.g.: mov dword [eax], 1). -- -- If the list has a "1" or "2" prefix, the operand size is taken -- from the respective operand and any other operand sizes are ignored. -- If the list contains only ".", all operand sizes are ignored. -- If the list has a "/" prefix, the concatenated (mixed) operand sizes -- are compared to the match. -- -- E.g. "rrdw" matches for either two dword registers or two word -- registers. "Fx2dq" matches an st0 operand plus an index operand -- pointing to a dword (float) or qword (double). -- -- Every character after the ":" is part of the pattern string: -- Hex chars are accumulated to form the opcode (left to right). -- "n" disables the standard opcode mods -- (otherwise: -1 for "b", o16 prefix for "w", rex.w for "q") -- "X" Force REX.W. -- "r"/"R" adds the reg. number from the 1st/2nd operand to the opcode. -- "m"/"M" generates ModRM/SIB from the 1st/2nd operand. -- The spare 3 bits are either filled with the last hex digit or -- the result from a previous "r"/"R". The opcode is restored. -- "u" Use VEX encoding, vvvv unused. -- "v"/"V" Use VEX encoding, vvvv from 1st/2nd operand (the operand is -- removed from the list used by future characters). -- "w" Use VEX encoding, vvvv from 3rd operand. -- "L" Force VEX.L -- -- All of the following characters force a flush of the opcode: -- "o"/"O" stores a pure 32 bit disp (offset) from the 1st/2nd operand. -- "s" stores a 4 bit immediate from the last register operand, -- followed by 4 zero bits. -- "S" stores a signed 8 bit immediate from the last operand. -- "U" stores an unsigned 8 bit immediate from the last operand. -- "W" stores an unsigned 16 bit immediate from the last operand. -- "i" stores an operand sized immediate from the last operand. -- "I" dito, but generates an action code to optionally modify -- the opcode (+2) for a signed 8 bit immediate. -- "J" generates one of the REL action codes from the last operand. -- ------------------------------------------------------------------------------ -- Template strings for x86 instructions. Ordered by first opcode byte. -- Unimplemented opcodes (deliberate omissions) are marked with *. local map_op = { -- 00-05: add... -- 06: *push es -- 07: *pop es -- 08-0D: or... -- 0E: *push cs -- 0F: two byte opcode prefix -- 10-15: adc... -- 16: *push ss -- 17: *pop ss -- 18-1D: sbb... -- 1E: *push ds -- 1F: *pop ds -- 20-25: and... es_0 = "26", -- 27: *daa -- 28-2D: sub... cs_0 = "2E", -- 2F: *das -- 30-35: xor... ss_0 = "36", -- 37: *aaa -- 38-3D: cmp... ds_0 = "3E", -- 3F: *aas inc_1 = x64 and "m:FF0m" or "rdw:40r|m:FF0m", dec_1 = x64 and "m:FF1m" or "rdw:48r|m:FF1m", push_1 = (x64 and "rq:n50r|rw:50r|mq:nFF6m|mw:FF6m" or "rdw:50r|mdw:FF6m").."|S.:6AS|ib:n6Ai|i.:68i", pop_1 = x64 and "rq:n58r|rw:58r|mq:n8F0m|mw:8F0m" or "rdw:58r|mdw:8F0m", -- 60: *pusha, *pushad, *pushaw -- 61: *popa, *popad, *popaw -- 62: *bound rdw,x -- 63: x86: *arpl mw,rw movsxd_2 = x64 and "rm/qd:63rM", fs_0 = "64", gs_0 = "65", o16_0 = "66", a16_0 = not x64 and "67" or nil, a32_0 = x64 and "67", -- 68: push idw -- 69: imul rdw,mdw,idw -- 6A: push ib -- 6B: imul rdw,mdw,S -- 6C: *insb -- 6D: *insd, *insw -- 6E: *outsb -- 6F: *outsd, *outsw -- 70-7F: jcc lb -- 80: add... mb,i -- 81: add... mdw,i -- 82: *undefined -- 83: add... mdw,S test_2 = "mr:85Rm|rm:85rM|Ri:A9ri|mi:F70mi", -- 86: xchg rb,mb -- 87: xchg rdw,mdw -- 88: mov mb,r -- 89: mov mdw,r -- 8A: mov r,mb -- 8B: mov r,mdw -- 8C: *mov mdw,seg lea_2 = "rx1dq:8DrM", -- 8E: *mov seg,mdw -- 8F: pop mdw nop_0 = "90", xchg_2 = "Rrqdw:90R|rRqdw:90r|rm:87rM|mr:87Rm", cbw_0 = "6698", cwde_0 = "98", cdqe_0 = "4898", cwd_0 = "6699", cdq_0 = "99", cqo_0 = "4899", -- 9A: *call iw:idw wait_0 = "9B", fwait_0 = "9B", pushf_0 = "9C", pushfd_0 = not x64 and "9C", pushfq_0 = x64 and "9C", popf_0 = "9D", popfd_0 = not x64 and "9D", popfq_0 = x64 and "9D", sahf_0 = "9E", lahf_0 = "9F", mov_2 = "OR:A3o|RO:A1O|mr:89Rm|rm:8BrM|rib:nB0ri|ridw:B8ri|mi:C70mi", movsb_0 = "A4", movsw_0 = "66A5", movsd_0 = "A5", cmpsb_0 = "A6", cmpsw_0 = "66A7", cmpsd_0 = "A7", -- A8: test Rb,i -- A9: test Rdw,i stosb_0 = "AA", stosw_0 = "66AB", stosd_0 = "AB", lodsb_0 = "AC", lodsw_0 = "66AD", lodsd_0 = "AD", scasb_0 = "AE", scasw_0 = "66AF", scasd_0 = "AF", -- B0-B7: mov rb,i -- B8-BF: mov rdw,i -- C0: rol... mb,i -- C1: rol... mdw,i ret_1 = "i.:nC2W", ret_0 = "C3", -- C4: *les rdw,mq -- C5: *lds rdw,mq -- C6: mov mb,i -- C7: mov mdw,i -- C8: *enter iw,ib leave_0 = "C9", -- CA: *retf iw -- CB: *retf int3_0 = "CC", int_1 = "i.:nCDU", into_0 = "CE", -- CF: *iret -- D0: rol... mb,1 -- D1: rol... mdw,1 -- D2: rol... mb,cl -- D3: rol... mb,cl -- D4: *aam ib -- D5: *aad ib -- D6: *salc -- D7: *xlat -- D8-DF: floating point ops -- E0: *loopne -- E1: *loope -- E2: *loop -- E3: *jcxz, *jecxz -- E4: *in Rb,ib -- E5: *in Rdw,ib -- E6: *out ib,Rb -- E7: *out ib,Rdw call_1 = x64 and "mq:nFF2m|J.:E8nJ" or "md:FF2m|J.:E8J", jmp_1 = x64 and "mq:nFF4m|J.:E9nJ" or "md:FF4m|J.:E9J", -- short: EB -- EA: *jmp iw:idw -- EB: jmp ib -- EC: *in Rb,dx -- ED: *in Rdw,dx -- EE: *out dx,Rb -- EF: *out dx,Rdw lock_0 = "F0", int1_0 = "F1", repne_0 = "F2", repnz_0 = "F2", rep_0 = "F3", repe_0 = "F3", repz_0 = "F3", -- F4: *hlt cmc_0 = "F5", -- F6: test... mb,i; div... mb -- F7: test... mdw,i; div... mdw clc_0 = "F8", stc_0 = "F9", -- FA: *cli cld_0 = "FC", std_0 = "FD", -- FE: inc... mb -- FF: inc... mdw -- misc ops not_1 = "m:F72m", neg_1 = "m:F73m", mul_1 = "m:F74m", imul_1 = "m:F75m", div_1 = "m:F76m", idiv_1 = "m:F77m", imul_2 = "rmqdw:0FAFrM|rIqdw:69rmI|rSqdw:6BrmS|riqdw:69rmi", imul_3 = "rmIqdw:69rMI|rmSqdw:6BrMS|rmiqdw:69rMi", movzx_2 = "rm/db:0FB6rM|rm/qb:|rm/wb:0FB6rM|rm/dw:0FB7rM|rm/qw:", movsx_2 = "rm/db:0FBErM|rm/qb:|rm/wb:0FBErM|rm/dw:0FBFrM|rm/qw:", bswap_1 = "rqd:0FC8r", bsf_2 = "rmqdw:0FBCrM", bsr_2 = "rmqdw:0FBDrM", bt_2 = "mrqdw:0FA3Rm|miqdw:0FBA4mU", btc_2 = "mrqdw:0FBBRm|miqdw:0FBA7mU", btr_2 = "mrqdw:0FB3Rm|miqdw:0FBA6mU", bts_2 = "mrqdw:0FABRm|miqdw:0FBA5mU", shld_3 = "mriqdw:0FA4RmU|mrC/qq:0FA5Rm|mrC/dd:|mrC/ww:", shrd_3 = "mriqdw:0FACRmU|mrC/qq:0FADRm|mrC/dd:|mrC/ww:", rdtsc_0 = "0F31", -- P1+ rdpmc_0 = "0F33", -- P6+ cpuid_0 = "0FA2", -- P1+ -- floating point ops fst_1 = "ff:DDD0r|xd:D92m|xq:nDD2m", fstp_1 = "ff:DDD8r|xd:D93m|xq:nDD3m|xt:DB7m", fld_1 = "ff:D9C0r|xd:D90m|xq:nDD0m|xt:DB5m", fpop_0 = "DDD8", -- Alias for fstp st0. fist_1 = "xw:nDF2m|xd:DB2m", fistp_1 = "xw:nDF3m|xd:DB3m|xq:nDF7m", fild_1 = "xw:nDF0m|xd:DB0m|xq:nDF5m", fxch_0 = "D9C9", fxch_1 = "ff:D9C8r", fxch_2 = "fFf:D9C8r|Fff:D9C8R", fucom_1 = "ff:DDE0r", fucom_2 = "Fff:DDE0R", fucomp_1 = "ff:DDE8r", fucomp_2 = "Fff:DDE8R", fucomi_1 = "ff:DBE8r", -- P6+ fucomi_2 = "Fff:DBE8R", -- P6+ fucomip_1 = "ff:DFE8r", -- P6+ fucomip_2 = "Fff:DFE8R", -- P6+ fcomi_1 = "ff:DBF0r", -- P6+ fcomi_2 = "Fff:DBF0R", -- P6+ fcomip_1 = "ff:DFF0r", -- P6+ fcomip_2 = "Fff:DFF0R", -- P6+ fucompp_0 = "DAE9", fcompp_0 = "DED9", fldenv_1 = "x.:D94m", fnstenv_1 = "x.:D96m", fstenv_1 = "x.:9BD96m", fldcw_1 = "xw:nD95m", fstcw_1 = "xw:n9BD97m", fnstcw_1 = "xw:nD97m", fstsw_1 = "Rw:n9BDFE0|xw:n9BDD7m", fnstsw_1 = "Rw:nDFE0|xw:nDD7m", fclex_0 = "9BDBE2", fnclex_0 = "DBE2", fnop_0 = "D9D0", -- D9D1-D9DF: unassigned fchs_0 = "D9E0", fabs_0 = "D9E1", -- D9E2: unassigned -- D9E3: unassigned ftst_0 = "D9E4", fxam_0 = "D9E5", -- D9E6: unassigned -- D9E7: unassigned fld1_0 = "D9E8", fldl2t_0 = "D9E9", fldl2e_0 = "D9EA", fldpi_0 = "D9EB", fldlg2_0 = "D9EC", fldln2_0 = "D9ED", fldz_0 = "D9EE", -- D9EF: unassigned f2xm1_0 = "D9F0", fyl2x_0 = "D9F1", fptan_0 = "D9F2", fpatan_0 = "D9F3", fxtract_0 = "D9F4", fprem1_0 = "D9F5", fdecstp_0 = "D9F6", fincstp_0 = "D9F7", fprem_0 = "D9F8", fyl2xp1_0 = "D9F9", fsqrt_0 = "D9FA", fsincos_0 = "D9FB", frndint_0 = "D9FC", fscale_0 = "D9FD", fsin_0 = "D9FE", fcos_0 = "D9FF", -- SSE, SSE2 andnpd_2 = "rmo:660F55rM", andnps_2 = "rmo:0F55rM", andpd_2 = "rmo:660F54rM", andps_2 = "rmo:0F54rM", clflush_1 = "x.:0FAE7m", cmppd_3 = "rmio:660FC2rMU", cmpps_3 = "rmio:0FC2rMU", cmpsd_3 = "rrio:F20FC2rMU|rxi/oq:", cmpss_3 = "rrio:F30FC2rMU|rxi/od:", comisd_2 = "rro:660F2FrM|rx/oq:", comiss_2 = "rro:0F2FrM|rx/od:", cvtdq2pd_2 = "rro:F30FE6rM|rx/oq:", cvtdq2ps_2 = "rmo:0F5BrM", cvtpd2dq_2 = "rmo:F20FE6rM", cvtpd2ps_2 = "rmo:660F5ArM", cvtpi2pd_2 = "rx/oq:660F2ArM", cvtpi2ps_2 = "rx/oq:0F2ArM", cvtps2dq_2 = "rmo:660F5BrM", cvtps2pd_2 = "rro:0F5ArM|rx/oq:", cvtsd2si_2 = "rr/do:F20F2DrM|rr/qo:|rx/dq:|rxq:", cvtsd2ss_2 = "rro:F20F5ArM|rx/oq:", cvtsi2sd_2 = "rm/od:F20F2ArM|rm/oq:F20F2ArXM", cvtsi2ss_2 = "rm/od:F30F2ArM|rm/oq:F30F2ArXM", cvtss2sd_2 = "rro:F30F5ArM|rx/od:", cvtss2si_2 = "rr/do:F30F2DrM|rr/qo:|rxd:|rx/qd:", cvttpd2dq_2 = "rmo:660FE6rM", cvttps2dq_2 = "rmo:F30F5BrM", cvttsd2si_2 = "rr/do:F20F2CrM|rr/qo:|rx/dq:|rxq:", cvttss2si_2 = "rr/do:F30F2CrM|rr/qo:|rxd:|rx/qd:", fxsave_1 = "x.:0FAE0m", fxrstor_1 = "x.:0FAE1m", ldmxcsr_1 = "xd:0FAE2m", lfence_0 = "0FAEE8", maskmovdqu_2 = "rro:660FF7rM", mfence_0 = "0FAEF0", movapd_2 = "rmo:660F28rM|mro:660F29Rm", movaps_2 = "rmo:0F28rM|mro:0F29Rm", movd_2 = "rm/od:660F6ErM|rm/oq:660F6ErXM|mr/do:660F7ERm|mr/qo:", movdqa_2 = "rmo:660F6FrM|mro:660F7FRm", movdqu_2 = "rmo:F30F6FrM|mro:F30F7FRm", movhlps_2 = "rro:0F12rM", movhpd_2 = "rx/oq:660F16rM|xr/qo:n660F17Rm", movhps_2 = "rx/oq:0F16rM|xr/qo:n0F17Rm", movlhps_2 = "rro:0F16rM", movlpd_2 = "rx/oq:660F12rM|xr/qo:n660F13Rm", movlps_2 = "rx/oq:0F12rM|xr/qo:n0F13Rm", movmskpd_2 = "rr/do:660F50rM", movmskps_2 = "rr/do:0F50rM", movntdq_2 = "xro:660FE7Rm", movnti_2 = "xrqd:0FC3Rm", movntpd_2 = "xro:660F2BRm", movntps_2 = "xro:0F2BRm", movq_2 = "rro:F30F7ErM|rx/oq:|xr/qo:n660FD6Rm", movsd_2 = "rro:F20F10rM|rx/oq:|xr/qo:nF20F11Rm", movss_2 = "rro:F30F10rM|rx/od:|xr/do:F30F11Rm", movupd_2 = "rmo:660F10rM|mro:660F11Rm", movups_2 = "rmo:0F10rM|mro:0F11Rm", orpd_2 = "rmo:660F56rM", orps_2 = "rmo:0F56rM", pause_0 = "F390", pextrw_3 = "rri/do:660FC5rMU|xri/wo:660F3A15nRmU", -- Mem op: SSE4.1 only. pinsrw_3 = "rri/od:660FC4rMU|rxi/ow:", pmovmskb_2 = "rr/do:660FD7rM", prefetchnta_1 = "xb:n0F180m", prefetcht0_1 = "xb:n0F181m", prefetcht1_1 = "xb:n0F182m", prefetcht2_1 = "xb:n0F183m", pshufd_3 = "rmio:660F70rMU", pshufhw_3 = "rmio:F30F70rMU", pshuflw_3 = "rmio:F20F70rMU", pslld_2 = "rmo:660FF2rM|rio:660F726mU", pslldq_2 = "rio:660F737mU", psllq_2 = "rmo:660FF3rM|rio:660F736mU", psllw_2 = "rmo:660FF1rM|rio:660F716mU", psrad_2 = "rmo:660FE2rM|rio:660F724mU", psraw_2 = "rmo:660FE1rM|rio:660F714mU", psrld_2 = "rmo:660FD2rM|rio:660F722mU", psrldq_2 = "rio:660F733mU", psrlq_2 = "rmo:660FD3rM|rio:660F732mU", psrlw_2 = "rmo:660FD1rM|rio:660F712mU", rcpps_2 = "rmo:0F53rM", rcpss_2 = "rro:F30F53rM|rx/od:", rsqrtps_2 = "rmo:0F52rM", rsqrtss_2 = "rmo:F30F52rM", sfence_0 = "0FAEF8", shufpd_3 = "rmio:660FC6rMU", shufps_3 = "rmio:0FC6rMU", stmxcsr_1 = "xd:0FAE3m", ucomisd_2 = "rro:660F2ErM|rx/oq:", ucomiss_2 = "rro:0F2ErM|rx/od:", unpckhpd_2 = "rmo:660F15rM", unpckhps_2 = "rmo:0F15rM", unpcklpd_2 = "rmo:660F14rM", unpcklps_2 = "rmo:0F14rM", xorpd_2 = "rmo:660F57rM", xorps_2 = "rmo:0F57rM", -- SSE3 ops fisttp_1 = "xw:nDF1m|xd:DB1m|xq:nDD1m", addsubpd_2 = "rmo:660FD0rM", addsubps_2 = "rmo:F20FD0rM", haddpd_2 = "rmo:660F7CrM", haddps_2 = "rmo:F20F7CrM", hsubpd_2 = "rmo:660F7DrM", hsubps_2 = "rmo:F20F7DrM", lddqu_2 = "rxo:F20FF0rM", movddup_2 = "rmo:F20F12rM", movshdup_2 = "rmo:F30F16rM", movsldup_2 = "rmo:F30F12rM", -- SSSE3 ops pabsb_2 = "rmo:660F381CrM", pabsd_2 = "rmo:660F381ErM", pabsw_2 = "rmo:660F381DrM", palignr_3 = "rmio:660F3A0FrMU", phaddd_2 = "rmo:660F3802rM", phaddsw_2 = "rmo:660F3803rM", phaddw_2 = "rmo:660F3801rM", phsubd_2 = "rmo:660F3806rM", phsubsw_2 = "rmo:660F3807rM", phsubw_2 = "rmo:660F3805rM", pmaddubsw_2 = "rmo:660F3804rM", pmulhrsw_2 = "rmo:660F380BrM", pshufb_2 = "rmo:660F3800rM", psignb_2 = "rmo:660F3808rM", psignd_2 = "rmo:660F380ArM", psignw_2 = "rmo:660F3809rM", -- SSE4.1 ops blendpd_3 = "rmio:660F3A0DrMU", blendps_3 = "rmio:660F3A0CrMU", blendvpd_3 = "rmRo:660F3815rM", blendvps_3 = "rmRo:660F3814rM", dppd_3 = "rmio:660F3A41rMU", dpps_3 = "rmio:660F3A40rMU", extractps_3 = "mri/do:660F3A17RmU|rri/qo:660F3A17RXmU", insertps_3 = "rrio:660F3A41rMU|rxi/od:", movntdqa_2 = "rxo:660F382ArM", mpsadbw_3 = "rmio:660F3A42rMU", packusdw_2 = "rmo:660F382BrM", pblendvb_3 = "rmRo:660F3810rM", pblendw_3 = "rmio:660F3A0ErMU", pcmpeqq_2 = "rmo:660F3829rM", pextrb_3 = "rri/do:660F3A14nRmU|rri/qo:|xri/bo:", pextrd_3 = "mri/do:660F3A16RmU", pextrq_3 = "mri/qo:660F3A16RmU", -- pextrw is SSE2, mem operand is SSE4.1 only phminposuw_2 = "rmo:660F3841rM", pinsrb_3 = "rri/od:660F3A20nrMU|rxi/ob:", pinsrd_3 = "rmi/od:660F3A22rMU", pinsrq_3 = "rmi/oq:660F3A22rXMU", pmaxsb_2 = "rmo:660F383CrM", pmaxsd_2 = "rmo:660F383DrM", pmaxud_2 = "rmo:660F383FrM", pmaxuw_2 = "rmo:660F383ErM", pminsb_2 = "rmo:660F3838rM", pminsd_2 = "rmo:660F3839rM", pminud_2 = "rmo:660F383BrM", pminuw_2 = "rmo:660F383ArM", pmovsxbd_2 = "rro:660F3821rM|rx/od:", pmovsxbq_2 = "rro:660F3822rM|rx/ow:", pmovsxbw_2 = "rro:660F3820rM|rx/oq:", pmovsxdq_2 = "rro:660F3825rM|rx/oq:", pmovsxwd_2 = "rro:660F3823rM|rx/oq:", pmovsxwq_2 = "rro:660F3824rM|rx/od:", pmovzxbd_2 = "rro:660F3831rM|rx/od:", pmovzxbq_2 = "rro:660F3832rM|rx/ow:", pmovzxbw_2 = "rro:660F3830rM|rx/oq:", pmovzxdq_2 = "rro:660F3835rM|rx/oq:", pmovzxwd_2 = "rro:660F3833rM|rx/oq:", pmovzxwq_2 = "rro:660F3834rM|rx/od:", pmuldq_2 = "rmo:660F3828rM", pmulld_2 = "rmo:660F3840rM", ptest_2 = "rmo:660F3817rM", roundpd_3 = "rmio:660F3A09rMU", roundps_3 = "rmio:660F3A08rMU", roundsd_3 = "rrio:660F3A0BrMU|rxi/oq:", roundss_3 = "rrio:660F3A0ArMU|rxi/od:", -- SSE4.2 ops crc32_2 = "rmqd:F20F38F1rM|rm/dw:66F20F38F1rM|rm/db:F20F38F0rM|rm/qb:", pcmpestri_3 = "rmio:660F3A61rMU", pcmpestrm_3 = "rmio:660F3A60rMU", pcmpgtq_2 = "rmo:660F3837rM", pcmpistri_3 = "rmio:660F3A63rMU", pcmpistrm_3 = "rmio:660F3A62rMU", popcnt_2 = "rmqdw:F30FB8rM", -- SSE4a extrq_2 = "rro:660F79rM", extrq_3 = "riio:660F780mUU", insertq_2 = "rro:F20F79rM", insertq_4 = "rriio:F20F78rMUU", lzcnt_2 = "rmqdw:F30FBDrM", movntsd_2 = "xr/qo:nF20F2BRm", movntss_2 = "xr/do:F30F2BRm", -- popcnt is also in SSE4.2 -- AES-NI aesdec_2 = "rmo:660F38DErM", aesdeclast_2 = "rmo:660F38DFrM", aesenc_2 = "rmo:660F38DCrM", aesenclast_2 = "rmo:660F38DDrM", aesimc_2 = "rmo:660F38DBrM", aeskeygenassist_3 = "rmio:660F3ADFrMU", pclmulqdq_3 = "rmio:660F3A44rMU", -- AVX FP ops vaddsubpd_3 = "rrmoy:660FVD0rM", vaddsubps_3 = "rrmoy:F20FVD0rM", vandpd_3 = "rrmoy:660FV54rM", vandps_3 = "rrmoy:0FV54rM", vandnpd_3 = "rrmoy:660FV55rM", vandnps_3 = "rrmoy:0FV55rM", vblendpd_4 = "rrmioy:660F3AV0DrMU", vblendps_4 = "rrmioy:660F3AV0CrMU", vblendvpd_4 = "rrmroy:660F3AV4BrMs", vblendvps_4 = "rrmroy:660F3AV4ArMs", vbroadcastf128_2 = "rx/yo:660F38u1ArM", vcmppd_4 = "rrmioy:660FVC2rMU", vcmpps_4 = "rrmioy:0FVC2rMU", vcmpsd_4 = "rrrio:F20FVC2rMU|rrxi/ooq:", vcmpss_4 = "rrrio:F30FVC2rMU|rrxi/ood:", vcomisd_2 = "rro:660Fu2FrM|rx/oq:", vcomiss_2 = "rro:0Fu2FrM|rx/od:", vcvtdq2pd_2 = "rro:F30FuE6rM|rx/oq:|rm/yo:", vcvtdq2ps_2 = "rmoy:0Fu5BrM", vcvtpd2dq_2 = "rmoy:F20FuE6rM", vcvtpd2ps_2 = "rmoy:660Fu5ArM", vcvtps2dq_2 = "rmoy:660Fu5BrM", vcvtps2pd_2 = "rro:0Fu5ArM|rx/oq:|rm/yo:", vcvtsd2si_2 = "rr/do:F20Fu2DrM|rx/dq:|rr/qo:|rxq:", vcvtsd2ss_3 = "rrro:F20FV5ArM|rrx/ooq:", vcvtsi2sd_3 = "rrm/ood:F20FV2ArM|rrm/ooq:F20FVX2ArM", vcvtsi2ss_3 = "rrm/ood:F30FV2ArM|rrm/ooq:F30FVX2ArM", vcvtss2sd_3 = "rrro:F30FV5ArM|rrx/ood:", vcvtss2si_2 = "rr/do:F30Fu2DrM|rxd:|rr/qo:|rx/qd:", vcvttpd2dq_2 = "rmo:660FuE6rM|rm/oy:660FuLE6rM", vcvttps2dq_2 = "rmoy:F30Fu5BrM", vcvttsd2si_2 = "rr/do:F20Fu2CrM|rx/dq:|rr/qo:|rxq:", vcvttss2si_2 = "rr/do:F30Fu2CrM|rxd:|rr/qo:|rx/qd:", vdppd_4 = "rrmio:660F3AV41rMU", vdpps_4 = "rrmioy:660F3AV40rMU", vextractf128_3 = "mri/oy:660F3AuL19RmU", vextractps_3 = "mri/do:660F3Au17RmU", vhaddpd_3 = "rrmoy:660FV7CrM", vhaddps_3 = "rrmoy:F20FV7CrM", vhsubpd_3 = "rrmoy:660FV7DrM", vhsubps_3 = "rrmoy:F20FV7DrM", vinsertf128_4 = "rrmi/yyo:660F3AV18rMU", vinsertps_4 = "rrrio:660F3AV21rMU|rrxi/ood:", vldmxcsr_1 = "xd:0FuAE2m", vmaskmovps_3 = "rrxoy:660F38V2CrM|xrroy:660F38V2ERm", vmaskmovpd_3 = "rrxoy:660F38V2DrM|xrroy:660F38V2FRm", vmovapd_2 = "rmoy:660Fu28rM|mroy:660Fu29Rm", vmovaps_2 = "rmoy:0Fu28rM|mroy:0Fu29Rm", vmovd_2 = "rm/od:660Fu6ErM|rm/oq:660FuX6ErM|mr/do:660Fu7ERm|mr/qo:", vmovq_2 = "rro:F30Fu7ErM|rx/oq:|xr/qo:660FuD6Rm", vmovddup_2 = "rmy:F20Fu12rM|rro:|rx/oq:", vmovhlps_3 = "rrro:0FV12rM", vmovhpd_2 = "xr/qo:660Fu17Rm", vmovhpd_3 = "rrx/ooq:660FV16rM", vmovhps_2 = "xr/qo:0Fu17Rm", vmovhps_3 = "rrx/ooq:0FV16rM", vmovlhps_3 = "rrro:0FV16rM", vmovlpd_2 = "xr/qo:660Fu13Rm", vmovlpd_3 = "rrx/ooq:660FV12rM", vmovlps_2 = "xr/qo:0Fu13Rm", vmovlps_3 = "rrx/ooq:0FV12rM", vmovmskpd_2 = "rr/do:660Fu50rM|rr/dy:660FuL50rM", vmovmskps_2 = "rr/do:0Fu50rM|rr/dy:0FuL50rM", vmovntpd_2 = "xroy:660Fu2BRm", vmovntps_2 = "xroy:0Fu2BRm", vmovsd_2 = "rx/oq:F20Fu10rM|xr/qo:F20Fu11Rm", vmovsd_3 = "rrro:F20FV10rM", vmovshdup_2 = "rmoy:F30Fu16rM", vmovsldup_2 = "rmoy:F30Fu12rM", vmovss_2 = "rx/od:F30Fu10rM|xr/do:F30Fu11Rm", vmovss_3 = "rrro:F30FV10rM", vmovupd_2 = "rmoy:660Fu10rM|mroy:660Fu11Rm", vmovups_2 = "rmoy:0Fu10rM|mroy:0Fu11Rm", vorpd_3 = "rrmoy:660FV56rM", vorps_3 = "rrmoy:0FV56rM", vpermilpd_3 = "rrmoy:660F38V0DrM|rmioy:660F3Au05rMU", vpermilps_3 = "rrmoy:660F38V0CrM|rmioy:660F3Au04rMU", vperm2f128_4 = "rrmiy:660F3AV06rMU", vptestpd_2 = "rmoy:660F38u0FrM", vptestps_2 = "rmoy:660F38u0ErM", vrcpps_2 = "rmoy:0Fu53rM", vrcpss_3 = "rrro:F30FV53rM|rrx/ood:", vrsqrtps_2 = "rmoy:0Fu52rM", vrsqrtss_3 = "rrro:F30FV52rM|rrx/ood:", vroundpd_3 = "rmioy:660F3Au09rMU", vroundps_3 = "rmioy:660F3Au08rMU", vroundsd_4 = "rrrio:660F3AV0BrMU|rrxi/ooq:", vroundss_4 = "rrrio:660F3AV0ArMU|rrxi/ood:", vshufpd_4 = "rrmioy:660FVC6rMU", vshufps_4 = "rrmioy:0FVC6rMU", vsqrtps_2 = "rmoy:0Fu51rM", vsqrtss_2 = "rro:F30Fu51rM|rx/od:", vsqrtpd_2 = "rmoy:660Fu51rM", vsqrtsd_2 = "rro:F20Fu51rM|rx/oq:", vstmxcsr_1 = "xd:0FuAE3m", vucomisd_2 = "rro:660Fu2ErM|rx/oq:", vucomiss_2 = "rro:0Fu2ErM|rx/od:", vunpckhpd_3 = "rrmoy:660FV15rM", vunpckhps_3 = "rrmoy:0FV15rM", vunpcklpd_3 = "rrmoy:660FV14rM", vunpcklps_3 = "rrmoy:0FV14rM", vxorpd_3 = "rrmoy:660FV57rM", vxorps_3 = "rrmoy:0FV57rM", vzeroall_0 = "0FuL77", vzeroupper_0 = "0Fu77", -- AVX2 FP ops vbroadcastss_2 = "rx/od:660F38u18rM|rx/yd:|rro:|rr/yo:", vbroadcastsd_2 = "rx/yq:660F38u19rM|rr/yo:", -- *vgather* (!vsib) vpermpd_3 = "rmiy:660F3AuX01rMU", vpermps_3 = "rrmy:660F38V16rM", -- AVX, AVX2 integer ops -- In general, xmm requires AVX, ymm requires AVX2. vaesdec_3 = "rrmo:660F38VDErM", vaesdeclast_3 = "rrmo:660F38VDFrM", vaesenc_3 = "rrmo:660F38VDCrM", vaesenclast_3 = "rrmo:660F38VDDrM", vaesimc_2 = "rmo:660F38uDBrM", vaeskeygenassist_3 = "rmio:660F3AuDFrMU", vlddqu_2 = "rxoy:F20FuF0rM", vmaskmovdqu_2 = "rro:660FuF7rM", vmovdqa_2 = "rmoy:660Fu6FrM|mroy:660Fu7FRm", vmovdqu_2 = "rmoy:F30Fu6FrM|mroy:F30Fu7FRm", vmovntdq_2 = "xroy:660FuE7Rm", vmovntdqa_2 = "rxoy:660F38u2ArM", vmpsadbw_4 = "rrmioy:660F3AV42rMU", vpabsb_2 = "rmoy:660F38u1CrM", vpabsd_2 = "rmoy:660F38u1ErM", vpabsw_2 = "rmoy:660F38u1DrM", vpackusdw_3 = "rrmoy:660F38V2BrM", vpalignr_4 = "rrmioy:660F3AV0FrMU", vpblendvb_4 = "rrmroy:660F3AV4CrMs", vpblendw_4 = "rrmioy:660F3AV0ErMU", vpclmulqdq_4 = "rrmio:660F3AV44rMU", vpcmpeqq_3 = "rrmoy:660F38V29rM", vpcmpestri_3 = "rmio:660F3Au61rMU", vpcmpestrm_3 = "rmio:660F3Au60rMU", vpcmpgtq_3 = "rrmoy:660F38V37rM", vpcmpistri_3 = "rmio:660F3Au63rMU", vpcmpistrm_3 = "rmio:660F3Au62rMU", vpextrb_3 = "rri/do:660F3Au14nRmU|rri/qo:|xri/bo:", vpextrw_3 = "rri/do:660FuC5rMU|xri/wo:660F3Au15nRmU", vpextrd_3 = "mri/do:660F3Au16RmU", vpextrq_3 = "mri/qo:660F3Au16RmU", vphaddw_3 = "rrmoy:660F38V01rM", vphaddd_3 = "rrmoy:660F38V02rM", vphaddsw_3 = "rrmoy:660F38V03rM", vphminposuw_2 = "rmo:660F38u41rM", vphsubw_3 = "rrmoy:660F38V05rM", vphsubd_3 = "rrmoy:660F38V06rM", vphsubsw_3 = "rrmoy:660F38V07rM", vpinsrb_4 = "rrri/ood:660F3AV20rMU|rrxi/oob:", vpinsrw_4 = "rrri/ood:660FVC4rMU|rrxi/oow:", vpinsrd_4 = "rrmi/ood:660F3AV22rMU", vpinsrq_4 = "rrmi/ooq:660F3AVX22rMU", vpmaddubsw_3 = "rrmoy:660F38V04rM", vpmaxsb_3 = "rrmoy:660F38V3CrM", vpmaxsd_3 = "rrmoy:660F38V3DrM", vpmaxuw_3 = "rrmoy:660F38V3ErM", vpmaxud_3 = "rrmoy:660F38V3FrM", vpminsb_3 = "rrmoy:660F38V38rM", vpminsd_3 = "rrmoy:660F38V39rM", vpminuw_3 = "rrmoy:660F38V3ArM", vpminud_3 = "rrmoy:660F38V3BrM", vpmovmskb_2 = "rr/do:660FuD7rM|rr/dy:660FuLD7rM", vpmovsxbw_2 = "rroy:660F38u20rM|rx/oq:|rx/yo:", vpmovsxbd_2 = "rroy:660F38u21rM|rx/od:|rx/yq:", vpmovsxbq_2 = "rroy:660F38u22rM|rx/ow:|rx/yd:", vpmovsxwd_2 = "rroy:660F38u23rM|rx/oq:|rx/yo:", vpmovsxwq_2 = "rroy:660F38u24rM|rx/od:|rx/yq:", vpmovsxdq_2 = "rroy:660F38u25rM|rx/oq:|rx/yo:", vpmovzxbw_2 = "rroy:660F38u30rM|rx/oq:|rx/yo:", vpmovzxbd_2 = "rroy:660F38u31rM|rx/od:|rx/yq:", vpmovzxbq_2 = "rroy:660F38u32rM|rx/ow:|rx/yd:", vpmovzxwd_2 = "rroy:660F38u33rM|rx/oq:|rx/yo:", vpmovzxwq_2 = "rroy:660F38u34rM|rx/od:|rx/yq:", vpmovzxdq_2 = "rroy:660F38u35rM|rx/oq:|rx/yo:", vpmuldq_3 = "rrmoy:660F38V28rM", vpmulhrsw_3 = "rrmoy:660F38V0BrM", vpmulld_3 = "rrmoy:660F38V40rM", vpshufb_3 = "rrmoy:660F38V00rM", vpshufd_3 = "rmioy:660Fu70rMU", vpshufhw_3 = "rmioy:F30Fu70rMU", vpshuflw_3 = "rmioy:F20Fu70rMU", vpsignb_3 = "rrmoy:660F38V08rM", vpsignw_3 = "rrmoy:660F38V09rM", vpsignd_3 = "rrmoy:660F38V0ArM", vpslldq_3 = "rrioy:660Fv737mU", vpsllw_3 = "rrmoy:660FVF1rM|rrioy:660Fv716mU", vpslld_3 = "rrmoy:660FVF2rM|rrioy:660Fv726mU", vpsllq_3 = "rrmoy:660FVF3rM|rrioy:660Fv736mU", vpsraw_3 = "rrmoy:660FVE1rM|rrioy:660Fv714mU", vpsrad_3 = "rrmoy:660FVE2rM|rrioy:660Fv724mU", vpsrldq_3 = "rrioy:660Fv733mU", vpsrlw_3 = "rrmoy:660FVD1rM|rrioy:660Fv712mU", vpsrld_3 = "rrmoy:660FVD2rM|rrioy:660Fv722mU", vpsrlq_3 = "rrmoy:660FVD3rM|rrioy:660Fv732mU", vptest_2 = "rmoy:660F38u17rM", -- AVX2 integer ops vbroadcasti128_2 = "rx/yo:660F38u5ArM", vinserti128_4 = "rrmi/yyo:660F3AV38rMU", vextracti128_3 = "mri/oy:660F3AuL39RmU", vpblendd_4 = "rrmioy:660F3AV02rMU", vpbroadcastb_2 = "rro:660F38u78rM|rx/ob:|rr/yo:|rx/yb:", vpbroadcastw_2 = "rro:660F38u79rM|rx/ow:|rr/yo:|rx/yw:", vpbroadcastd_2 = "rro:660F38u58rM|rx/od:|rr/yo:|rx/yd:", vpbroadcastq_2 = "rro:660F38u59rM|rx/oq:|rr/yo:|rx/yq:", vpermd_3 = "rrmy:660F38V36rM", vpermq_3 = "rmiy:660F3AuX00rMU", -- *vpgather* (!vsib) vperm2i128_4 = "rrmiy:660F3AV46rMU", vpmaskmovd_3 = "rrxoy:660F38V8CrM|xrroy:660F38V8ERm", vpmaskmovq_3 = "rrxoy:660F38VX8CrM|xrroy:660F38VX8ERm", vpsllvd_3 = "rrmoy:660F38V47rM", vpsllvq_3 = "rrmoy:660F38VX47rM", vpsravd_3 = "rrmoy:660F38V46rM", vpsrlvd_3 = "rrmoy:660F38V45rM", vpsrlvq_3 = "rrmoy:660F38VX45rM", -- Intel ADX adcx_2 = "rmqd:660F38F6rM", adox_2 = "rmqd:F30F38F6rM", -- BMI1 andn_3 = "rrmqd:0F38VF2rM", bextr_3 = "rmrqd:0F38wF7rM", blsi_2 = "rmqd:0F38vF33m", blsmsk_2 = "rmqd:0F38vF32m", blsr_2 = "rmqd:0F38vF31m", tzcnt_2 = "rmqdw:F30FBCrM", -- BMI2 bzhi_3 = "rmrqd:0F38wF5rM", mulx_3 = "rrmqd:F20F38VF6rM", pdep_3 = "rrmqd:F20F38VF5rM", pext_3 = "rrmqd:F30F38VF5rM", rorx_3 = "rmSqd:F20F3AuF0rMS", sarx_3 = "rmrqd:F30F38wF7rM", shrx_3 = "rmrqd:F20F38wF7rM", shlx_3 = "rmrqd:660F38wF7rM", -- FMA3 vfmaddsub132pd_3 = "rrmoy:660F38VX96rM", vfmaddsub132ps_3 = "rrmoy:660F38V96rM", vfmaddsub213pd_3 = "rrmoy:660F38VXA6rM", vfmaddsub213ps_3 = "rrmoy:660F38VA6rM", vfmaddsub231pd_3 = "rrmoy:660F38VXB6rM", vfmaddsub231ps_3 = "rrmoy:660F38VB6rM", vfmsubadd132pd_3 = "rrmoy:660F38VX97rM", vfmsubadd132ps_3 = "rrmoy:660F38V97rM", vfmsubadd213pd_3 = "rrmoy:660F38VXA7rM", vfmsubadd213ps_3 = "rrmoy:660F38VA7rM", vfmsubadd231pd_3 = "rrmoy:660F38VXB7rM", vfmsubadd231ps_3 = "rrmoy:660F38VB7rM", vfmadd132pd_3 = "rrmoy:660F38VX98rM", vfmadd132ps_3 = "rrmoy:660F38V98rM", vfmadd132sd_3 = "rrro:660F38VX99rM|rrx/ooq:", vfmadd132ss_3 = "rrro:660F38V99rM|rrx/ood:", vfmadd213pd_3 = "rrmoy:660F38VXA8rM", vfmadd213ps_3 = "rrmoy:660F38VA8rM", vfmadd213sd_3 = "rrro:660F38VXA9rM|rrx/ooq:", vfmadd213ss_3 = "rrro:660F38VA9rM|rrx/ood:", vfmadd231pd_3 = "rrmoy:660F38VXB8rM", vfmadd231ps_3 = "rrmoy:660F38VB8rM", vfmadd231sd_3 = "rrro:660F38VXB9rM|rrx/ooq:", vfmadd231ss_3 = "rrro:660F38VB9rM|rrx/ood:", vfmsub132pd_3 = "rrmoy:660F38VX9ArM", vfmsub132ps_3 = "rrmoy:660F38V9ArM", vfmsub132sd_3 = "rrro:660F38VX9BrM|rrx/ooq:", vfmsub132ss_3 = "rrro:660F38V9BrM|rrx/ood:", vfmsub213pd_3 = "rrmoy:660F38VXAArM", vfmsub213ps_3 = "rrmoy:660F38VAArM", vfmsub213sd_3 = "rrro:660F38VXABrM|rrx/ooq:", vfmsub213ss_3 = "rrro:660F38VABrM|rrx/ood:", vfmsub231pd_3 = "rrmoy:660F38VXBArM", vfmsub231ps_3 = "rrmoy:660F38VBArM", vfmsub231sd_3 = "rrro:660F38VXBBrM|rrx/ooq:", vfmsub231ss_3 = "rrro:660F38VBBrM|rrx/ood:", vfnmadd132pd_3 = "rrmoy:660F38VX9CrM", vfnmadd132ps_3 = "rrmoy:660F38V9CrM", vfnmadd132sd_3 = "rrro:660F38VX9DrM|rrx/ooq:", vfnmadd132ss_3 = "rrro:660F38V9DrM|rrx/ood:", vfnmadd213pd_3 = "rrmoy:660F38VXACrM", vfnmadd213ps_3 = "rrmoy:660F38VACrM", vfnmadd213sd_3 = "rrro:660F38VXADrM|rrx/ooq:", vfnmadd213ss_3 = "rrro:660F38VADrM|rrx/ood:", vfnmadd231pd_3 = "rrmoy:660F38VXBCrM", vfnmadd231ps_3 = "rrmoy:660F38VBCrM", vfnmadd231sd_3 = "rrro:660F38VXBDrM|rrx/ooq:", vfnmadd231ss_3 = "rrro:660F38VBDrM|rrx/ood:", vfnmsub132pd_3 = "rrmoy:660F38VX9ErM", vfnmsub132ps_3 = "rrmoy:660F38V9ErM", vfnmsub132sd_3 = "rrro:660F38VX9FrM|rrx/ooq:", vfnmsub132ss_3 = "rrro:660F38V9FrM|rrx/ood:", vfnmsub213pd_3 = "rrmoy:660F38VXAErM", vfnmsub213ps_3 = "rrmoy:660F38VAErM", vfnmsub213sd_3 = "rrro:660F38VXAFrM|rrx/ooq:", vfnmsub213ss_3 = "rrro:660F38VAFrM|rrx/ood:", vfnmsub231pd_3 = "rrmoy:660F38VXBErM", vfnmsub231ps_3 = "rrmoy:660F38VBErM", vfnmsub231sd_3 = "rrro:660F38VXBFrM|rrx/ooq:", vfnmsub231ss_3 = "rrro:660F38VBFrM|rrx/ood:", } ------------------------------------------------------------------------------ -- Arithmetic ops. for name,n in pairs{ add = 0, ["or"] = 1, adc = 2, sbb = 3, ["and"] = 4, sub = 5, xor = 6, cmp = 7 } do local n8 = shl(n, 3) map_op[name.."_2"] = format( "mr:%02XRm|rm:%02XrM|mI1qdw:81%XmI|mS1qdw:83%XmS|Ri1qdwb:%02Xri|mi1qdwb:81%Xmi", 1+n8, 3+n8, n, n, 5+n8, n) end -- Shift ops. for name,n in pairs{ rol = 0, ror = 1, rcl = 2, rcr = 3, shl = 4, shr = 5, sar = 7, sal = 4 } do map_op[name.."_2"] = format("m1:D1%Xm|mC1qdwb:D3%Xm|mi:C1%XmU", n, n, n) end -- Conditional ops. for cc,n in pairs(map_cc) do map_op["j"..cc.."_1"] = format("J.:n0F8%XJ", n) -- short: 7%X map_op["set"..cc.."_1"] = format("mb:n0F9%X2m", n) map_op["cmov"..cc.."_2"] = format("rmqdw:0F4%XrM", n) -- P6+ end -- FP arithmetic ops. for name,n in pairs{ add = 0, mul = 1, com = 2, comp = 3, sub = 4, subr = 5, div = 6, divr = 7 } do local nc = 0xc0 + shl(n, 3) local nr = nc + (n < 4 and 0 or (n % 2 == 0 and 8 or -8)) local fn = "f"..name map_op[fn.."_1"] = format("ff:D8%02Xr|xd:D8%Xm|xq:nDC%Xm", nc, n, n) if n == 2 or n == 3 then map_op[fn.."_2"] = format("Fff:D8%02XR|Fx2d:D8%XM|Fx2q:nDC%XM", nc, n, n) else map_op[fn.."_2"] = format("Fff:D8%02XR|fFf:DC%02Xr|Fx2d:D8%XM|Fx2q:nDC%XM", nc, nr, n, n) map_op[fn.."p_1"] = format("ff:DE%02Xr", nr) map_op[fn.."p_2"] = format("fFf:DE%02Xr", nr) end map_op["fi"..name.."_1"] = format("xd:DA%Xm|xw:nDE%Xm", n, n) end -- FP conditional moves. for cc,n in pairs{ b=0, e=1, be=2, u=3, nb=4, ne=5, nbe=6, nu=7 } do local nc = 0xdac0 + shl(band(n, 3), 3) + shl(band(n, 4), 6) map_op["fcmov"..cc.."_1"] = format("ff:%04Xr", nc) -- P6+ map_op["fcmov"..cc.."_2"] = format("Fff:%04XR", nc) -- P6+ end -- SSE / AVX FP arithmetic ops. for name,n in pairs{ sqrt = 1, add = 8, mul = 9, sub = 12, min = 13, div = 14, max = 15 } do map_op[name.."ps_2"] = format("rmo:0F5%XrM", n) map_op[name.."ss_2"] = format("rro:F30F5%XrM|rx/od:", n) map_op[name.."pd_2"] = format("rmo:660F5%XrM", n) map_op[name.."sd_2"] = format("rro:F20F5%XrM|rx/oq:", n) if n ~= 1 then map_op["v"..name.."ps_3"] = format("rrmoy:0FV5%XrM", n) map_op["v"..name.."ss_3"] = format("rrro:F30FV5%XrM|rrx/ood:", n) map_op["v"..name.."pd_3"] = format("rrmoy:660FV5%XrM", n) map_op["v"..name.."sd_3"] = format("rrro:F20FV5%XrM|rrx/ooq:", n) end end -- SSE2 / AVX / AVX2 integer arithmetic ops (66 0F leaf). for name,n in pairs{ paddb = 0xFC, paddw = 0xFD, paddd = 0xFE, paddq = 0xD4, paddsb = 0xEC, paddsw = 0xED, packssdw = 0x6B, packsswb = 0x63, packuswb = 0x67, paddusb = 0xDC, paddusw = 0xDD, pand = 0xDB, pandn = 0xDF, pavgb = 0xE0, pavgw = 0xE3, pcmpeqb = 0x74, pcmpeqd = 0x76, pcmpeqw = 0x75, pcmpgtb = 0x64, pcmpgtd = 0x66, pcmpgtw = 0x65, pmaddwd = 0xF5, pmaxsw = 0xEE, pmaxub = 0xDE, pminsw = 0xEA, pminub = 0xDA, pmulhuw = 0xE4, pmulhw = 0xE5, pmullw = 0xD5, pmuludq = 0xF4, por = 0xEB, psadbw = 0xF6, psubb = 0xF8, psubw = 0xF9, psubd = 0xFA, psubq = 0xFB, psubsb = 0xE8, psubsw = 0xE9, psubusb = 0xD8, psubusw = 0xD9, punpckhbw = 0x68, punpckhwd = 0x69, punpckhdq = 0x6A, punpckhqdq = 0x6D, punpcklbw = 0x60, punpcklwd = 0x61, punpckldq = 0x62, punpcklqdq = 0x6C, pxor = 0xEF } do map_op[name.."_2"] = format("rmo:660F%02XrM", n) map_op["v"..name.."_3"] = format("rrmoy:660FV%02XrM", n) end ------------------------------------------------------------------------------ local map_vexarg = { u = false, v = 1, V = 2, w = 3 } -- Process pattern string. local function dopattern(pat, args, sz, op, needrex) local digit, addin, vex local opcode = 0 local szov = sz local narg = 1 local rex = 0 -- Limit number of section buffer positions used by a single dasm_put(). -- A single opcode needs a maximum of 6 positions. if secpos+6 > maxsecpos then wflush() end -- Process each character. for c in gmatch(pat.."|", ".") do if match(c, "%x") then -- Hex digit. digit = byte(c) - 48 if digit > 48 then digit = digit - 39 elseif digit > 16 then digit = digit - 7 end opcode = opcode*16 + digit addin = nil elseif c == "n" then -- Disable operand size mods for opcode. szov = nil elseif c == "X" then -- Force REX.W. rex = 8 elseif c == "L" then -- Force VEX.L. vex.l = true elseif c == "r" then -- Merge 1st operand regno. into opcode. addin = args[1]; opcode = opcode + (addin.reg % 8) if narg < 2 then narg = 2 end elseif c == "R" then -- Merge 2nd operand regno. into opcode. addin = args[2]; opcode = opcode + (addin.reg % 8) narg = 3 elseif c == "m" or c == "M" then -- Encode ModRM/SIB. local s if addin then s = addin.reg opcode = opcode - band(s, 7) -- Undo regno opcode merge. else s = band(opcode, 15) -- Undo last digit. opcode = shr(opcode, 4) end local nn = c == "m" and 1 or 2 local t = args[nn] if narg <= nn then narg = nn + 1 end if szov == "q" and rex == 0 then rex = rex + 8 end if t.reg and t.reg > 7 then rex = rex + 1 end if t.xreg and t.xreg > 7 then rex = rex + 2 end if s > 7 then rex = rex + 4 end if needrex then rex = rex + 16 end local psz, sk = wputop(szov, opcode, rex, vex, s < 0, t.vreg or t.vxreg) opcode = nil local imark = sub(pat, -1) -- Force a mark (ugly). -- Put ModRM/SIB with regno/last digit as spare. wputmrmsib(t, imark, s, addin and addin.vreg, psz, sk) addin = nil elseif map_vexarg[c] ~= nil then -- Encode using VEX prefix local b = band(opcode, 255); opcode = shr(opcode, 8) local m = 1 if b == 0x38 then m = 2 elseif b == 0x3a then m = 3 end if m ~= 1 then b = band(opcode, 255); opcode = shr(opcode, 8) end if b ~= 0x0f then werror("expected `0F', `0F38', or `0F3A' to precede `"..c.. "' in pattern `"..pat.."' for `"..op.."'") end local v = map_vexarg[c] if v then v = remove(args, v) end b = band(opcode, 255) local p = 0 if b == 0x66 then p = 1 elseif b == 0xf3 then p = 2 elseif b == 0xf2 then p = 3 end if p ~= 0 then opcode = shr(opcode, 8) end if opcode ~= 0 then wputop(nil, opcode, 0); opcode = 0 end vex = { m = m, p = p, v = v } else if opcode then -- Flush opcode. if szov == "q" and rex == 0 then rex = rex + 8 end if needrex then rex = rex + 16 end if addin and addin.reg == -1 then local psz, sk = wputop(szov, opcode - 7, rex, vex, true) wvreg("opcode", addin.vreg, psz, sk) else if addin and addin.reg > 7 then rex = rex + 1 end wputop(szov, opcode, rex, vex) end opcode = nil end if c == "|" then break end if c == "o" then -- Offset (pure 32 bit displacement). wputdarg(args[1].disp); if narg < 2 then narg = 2 end elseif c == "O" then wputdarg(args[2].disp); narg = 3 else -- Anything else is an immediate operand. local a = args[narg] narg = narg + 1 local mode, imm = a.mode, a.imm if mode == "iJ" and not match(x64 and "J" or "iIJ", c) then werror("bad operand size for label") end if c == "S" then wputsbarg(imm) elseif c == "U" then wputbarg(imm) elseif c == "W" then wputwarg(imm) elseif c == "i" or c == "I" then if mode == "iJ" then wputlabel("IMM_", imm, 1) elseif mode == "iI" and c == "I" then waction(sz == "w" and "IMM_WB" or "IMM_DB", imm) else wputszarg(sz, imm) end elseif c == "J" then if mode == "iPJ" then waction("REL_A", imm) -- !x64 (secpos) else wputlabel("REL_", imm, 2) end elseif c == "s" then local reg = a.reg if reg < 0 then wputb(0) wvreg("imm.hi", a.vreg) else wputb(shl(reg, 4)) end else werror("bad char `"..c.."' in pattern `"..pat.."' for `"..op.."'") end end end end end ------------------------------------------------------------------------------ -- Mapping of operand modes to short names. Suppress output with '#'. local map_modename = { r = "reg", R = "eax", C = "cl", x = "mem", m = "mrm", i = "imm", f = "stx", F = "st0", J = "lbl", ["1"] = "1", I = "#", S = "#", O = "#", } -- Return a table/string showing all possible operand modes. local function templatehelp(template, nparams) if nparams == 0 then return "" end local t = {} for tm in gmatch(template, "[^%|]+") do local s = map_modename[sub(tm, 1, 1)] s = s..gsub(sub(tm, 2, nparams), ".", function(c) return ", "..map_modename[c] end) if not match(s, "#") then t[#t+1] = s end end return t end -- Match operand modes against mode match part of template. local function matchtm(tm, args) for i=1,#args do if not match(args[i].mode, sub(tm, i, i)) then return end end return true end -- Handle opcodes defined with template strings. map_op[".template__"] = function(params, template, nparams) if not params then return templatehelp(template, nparams) end local args = {} -- Zero-operand opcodes have no match part. if #params == 0 then dopattern(template, args, "d", params.op, nil) return end -- Determine common operand size (coerce undefined size) or flag as mixed. local sz, szmix, needrex for i,p in ipairs(params) do args[i] = parseoperand(p) local nsz = args[i].opsize if nsz then if sz and sz ~= nsz then szmix = true else sz = nsz end end local nrex = args[i].needrex if nrex ~= nil then if needrex == nil then needrex = nrex elseif needrex ~= nrex then werror("bad mix of byte-addressable registers") end end end -- Try all match:pattern pairs (separated by '|'). local gotmatch, lastpat for tm in gmatch(template, "[^%|]+") do -- Split off size match (starts after mode match) and pattern string. local szm, pat = match(tm, "^(.-):(.*)$", #args+1) if pat == "" then pat = lastpat else lastpat = pat end if matchtm(tm, args) then local prefix = sub(szm, 1, 1) if prefix == "/" then -- Exactly match leading operand sizes. for i = #szm,1,-1 do if i == 1 then dopattern(pat, args, sz, params.op, needrex) -- Process pattern. return elseif args[i-1].opsize ~= sub(szm, i, i) then break end end else -- Match common operand size. local szp = sz if szm == "" then szm = x64 and "qdwb" or "dwb" end -- Default sizes. if prefix == "1" then szp = args[1].opsize; szmix = nil elseif prefix == "2" then szp = args[2].opsize; szmix = nil end if not szmix and (prefix == "." or match(szm, szp or "#")) then dopattern(pat, args, szp, params.op, needrex) -- Process pattern. return end end gotmatch = true end end local msg = "bad operand mode" if gotmatch then if szmix then msg = "mixed operand size" else msg = sz and "bad operand size" or "missing operand size" end end werror(msg.." in `"..opmodestr(params.op, args).."'") end ------------------------------------------------------------------------------ -- x64-specific opcode for 64 bit immediates and displacements. if x64 then function map_op.mov64_2(params) if not params then return { "reg, imm", "reg, [disp]", "[disp], reg" } end if secpos+2 > maxsecpos then wflush() end local opcode, op64, sz, rex, vreg local op64 = match(params[1], "^%[%s*(.-)%s*%]$") if op64 then local a = parseoperand(params[2]) if a.mode ~= "rmR" then werror("bad operand mode") end sz = a.opsize rex = sz == "q" and 8 or 0 opcode = 0xa3 else op64 = match(params[2], "^%[%s*(.-)%s*%]$") local a = parseoperand(params[1]) if op64 then if a.mode ~= "rmR" then werror("bad operand mode") end sz = a.opsize rex = sz == "q" and 8 or 0 opcode = 0xa1 else if sub(a.mode, 1, 1) ~= "r" or a.opsize ~= "q" then werror("bad operand mode") end op64 = params[2] if a.reg == -1 then vreg = a.vreg opcode = 0xb8 else opcode = 0xb8 + band(a.reg, 7) end rex = a.reg > 7 and 9 or 8 end end local psz, sk = wputop(sz, opcode, rex, nil, vreg) wvreg("opcode", vreg, psz, sk) waction("IMM_D", format("(unsigned int)(%s)", op64)) waction("IMM_D", format("(unsigned int)((%s)>>32)", op64)) end end ------------------------------------------------------------------------------ -- Pseudo-opcodes for data storage. local function op_data(params) if not params then return "imm..." end local sz = sub(params.op, 2, 2) if sz == "l" then sz = "d" elseif sz == "a" then sz = addrsize end for _,p in ipairs(params) do local a = parseoperand(p, sz == "q") if sub(a.mode, 1, 1) ~= "i" or (a.opsize and a.opsize ~= sz) then werror("bad mode or size in `"..p.."'") end if a.mode == "iJ" then wputlabel("IMM_", a.imm, 1) elseif sz == "q" then wputqarg(a.imm) else wputszarg(sz, a.imm) end if secpos+2 > maxsecpos then wflush() end end end map_op[".byte_*"] = op_data map_op[".sbyte_*"] = op_data map_op[".word_*"] = op_data map_op[".dword_*"] = op_data map_op[".qword_*"] = op_data map_op[".aword_*"] = op_data map_op[".long_*"] = op_data map_op[".quad_*"] = op_data map_op[".addr_*"] = op_data ------------------------------------------------------------------------------ -- Pseudo-opcode to mark the position where the action list is to be emitted. map_op[".actionlist_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeactions(out, name) end) end -- Pseudo-opcode to mark the position where the global enum is to be emitted. map_op[".globals_1"] = function(params) if not params then return "prefix" end local prefix = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobals(out, prefix) end) end -- Pseudo-opcode to mark the position where the global names are to be emitted. map_op[".globalnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobalnames(out, name) end) end -- Pseudo-opcode to mark the position where the extern names are to be emitted. map_op[".externnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeexternnames(out, name) end) end ------------------------------------------------------------------------------ -- Label pseudo-opcode (converted from trailing colon form). map_op[".label_2"] = function(params) if not params then return "[1-9] | ->global | =>pcexpr [, addr]" end if secpos+2 > maxsecpos then wflush() end local a = parseoperand(params[1]) local mode, imm = a.mode, a.imm if type(imm) == "number" and (mode == "iJ" or (imm >= 1 and imm <= 9)) then -- Local label (1: ... 9:) or global label (->global:). waction("LABEL_LG", nil, 1) wputxb(imm) elseif mode == "iJ" then -- PC label (=>pcexpr:). waction("LABEL_PC", imm) else werror("bad label definition") end -- SETLABEL must immediately follow LABEL_LG/LABEL_PC. local addr = params[2] if addr then local a = parseoperand(addr) if a.mode == "iPJ" then waction("SETLABEL", a.imm) else werror("bad label assignment") end end end map_op[".label_1"] = map_op[".label_2"] ------------------------------------------------------------------------------ -- Alignment pseudo-opcode. map_op[".align_1"] = function(params) if not params then return "numpow2" end if secpos+1 > maxsecpos then wflush() end local align = tonumber(params[1]) or map_opsizenum[map_opsize[params[1]]] if align then local x = align -- Must be a power of 2 in the range (2 ... 256). for i=1,8 do x = x / 2 if x == 1 then waction("ALIGN", nil, 1) wputxb(align-1) -- Action byte is 2**n-1. return end end end werror("bad alignment") end -- Spacing pseudo-opcode. map_op[".space_2"] = function(params) if not params then return "num [, filler]" end if secpos+1 > maxsecpos then wflush() end waction("SPACE", params[1]) local fill = params[2] if fill then fill = tonumber(fill) if not fill or fill < 0 or fill > 255 then werror("bad filler") end end wputxb(fill or 0) end map_op[".space_1"] = map_op[".space_2"] ------------------------------------------------------------------------------ -- Pseudo-opcode for (primitive) type definitions (map to C types). map_op[".type_3"] = function(params, nparams) if not params then return nparams == 2 and "name, ctype" or "name, ctype, reg" end local name, ctype, reg = params[1], params[2], params[3] if not match(name, "^[%a_][%w_]*$") then werror("bad type name `"..name.."'") end local tp = map_type[name] if tp then werror("duplicate type `"..name.."'") end if reg and not map_reg_valid_base[reg] then werror("bad base register `"..(map_reg_rev[reg] or reg).."'") end -- Add #type to defines. A bit unclean to put it in map_archdef. map_archdef["#"..name] = "sizeof("..ctype..")" -- Add new type and emit shortcut define. local num = ctypenum + 1 map_type[name] = { ctype = ctype, ctypefmt = format("Dt%X(%%s)", num), reg = reg, } wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) ctypenum = num end map_op[".type_2"] = map_op[".type_3"] -- Dump type definitions. local function dumptypes(out, lvl) local t = {} for name in pairs(map_type) do t[#t+1] = name end sort(t) out:write("Type definitions:\n") for _,name in ipairs(t) do local tp = map_type[name] local reg = tp.reg and map_reg_rev[tp.reg] or "" out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) end out:write("\n") end ------------------------------------------------------------------------------ -- Set the current section. function _M.section(num) waction("SECTION") wputxb(num) wflush(true) -- SECTION is a terminal action. end ------------------------------------------------------------------------------ -- Dump architecture description. function _M.dumparch(out) out:write(format("DynASM %s version %s, released %s\n\n", _info.arch, _info.version, _info.release)) dumpregs(out) dumpactions(out) end -- Dump all user defined elements. function _M.dumpdef(out, lvl) dumptypes(out, lvl) dumpglobals(out, lvl) dumpexterns(out, lvl) end ------------------------------------------------------------------------------ -- Pass callbacks from/to the DynASM core. function _M.passcb(wl, we, wf, ww) wline, werror, wfatal, wwarn = wl, we, wf, ww return wflush end -- Setup the arch-specific module. function _M.setup(arch, opt) g_arch, g_opt = arch, opt end -- Merge the core maps and the arch-specific maps. function _M.mergemaps(map_coreop, map_def) setmetatable(map_op, { __index = map_coreop }) setmetatable(map_def, { __index = map_archdef }) return map_op, map_def end return _M ------------------------------------------------------------------------------ ================================================ FILE: third_party/luajit/luajit/dynasm/dynasm.lua ================================================ ------------------------------------------------------------------------------ -- DynASM. A dynamic assembler for code generation engines. -- Originally designed and implemented for LuaJIT. -- -- Copyright (C) 2005-2022 Mike Pall. All rights reserved. -- See below for full copyright notice. ------------------------------------------------------------------------------ -- Application information. local _info = { name = "DynASM", description = "A dynamic assembler for code generation engines", version = "1.5.0", vernum = 10500, release = "2021-05-02", author = "Mike Pall", url = "https://luajit.org/dynasm.html", license = "MIT", copyright = [[ Copyright (C) 2005-2022 Mike Pall. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. [ MIT license: https://www.opensource.org/licenses/mit-license.php ] ]], } -- Cache library functions. local type, pairs, ipairs = type, pairs, ipairs local pcall, error, assert = pcall, error, assert local _s = string local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub local format, rep, upper = _s.format, _s.rep, _s.upper local _t = table local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort local exit = os.exit local io = io local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr ------------------------------------------------------------------------------ -- Program options. local g_opt = {} -- Global state for current file. local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch local g_errcount = 0 -- Write buffer for output file. local g_wbuffer, g_capbuffer ------------------------------------------------------------------------------ -- Write an output line (or callback function) to the buffer. local function wline(line, needindent) local buf = g_capbuffer or g_wbuffer buf[#buf+1] = needindent and g_indent..line or line g_synclineno = g_synclineno + 1 end -- Write assembler line as a comment, if requestd. local function wcomment(aline) if g_opt.comment then wline(g_opt.comment..aline..g_opt.endcomment, true) end end -- Resync CPP line numbers. local function wsync() if g_synclineno ~= g_lineno and g_opt.cpp then wline("#line "..g_lineno..' "'..g_fname..'"') g_synclineno = g_lineno end end -- Dummy action flush function. Replaced with arch-specific function later. local function wflush(term) end -- Dump all buffered output lines. local function wdumplines(out, buf) for _,line in ipairs(buf) do if type(line) == "string" then assert(out:write(line, "\n")) else -- Special callback to dynamically insert lines after end of processing. line(out) end end end ------------------------------------------------------------------------------ -- Emit an error. Processing continues with next statement. local function werror(msg) error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0) end -- Emit a fatal error. Processing stops. local function wfatal(msg) g_errcount = "fatal" werror(msg) end -- Print a warning. Processing continues. local function wwarn(msg) stderr:write(format("%s:%s: warning: %s:\n%s\n", g_fname, g_lineno, msg, g_curline)) end -- Print caught error message. But suppress excessive errors. local function wprinterr(...) if type(g_errcount) == "number" then -- Regular error. g_errcount = g_errcount + 1 if g_errcount < 21 then -- Seems to be a reasonable limit. stderr:write(...) elseif g_errcount == 21 then stderr:write(g_fname, ":*: warning: too many errors (suppressed further messages).\n") end else -- Fatal error. stderr:write(...) return true -- Stop processing. end end ------------------------------------------------------------------------------ -- Map holding all option handlers. local opt_map = {} local opt_current -- Print error and exit with error status. local function opterror(...) stderr:write("dynasm.lua: ERROR: ", ...) stderr:write("\n") exit(1) end -- Get option parameter. local function optparam(args) local argn = args.argn local p = args[argn] if not p then opterror("missing parameter for option `", opt_current, "'.") end args.argn = argn + 1 return p end ------------------------------------------------------------------------------ -- Core pseudo-opcodes. local map_coreop = {} -- Dummy opcode map. Replaced by arch-specific map. local map_op = {} -- Forward declarations. local dostmt local readfile ------------------------------------------------------------------------------ -- Map for defines (initially empty, chains to arch-specific map). local map_def = {} -- Pseudo-opcode to define a substitution. map_coreop[".define_2"] = function(params, nparams) if not params then return nparams == 1 and "name" or "name, subst" end local name, def = params[1], params[2] or "1" if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end map_def[name] = def end map_coreop[".define_1"] = map_coreop[".define_2"] -- Define a substitution on the command line. function opt_map.D(args) local namesubst = optparam(args) local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$") if name then map_def[name] = subst elseif match(namesubst, "^[%a_][%w_]*$") then map_def[namesubst] = "1" else opterror("bad define") end end -- Undefine a substitution on the command line. function opt_map.U(args) local name = optparam(args) if match(name, "^[%a_][%w_]*$") then map_def[name] = nil else opterror("bad define") end end -- Helper for definesubst. local gotsubst local function definesubst_one(word) local subst = map_def[word] if subst then gotsubst = word; return subst else return word end end -- Iteratively substitute defines. local function definesubst(stmt) -- Limit number of iterations. for i=1,100 do gotsubst = false stmt = gsub(stmt, "#?[%w_]+", definesubst_one) if not gotsubst then break end end if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end return stmt end -- Dump all defines. local function dumpdefines(out, lvl) local t = {} for name in pairs(map_def) do t[#t+1] = name end sort(t) out:write("Defines:\n") for _,name in ipairs(t) do local subst = map_def[name] if g_arch then subst = g_arch.revdef(subst) end out:write(format(" %-20s %s\n", name, subst)) end out:write("\n") end ------------------------------------------------------------------------------ -- Support variables for conditional assembly. local condlevel = 0 local condstack = {} -- Evaluate condition with a Lua expression. Substitutions already performed. local function cond_eval(cond) local func, err if setfenv then func, err = loadstring("return "..cond, "=expr") else -- No globals. All unknown identifiers evaluate to nil. func, err = load("return "..cond, "=expr", "t", {}) end if func then if setfenv then setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil. end local ok, res = pcall(func) if ok then if res == 0 then return false end -- Oh well. return not not res end err = res end wfatal("bad condition: "..err) end -- Skip statements until next conditional pseudo-opcode at the same level. local function stmtskip() local dostmt_save = dostmt local lvl = 0 dostmt = function(stmt) local op = match(stmt, "^%s*(%S+)") if op == ".if" then lvl = lvl + 1 elseif lvl ~= 0 then if op == ".endif" then lvl = lvl - 1 end elseif op == ".elif" or op == ".else" or op == ".endif" then dostmt = dostmt_save dostmt(stmt) end end end -- Pseudo-opcodes for conditional assembly. map_coreop[".if_1"] = function(params) if not params then return "condition" end local lvl = condlevel + 1 local res = cond_eval(params[1]) condlevel = lvl condstack[lvl] = res if not res then stmtskip() end end map_coreop[".elif_1"] = function(params) if not params then return "condition" end if condlevel == 0 then wfatal(".elif without .if") end local lvl = condlevel local res = condstack[lvl] if res then if res == "else" then wfatal(".elif after .else") end else res = cond_eval(params[1]) if res then condstack[lvl] = res return end end stmtskip() end map_coreop[".else_0"] = function(params) if condlevel == 0 then wfatal(".else without .if") end local lvl = condlevel local res = condstack[lvl] condstack[lvl] = "else" if res then if res == "else" then wfatal(".else after .else") end stmtskip() end end map_coreop[".endif_0"] = function(params) local lvl = condlevel if lvl == 0 then wfatal(".endif without .if") end condlevel = lvl - 1 end -- Check for unfinished conditionals. local function checkconds() if g_errcount ~= "fatal" and condlevel ~= 0 then wprinterr(g_fname, ":*: error: unbalanced conditional\n") end end ------------------------------------------------------------------------------ -- Search for a file in the given path and open it for reading. local function pathopen(path, name) local dirsep = package and match(package.path, "\\") and "\\" or "/" for _,p in ipairs(path) do local fullname = p == "" and name or p..dirsep..name local fin = io.open(fullname, "r") if fin then g_fname = fullname return fin end end end -- Include a file. map_coreop[".include_1"] = function(params) if not params then return "filename" end local name = params[1] -- Save state. Ugly, I know. but upvalues are fast. local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent -- Read the included file. local fatal = readfile(pathopen(g_opt.include, name) or wfatal("include file `"..name.."' not found")) -- Restore state. g_synclineno = -1 g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi if fatal then wfatal("in include file") end end -- Make .include and conditionals initially available, too. map_op[".include_1"] = map_coreop[".include_1"] map_op[".if_1"] = map_coreop[".if_1"] map_op[".elif_1"] = map_coreop[".elif_1"] map_op[".else_0"] = map_coreop[".else_0"] map_op[".endif_0"] = map_coreop[".endif_0"] ------------------------------------------------------------------------------ -- Support variables for macros. local mac_capture, mac_lineno, mac_name local mac_active = {} local mac_list = {} -- Pseudo-opcode to define a macro. map_coreop[".macro_*"] = function(mparams) if not mparams then return "name [, params...]" end -- Split off and validate macro name. local name = remove(mparams, 1) if not name then werror("missing macro name") end if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]*$")) then wfatal("bad macro name `"..name.."'") end -- Validate macro parameter names. local mdup = {} for _,mp in ipairs(mparams) do if not match(mp, "^[%a_][%w_]*$") then wfatal("bad macro parameter name `"..mp.."'") end if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end mdup[mp] = true end -- Check for duplicate or recursive macro definitions. local opname = name.."_"..#mparams if map_op[opname] or map_op[name.."_*"] then wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)") end if mac_capture then wfatal("recursive macro definition") end -- Enable statement capture. local lines = {} mac_lineno = g_lineno mac_name = name mac_capture = function(stmt) -- Statement capture function. -- Stop macro definition with .endmacro pseudo-opcode. if not match(stmt, "^%s*.endmacro%s*$") then lines[#lines+1] = stmt return end mac_capture = nil mac_lineno = nil mac_name = nil mac_list[#mac_list+1] = opname -- Add macro-op definition. map_op[opname] = function(params) if not params then return mparams, lines end -- Protect against recursive macro invocation. if mac_active[opname] then wfatal("recursive macro invocation") end mac_active[opname] = true -- Setup substitution map. local subst = {} for i,mp in ipairs(mparams) do subst[mp] = params[i] end local mcom if g_opt.maccomment and g_opt.comment then mcom = " MACRO "..name.." ("..#mparams..")" wcomment("{"..mcom) end -- Loop through all captured statements for _,stmt in ipairs(lines) do -- Substitute macro parameters. local st = gsub(stmt, "[%w_]+", subst) st = definesubst(st) st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b. if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end -- Emit statement. Use a protected call for better diagnostics. local ok, err = pcall(dostmt, st) if not ok then -- Add the captured statement to the error. wprinterr(err, "\n", g_indent, "| ", stmt, "\t[MACRO ", name, " (", #mparams, ")]\n") end end if mcom then wcomment("}"..mcom) end mac_active[opname] = nil end end end -- An .endmacro pseudo-opcode outside of a macro definition is an error. map_coreop[".endmacro_0"] = function(params) wfatal(".endmacro without .macro") end -- Dump all macros and their contents (with -PP only). local function dumpmacros(out, lvl) sort(mac_list) out:write("Macros:\n") for _,opname in ipairs(mac_list) do local name = sub(opname, 1, -3) local params, lines = map_op[opname]() out:write(format(" %-20s %s\n", name, concat(params, ", "))) if lvl > 1 then for _,line in ipairs(lines) do out:write(" |", line, "\n") end out:write("\n") end end out:write("\n") end -- Check for unfinished macro definitions. local function checkmacros() if mac_capture then wprinterr(g_fname, ":", mac_lineno, ": error: unfinished .macro `", mac_name ,"'\n") end end ------------------------------------------------------------------------------ -- Support variables for captures. local cap_lineno, cap_name local cap_buffers = {} local cap_used = {} -- Start a capture. map_coreop[".capture_1"] = function(params) if not params then return "name" end wflush() local name = params[1] if not match(name, "^[%a_][%w_]*$") then wfatal("bad capture name `"..name.."'") end if cap_name then wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno) end cap_name = name cap_lineno = g_lineno -- Create or continue a capture buffer and start the output line capture. local buf = cap_buffers[name] if not buf then buf = {}; cap_buffers[name] = buf end g_capbuffer = buf g_synclineno = 0 end -- Stop a capture. map_coreop[".endcapture_0"] = function(params) wflush() if not cap_name then wfatal(".endcapture without a valid .capture") end cap_name = nil cap_lineno = nil g_capbuffer = nil g_synclineno = 0 end -- Dump a capture buffer. map_coreop[".dumpcapture_1"] = function(params) if not params then return "name" end wflush() local name = params[1] if not match(name, "^[%a_][%w_]*$") then wfatal("bad capture name `"..name.."'") end cap_used[name] = true wline(function(out) local buf = cap_buffers[name] if buf then wdumplines(out, buf) end end) g_synclineno = 0 end -- Dump all captures and their buffers (with -PP only). local function dumpcaptures(out, lvl) out:write("Captures:\n") for name,buf in pairs(cap_buffers) do out:write(format(" %-20s %4s)\n", name, "("..#buf)) if lvl > 1 then local bar = rep("=", 76) out:write(" ", bar, "\n") for _,line in ipairs(buf) do out:write(" ", line, "\n") end out:write(" ", bar, "\n\n") end end out:write("\n") end -- Check for unfinished or unused captures. local function checkcaptures() if cap_name then wprinterr(g_fname, ":", cap_lineno, ": error: unfinished .capture `", cap_name,"'\n") return end for name in pairs(cap_buffers) do if not cap_used[name] then wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n") end end end ------------------------------------------------------------------------------ -- Sections names. local map_sections = {} -- Pseudo-opcode to define code sections. -- TODO: Data sections, BSS sections. Needs extra C code and API. map_coreop[".section_*"] = function(params) if not params then return "name..." end if #map_sections > 0 then werror("duplicate section definition") end wflush() for sn,name in ipairs(params) do local opname = "."..name.."_0" if not match(name, "^[%a][%w_]*$") or map_op[opname] or map_op["."..name.."_*"] then werror("bad section name `"..name.."'") end map_sections[#map_sections+1] = name wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1)) map_op[opname] = function(params) g_arch.section(sn-1) end end wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections)) end -- Dump all sections. local function dumpsections(out, lvl) out:write("Sections:\n") for _,name in ipairs(map_sections) do out:write(format(" %s\n", name)) end out:write("\n") end ------------------------------------------------------------------------------ -- Replacement for customized Lua, which lacks the package library. local prefix = "" if not require then function require(name) local fp = assert(io.open(prefix..name..".lua")) local s = fp:read("*a") assert(fp:close()) return assert(loadstring(s, "@"..name..".lua"))() end end -- Load architecture-specific module. local function loadarch(arch) if not match(arch, "^[%w_]+$") then return "bad arch name" end _G._map_def = map_def local ok, m_arch = pcall(require, "dasm_"..arch) if not ok then return "cannot load module: "..m_arch end g_arch = m_arch wflush = m_arch.passcb(wline, werror, wfatal, wwarn) m_arch.setup(arch, g_opt) map_op, map_def = m_arch.mergemaps(map_coreop, map_def) end -- Dump architecture description. function opt_map.dumparch(args) local name = optparam(args) if not g_arch then local err = loadarch(name) if err then opterror(err) end end local t = {} for name in pairs(map_coreop) do t[#t+1] = name end for name in pairs(map_op) do t[#t+1] = name end sort(t) local out = stdout local _arch = g_arch._info out:write(format("%s version %s, released %s, %s\n", _info.name, _info.version, _info.release, _info.url)) g_arch.dumparch(out) local pseudo = true out:write("Pseudo-Opcodes:\n") for _,sname in ipairs(t) do local name, nparam = match(sname, "^(.+)_([0-9%*])$") if name then if pseudo and sub(name, 1, 1) ~= "." then out:write("\nOpcodes:\n") pseudo = false end local f = map_op[sname] local s if nparam ~= "*" then nparam = nparam + 0 end if nparam == 0 then s = "" elseif type(f) == "string" then s = map_op[".template__"](nil, f, nparam) else s = f(nil, nparam) end if type(s) == "table" then for _,s2 in ipairs(s) do out:write(format(" %-12s %s\n", name, s2)) end else out:write(format(" %-12s %s\n", name, s)) end end end out:write("\n") exit(0) end -- Pseudo-opcode to set the architecture. -- Only initially available (map_op is replaced when called). map_op[".arch_1"] = function(params) if not params then return "name" end local err = loadarch(params[1]) if err then wfatal(err) end wline(format("#if DASM_VERSION != %d", _info.vernum)) wline('#error "Version mismatch between DynASM and included encoding engine"') wline("#endif") end -- Dummy .arch pseudo-opcode to improve the error report. map_coreop[".arch_1"] = function(params) if not params then return "name" end wfatal("duplicate .arch statement") end ------------------------------------------------------------------------------ -- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'. map_coreop[".nop_*"] = function(params) if not params then return "[ignored...]" end end -- Pseudo-opcodes to raise errors. map_coreop[".error_1"] = function(params) if not params then return "message" end werror(params[1]) end map_coreop[".fatal_1"] = function(params) if not params then return "message" end wfatal(params[1]) end -- Dump all user defined elements. local function dumpdef(out) local lvl = g_opt.dumpdef if lvl == 0 then return end dumpsections(out, lvl) dumpdefines(out, lvl) if g_arch then g_arch.dumpdef(out, lvl) end dumpmacros(out, lvl) dumpcaptures(out, lvl) end ------------------------------------------------------------------------------ -- Helper for splitstmt. local splitlvl local function splitstmt_one(c) if c == "(" then splitlvl = ")"..splitlvl elseif c == "[" then splitlvl = "]"..splitlvl elseif c == "{" then splitlvl = "}"..splitlvl elseif c == ")" or c == "]" or c == "}" then if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end splitlvl = sub(splitlvl, 2) elseif splitlvl == "" then return " \0 " end return c end -- Split statement into (pseudo-)opcode and params. local function splitstmt(stmt) -- Convert label with trailing-colon into .label statement. local label = match(stmt, "^%s*(.+):%s*$") if label then return ".label", {label} end -- Split at commas and equal signs, but obey parentheses and brackets. splitlvl = "" stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one) if splitlvl ~= "" then werror("unbalanced () or []") end -- Split off opcode. local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$") if not op then werror("bad statement syntax") end -- Split parameters. local params = {} for p in gmatch(other, "%s*(%Z+)%z?") do params[#params+1] = gsub(p, "%s+$", "") end if #params > 16 then werror("too many parameters") end params.op = op return op, params end -- Process a single statement. dostmt = function(stmt) -- Ignore empty statements. if match(stmt, "^%s*$") then return end -- Capture macro defs before substitution. if mac_capture then return mac_capture(stmt) end stmt = definesubst(stmt) -- Emit C code without parsing the line. if sub(stmt, 1, 1) == "|" then local tail = sub(stmt, 2) wflush() if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end return end -- Split into (pseudo-)opcode and params. local op, params = splitstmt(stmt) -- Get opcode handler (matching # of parameters or generic handler). local f = map_op[op.."_"..#params] or map_op[op.."_*"] if not f then if not g_arch then wfatal("first statement must be .arch") end -- Improve error report. for i=0,9 do if map_op[op.."_"..i] then werror("wrong number of parameters for `"..op.."'") end end werror("unknown statement `"..op.."'") end -- Call opcode handler or special handler for template strings. if type(f) == "string" then map_op[".template__"](params, f) else f(params) end end -- Process a single line. local function doline(line) if g_opt.flushline then wflush() end -- Assembler line? local indent, aline = match(line, "^(%s*)%|(.*)$") if not aline then -- No, plain C code line, need to flush first. wflush() wsync() wline(line, false) return end g_indent = indent -- Remember current line indentation. -- Emit C code (even from macros). Avoids echo and line parsing. if sub(aline, 1, 1) == "|" then if not mac_capture then wsync() elseif g_opt.comment then wsync() wcomment(aline) end dostmt(aline) return end -- Echo assembler line as a comment. if g_opt.comment then wsync() wcomment(aline) end -- Strip assembler comments. aline = gsub(aline, "//.*$", "") -- Split line into statements at semicolons. if match(aline, ";") then for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end else dostmt(aline) end end ------------------------------------------------------------------------------ -- Write DynASM header. local function dasmhead(out) out:write(format([[ /* ** This file has been pre-processed with DynASM. ** %s ** DynASM version %s, DynASM %s version %s ** DO NOT EDIT! The original file is in "%s". */ ]], _info.url, _info.version, g_arch._info.arch, g_arch._info.version, g_fname)) end -- Read input file. readfile = function(fin) g_indent = "" g_lineno = 0 g_synclineno = -1 -- Process all lines. for line in fin:lines() do g_lineno = g_lineno + 1 g_curline = line local ok, err = pcall(doline, line) if not ok and wprinterr(err, "\n") then return true end end wflush() -- Close input file. assert(fin == stdin or fin:close()) end -- Write output file. local function writefile(outfile) local fout -- Open output file. if outfile == nil or outfile == "-" then fout = stdout else fout = assert(io.open(outfile, "w")) end -- Write all buffered lines wdumplines(fout, g_wbuffer) -- Close output file. assert(fout == stdout or fout:close()) -- Optionally dump definitions. dumpdef(fout == stdout and stderr or stdout) end -- Translate an input file to an output file. local function translate(infile, outfile) g_wbuffer = {} g_indent = "" g_lineno = 0 g_synclineno = -1 -- Put header. wline(dasmhead) -- Read input file. local fin if infile == "-" then g_fname = "(stdin)" fin = stdin else g_fname = infile fin = assert(io.open(infile, "r")) end readfile(fin) -- Check for errors. if not g_arch then wprinterr(g_fname, ":*: error: missing .arch directive\n") end checkconds() checkmacros() checkcaptures() if g_errcount ~= 0 then stderr:write(g_fname, ":*: info: ", g_errcount, " error", (type(g_errcount) == "number" and g_errcount > 1) and "s" or "", " in input file -- no output file generated.\n") dumpdef(stderr) exit(1) end -- Write output file. writefile(outfile) end ------------------------------------------------------------------------------ -- Print help text. function opt_map.help() stdout:write("DynASM -- ", _info.description, ".\n") stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n") stdout:write[[ Usage: dynasm [OPTION]... INFILE.dasc|- -h, --help Display this help text. -V, --version Display version and copyright information. -o, --outfile FILE Output file name (default is stdout). -I, --include DIR Add directory to the include search path. -c, --ccomment Use /* */ comments for assembler lines. -C, --cppcomment Use // comments for assembler lines (default). -N, --nocomment Suppress assembler lines in output. -M, --maccomment Show macro expansions as comments (default off). -L, --nolineno Suppress CPP line number information in output. -F, --flushline Flush action list for every line. -D NAME[=SUBST] Define a substitution. -U NAME Undefine a substitution. -P, --dumpdef Dump defines, macros, etc. Repeat for more output. -A, --dumparch ARCH Load architecture ARCH and dump description. ]] exit(0) end -- Print version information. function opt_map.version() stdout:write(format("%s version %s, released %s\n%s\n\n%s", _info.name, _info.version, _info.release, _info.url, _info.copyright)) exit(0) end -- Misc. options. function opt_map.outfile(args) g_opt.outfile = optparam(args) end function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end function opt_map.nocomment() g_opt.comment = false end function opt_map.maccomment() g_opt.maccomment = true end function opt_map.nolineno() g_opt.cpp = false end function opt_map.flushline() g_opt.flushline = true end function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end ------------------------------------------------------------------------------ -- Short aliases for long options. local opt_alias = { h = "help", ["?"] = "help", V = "version", o = "outfile", I = "include", c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment", L = "nolineno", F = "flushline", P = "dumpdef", A = "dumparch", } -- Parse single option. local function parseopt(opt, args) opt_current = #opt == 1 and "-"..opt or "--"..opt local f = opt_map[opt] or opt_map[opt_alias[opt]] if not f then opterror("unrecognized option `", opt_current, "'. Try `--help'.\n") end f(args) end -- Parse arguments. local function parseargs(args) -- Default options. g_opt.comment = "//|" g_opt.endcomment = "" g_opt.cpp = true g_opt.dumpdef = 0 g_opt.include = { "" } -- Process all option arguments. args.argn = 1 repeat local a = args[args.argn] if not a then break end local lopt, opt = match(a, "^%-(%-?)(.+)") if not opt then break end args.argn = args.argn + 1 if lopt == "" then -- Loop through short options. for o in gmatch(opt, ".") do parseopt(o, args) end else -- Long option. parseopt(opt, args) end until false -- Check for proper number of arguments. local nargs = #args - args.argn + 1 if nargs ~= 1 then if nargs == 0 then if g_opt.dumpdef > 0 then return dumpdef(stdout) end end opt_map.help() end -- Translate a single input file to a single output file -- TODO: Handle multiple files? translate(args[args.argn], g_opt.outfile) end ------------------------------------------------------------------------------ -- Add the directory dynasm.lua resides in to the Lua module search path. local arg = arg if arg and arg[0] then prefix = match(arg[0], "^(.*[/\\])") if package and prefix then package.path = prefix.."?.lua;"..package.path end end -- Start DynASM. parseargs{...} ------------------------------------------------------------------------------ ================================================ FILE: third_party/luajit/luajit/etc/luajit.1 ================================================ .TH luajit 1 "" "" "LuaJIT documentation" .SH NAME luajit \- Just-In-Time Compiler for the Lua Language \fB .SH SYNOPSIS .B luajit [\fIoptions\fR]... [\fIscript\fR [\fIargs\fR]...] .SH "WEB SITE" .IR https://luajit.org .SH DESCRIPTION .PP This is the command-line program to run Lua programs with \fBLuaJIT\fR. .PP \fBLuaJIT\fR is a just-in-time (JIT) compiler for the Lua language. The virtual machine (VM) is based on a fast interpreter combined with a trace compiler. It can significantly improve the performance of Lua programs. .PP \fBLuaJIT\fR is API\- and ABI-compatible with the VM of the standard Lua\ 5.1 interpreter. When embedding the VM into an application, the built library can be used as a drop-in replacement. .SH OPTIONS .TP .BI "\-e " chunk Run the given chunk of Lua code. .TP .BI "\-l " library Load the named library, just like \fBrequire("\fR\fIlibrary\fR\fB")\fR. .TP .BI "\-b " ... Save or list bytecode. Run without arguments to get help on options. .TP .BI "\-j " command Perform LuaJIT control command (optional space after \fB\-j\fR). .TP .BI "\-O" [opt] Control LuaJIT optimizations. .TP .B "\-i" Run in interactive mode. .TP .B "\-v" Show \fBLuaJIT\fR version. .TP .B "\-E" Ignore environment variables. .TP .B "\-\-" Stop processing options. .TP .B "\-" Read script from stdin instead. .PP After all options are processed, the given \fIscript\fR is run. The arguments are passed in the global \fIarg\fR table. .PP Interactive mode is only entered, if no \fIscript\fR and no \fB\-e\fR option is given. Interactive mode can be left with EOF (\fICtrl\-Z\fB). .SH EXAMPLES .TP luajit hello.lua world Prints "Hello world", assuming \fIhello.lua\fR contains: .br print("Hello", arg[1]) .TP luajit \-e "local x=0; for i=1,1e9 do x=x+i end; print(x)" Calculates the sum of the numbers from 1 to 1000000000. .br And finishes in a reasonable amount of time, too. .TP luajit \-jv \-e "for i=1,10 do for j=1,10 do for k=1,100 do end end end" Runs some nested loops and shows the resulting traces. .SH COPYRIGHT .PP \fBLuaJIT\fR is Copyright \(co 2005-2022 Mike Pall. .br \fBLuaJIT\fR is open source software, released under the MIT license. .SH SEE ALSO .PP More details in the provided HTML docs or at: .IR https://luajit.org .br More about the Lua language can be found at: .IR https://lua.org/docs.html .PP lua(1) ================================================ FILE: third_party/luajit/luajit/etc/luajit.pc ================================================ # Package information for LuaJIT to be used by pkg-config. majver=2 minver=1 relver=0 version=${majver}.${minver}.${relver}-beta3 abiver=5.1 prefix=/usr/local multilib=lib exec_prefix=${prefix} libdir=${exec_prefix}/${multilib} libname=luajit-${abiver} includedir=${prefix}/include/luajit-${majver}.${minver} INSTALL_LMOD=${prefix}/share/lua/${abiver} INSTALL_CMOD=${prefix}/${multilib}/lua/${abiver} Name: LuaJIT Description: Just-in-time compiler for Lua URL: https://luajit.org Version: ${version} Requires: Libs: -L${libdir} -l${libname} Libs.private: -Wl,-E -lm -ldl Cflags: -I${includedir}