datadog 2.7.1 → 2.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +353 -1
- data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +78 -102
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
- data/ext/datadog_profiling_native_extension/collectors_stack.c +235 -57
- data/ext/datadog_profiling_native_extension/collectors_stack.h +21 -5
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +376 -156
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
- data/ext/datadog_profiling_native_extension/encoded_profile.c +79 -0
- data/ext/datadog_profiling_native_extension/encoded_profile.h +8 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +14 -8
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
- data/ext/datadog_profiling_native_extension/heap_recorder.c +295 -532
- data/ext/datadog_profiling_native_extension/heap_recorder.h +6 -8
- data/ext/datadog_profiling_native_extension/http_transport.c +64 -98
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +22 -0
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -5
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +69 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +16 -4
- data/ext/datadog_profiling_native_extension/profiling.c +19 -8
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +9 -21
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +2 -10
- data/ext/datadog_profiling_native_extension/stack_recorder.c +231 -181
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -2
- data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
- data/ext/libdatadog_api/crashtracker.c +17 -15
- data/ext/libdatadog_api/crashtracker.h +5 -0
- data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
- data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
- data/ext/libdatadog_api/extconf.rb +2 -2
- data/ext/libdatadog_api/init.c +15 -0
- data/ext/libdatadog_api/library_config.c +164 -0
- data/ext/libdatadog_api/library_config.h +25 -0
- data/ext/libdatadog_api/macos_development.md +3 -3
- data/ext/libdatadog_api/process_discovery.c +112 -0
- data/ext/libdatadog_api/process_discovery.h +5 -0
- data/ext/libdatadog_extconf_helpers.rb +2 -2
- data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +89 -0
- data/lib/datadog/appsec/actions_handler.rb +49 -0
- data/lib/datadog/appsec/anonymizer.rb +16 -0
- data/lib/datadog/appsec/api_security/lru_cache.rb +56 -0
- data/lib/datadog/appsec/api_security/route_extractor.rb +65 -0
- data/lib/datadog/appsec/api_security/sampler.rb +59 -0
- data/lib/datadog/appsec/api_security.rb +23 -0
- data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +623 -253
- data/lib/datadog/appsec/assets/waf_rules/strict.json +69 -107
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/component.rb +49 -65
- data/lib/datadog/appsec/compressed_json.rb +40 -0
- data/lib/datadog/appsec/configuration/settings.rb +212 -27
- data/lib/datadog/appsec/context.rb +74 -0
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +92 -0
- data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +101 -0
- data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/configuration.rb +52 -0
- data/lib/datadog/appsec/contrib/devise/data_extractor.rb +78 -0
- data/lib/datadog/appsec/contrib/devise/ext.rb +22 -0
- data/lib/datadog/appsec/contrib/devise/integration.rb +1 -2
- data/lib/datadog/appsec/contrib/devise/patcher.rb +33 -25
- data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +102 -0
- data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +69 -0
- data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +3 -3
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +106 -0
- data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +42 -0
- data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
- data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
- data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
- data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +41 -0
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +17 -30
- data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rack/ext.rb +34 -0
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +78 -98
- data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +73 -78
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +16 -33
- data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/patcher.rb +25 -38
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +38 -0
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +31 -68
- data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +5 -31
- data/lib/datadog/appsec/event.rb +96 -135
- data/lib/datadog/appsec/ext.rb +12 -3
- data/lib/datadog/appsec/instrumentation/gateway/argument.rb +7 -2
- data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +24 -0
- data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
- data/lib/datadog/appsec/metrics/collector.rb +38 -0
- data/lib/datadog/appsec/metrics/exporter.rb +35 -0
- data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
- data/lib/datadog/appsec/metrics.rb +13 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +52 -32
- data/lib/datadog/appsec/processor/rule_loader.rb +30 -36
- data/lib/datadog/appsec/remote.rb +31 -57
- data/lib/datadog/appsec/response.rb +19 -85
- data/lib/datadog/appsec/security_engine/engine.rb +194 -0
- data/lib/datadog/appsec/security_engine/result.rb +67 -0
- data/lib/datadog/appsec/security_engine/runner.rb +87 -0
- data/lib/datadog/appsec/security_engine.rb +9 -0
- data/lib/datadog/appsec/security_event.rb +39 -0
- data/lib/datadog/appsec/utils.rb +0 -2
- data/lib/datadog/appsec.rb +22 -12
- data/lib/datadog/auto_instrument.rb +3 -0
- data/lib/datadog/core/buffer/random.rb +18 -2
- data/lib/datadog/core/configuration/agent_settings.rb +52 -0
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +4 -18
- data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
- data/lib/datadog/core/configuration/components.rb +74 -32
- data/lib/datadog/core/configuration/components_state.rb +23 -0
- data/lib/datadog/core/configuration/ext.rb +5 -1
- data/lib/datadog/core/configuration/option.rb +81 -45
- data/lib/datadog/core/configuration/option_definition.rb +6 -4
- data/lib/datadog/core/configuration/options.rb +3 -3
- data/lib/datadog/core/configuration/settings.rb +121 -50
- data/lib/datadog/core/configuration/stable_config.rb +22 -0
- data/lib/datadog/core/configuration.rb +43 -11
- data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
- data/lib/datadog/core/crashtracking/component.rb +4 -13
- data/lib/datadog/core/crashtracking/tag_builder.rb +4 -22
- data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/core/encoding.rb +17 -1
- data/lib/datadog/core/environment/agent_info.rb +78 -0
- data/lib/datadog/core/environment/cgroup.rb +10 -12
- data/lib/datadog/core/environment/container.rb +38 -40
- data/lib/datadog/core/environment/ext.rb +6 -6
- data/lib/datadog/core/environment/git.rb +1 -0
- data/lib/datadog/core/environment/identity.rb +3 -3
- data/lib/datadog/core/environment/platform.rb +3 -3
- data/lib/datadog/core/environment/variable_helpers.rb +1 -1
- data/lib/datadog/core/error.rb +11 -9
- data/lib/datadog/core/logger.rb +2 -2
- data/lib/datadog/core/metrics/client.rb +27 -27
- data/lib/datadog/core/metrics/logging.rb +5 -5
- data/lib/datadog/core/process_discovery/tracer_memfd.rb +15 -0
- data/lib/datadog/core/process_discovery.rb +36 -0
- data/lib/datadog/core/rate_limiter.rb +4 -2
- data/lib/datadog/core/remote/client/capabilities.rb +6 -0
- data/lib/datadog/core/remote/client.rb +107 -92
- data/lib/datadog/core/remote/component.rb +18 -19
- data/lib/datadog/core/remote/configuration/digest.rb +7 -7
- data/lib/datadog/core/remote/configuration/path.rb +1 -1
- data/lib/datadog/core/remote/configuration/repository.rb +14 -1
- data/lib/datadog/core/remote/negotiation.rb +9 -9
- data/lib/datadog/core/remote/transport/config.rb +4 -3
- data/lib/datadog/core/remote/transport/http/api.rb +13 -18
- data/lib/datadog/core/remote/transport/http/client.rb +5 -4
- data/lib/datadog/core/remote/transport/http/config.rb +27 -55
- data/lib/datadog/core/remote/transport/http/negotiation.rb +8 -51
- data/lib/datadog/core/remote/transport/http.rb +25 -94
- data/lib/datadog/core/remote/transport/negotiation.rb +17 -4
- data/lib/datadog/core/remote/worker.rb +10 -7
- data/lib/datadog/core/runtime/metrics.rb +12 -5
- data/lib/datadog/core/tag_builder.rb +56 -0
- data/lib/datadog/core/telemetry/component.rb +84 -49
- data/lib/datadog/core/telemetry/emitter.rb +23 -11
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +66 -0
- data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
- data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
- data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
- data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +269 -0
- data/lib/datadog/core/telemetry/event/base.rb +40 -0
- data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
- data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
- data/lib/datadog/core/telemetry/event/log.rb +76 -0
- data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
- data/lib/datadog/core/telemetry/event.rb +17 -383
- data/lib/datadog/core/telemetry/ext.rb +1 -0
- data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
- data/lib/datadog/core/telemetry/logger.rb +5 -4
- data/lib/datadog/core/telemetry/logging.rb +12 -6
- data/lib/datadog/core/telemetry/metric.rb +28 -6
- data/lib/datadog/core/telemetry/request.rb +4 -4
- data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
- data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
- data/lib/datadog/core/telemetry/transport/http.rb +63 -0
- data/lib/datadog/core/telemetry/transport/telemetry.rb +51 -0
- data/lib/datadog/core/telemetry/worker.rb +128 -25
- data/lib/datadog/core/transport/http/adapters/net.rb +17 -2
- data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
- data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +18 -1
- data/lib/datadog/core/transport/http/api/spec.rb +36 -0
- data/lib/datadog/{tracing → core}/transport/http/builder.rb +53 -31
- data/lib/datadog/core/transport/http/env.rb +8 -0
- data/lib/datadog/core/transport/http.rb +75 -0
- data/lib/datadog/core/transport/response.rb +4 -0
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
- data/lib/datadog/core/utils/duration.rb +32 -32
- data/lib/datadog/core/utils/forking.rb +2 -2
- data/lib/datadog/core/utils/network.rb +6 -6
- data/lib/datadog/core/utils/only_once_successful.rb +16 -5
- data/lib/datadog/core/utils/time.rb +20 -0
- data/lib/datadog/core/utils/truncation.rb +21 -0
- data/lib/datadog/core/utils.rb +7 -0
- data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
- data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
- data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
- data/lib/datadog/core/worker.rb +1 -1
- data/lib/datadog/core/workers/async.rb +29 -12
- data/lib/datadog/core/workers/interval_loop.rb +12 -1
- data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
- data/lib/datadog/core.rb +8 -0
- data/lib/datadog/di/base.rb +115 -0
- data/lib/datadog/di/boot.rb +34 -0
- data/lib/datadog/di/code_tracker.rb +26 -15
- data/lib/datadog/di/component.rb +23 -14
- data/lib/datadog/di/configuration/settings.rb +25 -1
- data/lib/datadog/di/contrib/active_record.rb +1 -0
- data/lib/datadog/di/contrib/railtie.rb +15 -0
- data/lib/datadog/di/contrib.rb +28 -0
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +162 -21
- data/lib/datadog/di/logger.rb +30 -0
- data/lib/datadog/di/preload.rb +18 -0
- data/lib/datadog/di/probe.rb +14 -7
- data/lib/datadog/di/probe_builder.rb +1 -0
- data/lib/datadog/di/probe_manager.rb +11 -5
- data/lib/datadog/di/probe_notification_builder.rb +54 -38
- data/lib/datadog/di/probe_notifier_worker.rb +60 -26
- data/lib/datadog/di/redactor.rb +0 -1
- data/lib/datadog/di/remote.rb +147 -0
- data/lib/datadog/di/serializer.rb +19 -8
- data/lib/datadog/di/transport/diagnostics.rb +62 -0
- data/lib/datadog/di/transport/http/api.rb +42 -0
- data/lib/datadog/di/transport/http/client.rb +47 -0
- data/lib/datadog/di/transport/http/diagnostics.rb +65 -0
- data/lib/datadog/di/transport/http/input.rb +77 -0
- data/lib/datadog/di/transport/http.rb +57 -0
- data/lib/datadog/di/transport/input.rb +70 -0
- data/lib/datadog/di/utils.rb +103 -0
- data/lib/datadog/di.rb +14 -76
- data/lib/datadog/error_tracking/collector.rb +87 -0
- data/lib/datadog/error_tracking/component.rb +167 -0
- data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
- data/lib/datadog/error_tracking/configuration.rb +11 -0
- data/lib/datadog/error_tracking/ext.rb +18 -0
- data/lib/datadog/error_tracking/extensions.rb +16 -0
- data/lib/datadog/error_tracking/filters.rb +77 -0
- data/lib/datadog/error_tracking.rb +18 -0
- data/lib/datadog/kit/appsec/events.rb +15 -3
- data/lib/datadog/kit/identity.rb +9 -5
- data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
- data/lib/datadog/opentelemetry/api/baggage.rbs +26 -0
- data/lib/datadog/opentelemetry/api/context.rb +16 -2
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
- data/lib/datadog/opentelemetry.rb +2 -1
- data/lib/datadog/profiling/collectors/code_provenance.rb +18 -9
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -0
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
- data/lib/datadog/profiling/collectors/info.rb +3 -0
- data/lib/datadog/profiling/collectors/thread_context.rb +17 -2
- data/lib/datadog/profiling/component.rb +64 -82
- data/lib/datadog/profiling/encoded_profile.rb +11 -0
- data/lib/datadog/profiling/exporter.rb +3 -4
- data/lib/datadog/profiling/ext.rb +0 -14
- data/lib/datadog/profiling/flush.rb +5 -8
- data/lib/datadog/profiling/http_transport.rb +8 -87
- data/lib/datadog/profiling/load_native_extension.rb +1 -33
- data/lib/datadog/profiling/profiler.rb +2 -0
- data/lib/datadog/profiling/scheduler.rb +10 -2
- data/lib/datadog/profiling/stack_recorder.rb +9 -9
- data/lib/datadog/profiling/tag_builder.rb +5 -41
- data/lib/datadog/profiling/tasks/setup.rb +2 -0
- data/lib/datadog/profiling.rb +6 -2
- data/lib/datadog/tracing/analytics.rb +1 -1
- data/lib/datadog/tracing/component.rb +16 -12
- data/lib/datadog/tracing/configuration/ext.rb +8 -1
- data/lib/datadog/tracing/configuration/settings.rb +22 -10
- data/lib/datadog/tracing/context_provider.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +19 -12
- data/lib/datadog/tracing/contrib/action_pack/ext.rb +2 -0
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_record/integration.rb +7 -3
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +7 -2
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +36 -1
- data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +14 -4
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
- data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
- data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +4 -0
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
- data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -3
- data/lib/datadog/tracing/contrib/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/extensions.rb +29 -3
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -3
- data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
- data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +7 -1
- data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +3 -0
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +0 -15
- data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +4 -1
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +6 -10
- data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -16
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +7 -15
- data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +27 -0
- data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +48 -0
- data/lib/datadog/tracing/contrib/karafka/ext.rb +27 -0
- data/lib/datadog/tracing/contrib/karafka/integration.rb +45 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +66 -0
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +71 -0
- data/lib/datadog/tracing/contrib/karafka.rb +37 -0
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
- data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
- data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
- data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
- data/lib/datadog/tracing/contrib/patcher.rb +5 -2
- data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
- data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -3
- data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +6 -1
- data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +3 -0
- data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -2
- data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
- data/lib/datadog/tracing/contrib/support.rb +28 -0
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/correlation.rb +9 -2
- data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
- data/lib/datadog/tracing/distributed/baggage.rb +131 -0
- data/lib/datadog/tracing/distributed/datadog.rb +4 -2
- data/lib/datadog/tracing/distributed/propagation.rb +25 -4
- data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
- data/lib/datadog/tracing/metadata/errors.rb +4 -4
- data/lib/datadog/tracing/metadata/ext.rb +5 -0
- data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
- data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
- data/lib/datadog/tracing/metadata.rb +2 -0
- data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
- data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
- data/lib/datadog/tracing/span.rb +22 -5
- data/lib/datadog/tracing/span_event.rb +124 -4
- data/lib/datadog/tracing/span_operation.rb +52 -16
- data/lib/datadog/tracing/sync_writer.rb +10 -6
- data/lib/datadog/tracing/trace_digest.rb +9 -2
- data/lib/datadog/tracing/trace_operation.rb +55 -27
- data/lib/datadog/tracing/trace_segment.rb +6 -4
- data/lib/datadog/tracing/tracer.rb +66 -14
- data/lib/datadog/tracing/transport/http/api.rb +5 -4
- data/lib/datadog/tracing/transport/http/client.rb +5 -4
- data/lib/datadog/tracing/transport/http/traces.rb +13 -44
- data/lib/datadog/tracing/transport/http.rb +13 -70
- data/lib/datadog/tracing/transport/serializable_trace.rb +31 -7
- data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
- data/lib/datadog/tracing/transport/traces.rb +47 -13
- data/lib/datadog/tracing/utils.rb +1 -1
- data/lib/datadog/tracing/workers/trace_writer.rb +8 -5
- data/lib/datadog/tracing/workers.rb +5 -4
- data/lib/datadog/tracing/writer.rb +10 -6
- data/lib/datadog/tracing.rb +16 -3
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +2 -0
- metadata +149 -54
- data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
- data/ext/datadog_profiling_loader/extconf.rb +0 -60
- data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -92
- data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -114
- data/lib/datadog/appsec/contrib/devise/event.rb +0 -57
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -77
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -54
- data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
- data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
- data/lib/datadog/appsec/contrib/patcher.rb +0 -12
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
- data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
- data/lib/datadog/appsec/processor/actions.rb +0 -49
- data/lib/datadog/appsec/processor/context.rb +0 -107
- data/lib/datadog/appsec/processor/rule_merger.rb +0 -170
- data/lib/datadog/appsec/processor.rb +0 -106
- data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
- data/lib/datadog/appsec/reactive/engine.rb +0 -47
- data/lib/datadog/appsec/reactive/operation.rb +0 -68
- data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
- data/lib/datadog/appsec/scope.rb +0 -58
- data/lib/datadog/appsec/utils/trace_operation.rb +0 -15
- data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
- data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
- data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
- data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
- data/lib/datadog/core/telemetry/http/env.rb +0 -20
- data/lib/datadog/core/telemetry/http/ext.rb +0 -28
- data/lib/datadog/core/telemetry/http/response.rb +0 -70
- data/lib/datadog/core/telemetry/http/transport.rb +0 -90
- data/lib/datadog/di/transport.rb +0 -81
- data/lib/datadog/tracing/transport/http/api/spec.rb +0 -19
@@ -17,7 +17,7 @@
|
|
17
17
|
#include "setup_signal_handler.h"
|
18
18
|
#include "time_helpers.h"
|
19
19
|
|
20
|
-
// Used to trigger the execution of Collectors::
|
20
|
+
// Used to trigger the execution of Collectors::ThreadContext, which implements all of the sampling logic
|
21
21
|
// itself; this class only implements the "when to do it" part.
|
22
22
|
//
|
23
23
|
// This file implements the native bits of the Datadog::Profiling::Collectors::CpuAndWallTimeWorker class
|
@@ -33,7 +33,7 @@
|
|
33
33
|
// Currently, sampling Ruby threads requires calling Ruby VM APIs that are only safe to call while holding on to the
|
34
34
|
// global VM lock (and are not async-signal safe -- cannot be called from a signal handler).
|
35
35
|
//
|
36
|
-
// @ivoanjo: As a note, I don't think we should think of this constraint as set in stone. Since can reach
|
36
|
+
// @ivoanjo: As a note, I don't think we should think of this constraint as set in stone. Since we can reach inside the Ruby
|
37
37
|
// internals, we may be able to figure out a way of overcoming it. But it's definitely going to be hard so for now
|
38
38
|
// we're considering it as a given.
|
39
39
|
//
|
@@ -92,7 +92,7 @@ unsigned int MAX_ALLOC_WEIGHT = 10000;
|
|
92
92
|
#endif
|
93
93
|
|
94
94
|
// Contains state for a single CpuAndWallTimeWorker instance
|
95
|
-
struct
|
95
|
+
typedef struct {
|
96
96
|
// These are immutable after initialization
|
97
97
|
|
98
98
|
bool gc_profiling_enabled;
|
@@ -122,7 +122,11 @@ struct cpu_and_wall_time_worker_state {
|
|
122
122
|
// Others
|
123
123
|
|
124
124
|
// Used to detect/avoid nested sampling, e.g. when on_newobj_event gets triggered by a memory allocation
|
125
|
-
// that happens during another sample
|
125
|
+
// that happens during another sample, or when the signal handler gets triggered while we're already in the middle of
|
126
|
+
// sampling.
|
127
|
+
//
|
128
|
+
// @ivoanjo: Right now we always sample inside `safely_call`; if that ever changes, this flag may need to become
|
129
|
+
// volatile/atomic/have some barriers to ensure it's visible during e.g. signal handlers.
|
126
130
|
bool during_sample;
|
127
131
|
|
128
132
|
#ifndef NO_GVL_INSTRUMENTATION
|
@@ -145,16 +149,6 @@ struct cpu_and_wall_time_worker_state {
|
|
145
149
|
// How many times we actually tried to interrupt a thread for sampling
|
146
150
|
unsigned int interrupt_thread_attempts;
|
147
151
|
|
148
|
-
// # Stats for the results of calling rb_postponed_job_register_one
|
149
|
-
// The same function was already waiting to be executed
|
150
|
-
unsigned int postponed_job_skipped_already_existed;
|
151
|
-
// The function was added to the queue successfully
|
152
|
-
unsigned int postponed_job_success;
|
153
|
-
// The queue was full
|
154
|
-
unsigned int postponed_job_full;
|
155
|
-
// The function returned an unknown result code
|
156
|
-
unsigned int postponed_job_unknown_result;
|
157
|
-
|
158
152
|
// # CPU/Walltime sampling stats
|
159
153
|
// How many times we actually CPU/wall sampled
|
160
154
|
unsigned int cpu_sampled;
|
@@ -187,7 +181,7 @@ struct cpu_and_wall_time_worker_state {
|
|
187
181
|
uint64_t gvl_sampling_time_ns_max;
|
188
182
|
uint64_t gvl_sampling_time_ns_total;
|
189
183
|
} stats;
|
190
|
-
};
|
184
|
+
} cpu_and_wall_time_worker_state;
|
191
185
|
|
192
186
|
static VALUE _native_new(VALUE klass);
|
193
187
|
static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
|
@@ -195,7 +189,7 @@ static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr);
|
|
195
189
|
static VALUE _native_sampling_loop(VALUE self, VALUE instance);
|
196
190
|
static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread);
|
197
191
|
static VALUE stop(VALUE self_instance, VALUE optional_exception);
|
198
|
-
static void stop_state(
|
192
|
+
static void stop_state(cpu_and_wall_time_worker_state *state, VALUE optional_exception);
|
199
193
|
static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext);
|
200
194
|
static void *run_sampling_trigger_loop(void *state_ptr);
|
201
195
|
static void interrupt_sampling_trigger_loop(void *state_ptr);
|
@@ -221,14 +215,14 @@ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance);
|
|
221
215
|
static VALUE _native_stats_reset_not_thread_safe(DDTRACE_UNUSED VALUE self, VALUE instance);
|
222
216
|
void *simulate_sampling_signal_delivery(DDTRACE_UNUSED void *_unused);
|
223
217
|
static void grab_gvl_and_sample(void);
|
224
|
-
static void reset_stats_not_thread_safe(
|
218
|
+
static void reset_stats_not_thread_safe(cpu_and_wall_time_worker_state *state);
|
225
219
|
static void sleep_for(uint64_t time_ns);
|
226
220
|
static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self);
|
227
221
|
static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *unused2);
|
228
|
-
static void disable_tracepoints(
|
222
|
+
static void disable_tracepoints(cpu_and_wall_time_worker_state *state);
|
229
223
|
static VALUE _native_with_blocked_sigprof(DDTRACE_UNUSED VALUE self);
|
230
224
|
static VALUE rescued_sample_allocation(VALUE tracepoint_data);
|
231
|
-
static void delayed_error(
|
225
|
+
static void delayed_error(cpu_and_wall_time_worker_state *state, const char *error);
|
232
226
|
static VALUE _native_delayed_error(DDTRACE_UNUSED VALUE self, VALUE instance, VALUE error_msg);
|
233
227
|
static VALUE _native_hold_signals(DDTRACE_UNUSED VALUE self);
|
234
228
|
static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self);
|
@@ -262,7 +256,7 @@ static VALUE _native_gvl_profiling_hook_active(DDTRACE_UNUSED VALUE self, VALUE
|
|
262
256
|
// This global state is needed because a bunch of functions on this file need to access it from situations
|
263
257
|
// (e.g. signal handler) where it's impossible or just awkward to pass it as an argument.
|
264
258
|
static VALUE active_sampler_instance = Qnil;
|
265
|
-
static
|
259
|
+
static cpu_and_wall_time_worker_state *active_sampler_instance_state = NULL;
|
266
260
|
|
267
261
|
// See handle_sampling_signal for details on what this does
|
268
262
|
#ifdef NO_POSTPONED_TRIGGER
|
@@ -334,7 +328,7 @@ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
|
|
334
328
|
rb_define_singleton_method(testing_module, "_native_gvl_profiling_hook_active", _native_gvl_profiling_hook_active, 1);
|
335
329
|
}
|
336
330
|
|
337
|
-
// This structure is used to define a Ruby object that stores a pointer to a
|
331
|
+
// This structure is used to define a Ruby object that stores a pointer to a cpu_and_wall_time_worker_state
|
338
332
|
// See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works
|
339
333
|
static const rb_data_type_t cpu_and_wall_time_worker_typed_data = {
|
340
334
|
.wrap_struct_name = "Datadog::Profiling::Collectors::CpuAndWallTimeWorker",
|
@@ -350,7 +344,7 @@ static const rb_data_type_t cpu_and_wall_time_worker_typed_data = {
|
|
350
344
|
static VALUE _native_new(VALUE klass) {
|
351
345
|
long now = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
|
352
346
|
|
353
|
-
|
347
|
+
cpu_and_wall_time_worker_state *state = ruby_xcalloc(1, sizeof(cpu_and_wall_time_worker_state));
|
354
348
|
|
355
349
|
// Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory
|
356
350
|
// being leaked.
|
@@ -414,8 +408,8 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
414
408
|
ENFORCE_BOOLEAN(gvl_profiling_enabled);
|
415
409
|
ENFORCE_BOOLEAN(skip_idle_samples_for_testing)
|
416
410
|
|
417
|
-
|
418
|
-
TypedData_Get_Struct(self_instance,
|
411
|
+
cpu_and_wall_time_worker_state *state;
|
412
|
+
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
419
413
|
|
420
414
|
state->gc_profiling_enabled = (gc_profiling_enabled == Qtrue);
|
421
415
|
state->no_signals_workaround_enabled = (no_signals_workaround_enabled == Qtrue);
|
@@ -445,7 +439,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
445
439
|
|
446
440
|
// Since our state contains references to Ruby objects, we need to tell the Ruby GC about them
|
447
441
|
static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr) {
|
448
|
-
|
442
|
+
cpu_and_wall_time_worker_state *state = (cpu_and_wall_time_worker_state *) state_ptr;
|
449
443
|
|
450
444
|
rb_gc_mark(state->thread_context_collector_instance);
|
451
445
|
rb_gc_mark(state->idle_sampling_helper_instance);
|
@@ -457,8 +451,8 @@ static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr) {
|
|
457
451
|
|
458
452
|
// Called in a background thread created in CpuAndWallTimeWorker#start
|
459
453
|
static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
|
460
|
-
|
461
|
-
TypedData_Get_Struct(instance,
|
454
|
+
cpu_and_wall_time_worker_state *state;
|
455
|
+
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
462
456
|
|
463
457
|
// If we already got a delayed exception registered even before starting, raise before starting
|
464
458
|
if (state->failure_exception != Qnil) {
|
@@ -466,7 +460,7 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
|
|
466
460
|
rb_exc_raise(state->failure_exception);
|
467
461
|
}
|
468
462
|
|
469
|
-
|
463
|
+
cpu_and_wall_time_worker_state *old_state = active_sampler_instance_state;
|
470
464
|
if (old_state != NULL) {
|
471
465
|
if (is_thread_alive(old_state->owner_thread)) {
|
472
466
|
rb_raise(
|
@@ -546,15 +540,15 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
|
|
546
540
|
}
|
547
541
|
|
548
542
|
static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread) {
|
549
|
-
|
550
|
-
TypedData_Get_Struct(self_instance,
|
543
|
+
cpu_and_wall_time_worker_state *state;
|
544
|
+
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
551
545
|
|
552
546
|
state->stop_thread = worker_thread;
|
553
547
|
|
554
548
|
return stop(self_instance, /* optional_exception: */ Qnil);
|
555
549
|
}
|
556
550
|
|
557
|
-
static void stop_state(
|
551
|
+
static void stop_state(cpu_and_wall_time_worker_state *state, VALUE optional_exception) {
|
558
552
|
atomic_store(&state->should_run, false);
|
559
553
|
state->failure_exception = optional_exception;
|
560
554
|
|
@@ -563,8 +557,8 @@ static void stop_state(struct cpu_and_wall_time_worker_state *state, VALUE optio
|
|
563
557
|
}
|
564
558
|
|
565
559
|
static VALUE stop(VALUE self_instance, VALUE optional_exception) {
|
566
|
-
|
567
|
-
TypedData_Get_Struct(self_instance,
|
560
|
+
cpu_and_wall_time_worker_state *state;
|
561
|
+
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
568
562
|
|
569
563
|
stop_state(state, optional_exception);
|
570
564
|
|
@@ -575,7 +569,7 @@ static VALUE stop(VALUE self_instance, VALUE optional_exception) {
|
|
575
569
|
// We need to be careful not to change any state that may be observed OR to restore it if we do. For instance, if anything
|
576
570
|
// we do here can set `errno`, then we must be careful to restore the old `errno` after the fact.
|
577
571
|
static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext) {
|
578
|
-
|
572
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
579
573
|
|
580
574
|
// This can potentially happen if the CpuAndWallTimeWorker was stopped while the signal delivery was happening; nothing to do
|
581
575
|
if (state == NULL) return;
|
@@ -589,25 +583,17 @@ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED si
|
|
589
583
|
return;
|
590
584
|
}
|
591
585
|
|
592
|
-
// We
|
593
|
-
// a) we get triggered using SIGPROF, and the docs state a second SIGPROF will not interrupt an existing one
|
586
|
+
// We assume there can be no concurrent nor nested calls to handle_sampling_signal because
|
587
|
+
// a) we get triggered using SIGPROF, and the docs state a second SIGPROF will not interrupt an existing one (see sigaction docs on sa_mask)
|
594
588
|
// b) we validate we are in the thread that has the global VM lock; if a different thread gets a signal, it will return early
|
595
589
|
// because it will not have the global VM lock
|
596
590
|
|
597
|
-
// Note: rb_postponed_job_register_one ensures that if there's a previous sample_from_postponed_job queued for execution
|
598
|
-
// then we will not queue a second one. It does this by doing a linear scan on the existing jobs; in the future we
|
599
|
-
// may want to implement that check ourselves.
|
600
|
-
|
601
591
|
state->stats.signal_handler_enqueued_sample++;
|
602
592
|
|
603
|
-
// Note: If we ever want to get rid of rb_postponed_job_register_one, remember not to clobber Ruby exceptions, as
|
604
|
-
// this function does this helpful job for us now -- https://github.com/ruby/ruby/commit/a98e343d39c4d7bf1e2190b076720f32d9f298b3.
|
605
593
|
#ifndef NO_POSTPONED_TRIGGER // Ruby 3.3+
|
606
594
|
rb_postponed_job_trigger(sample_from_postponed_job_handle);
|
607
|
-
state->stats.postponed_job_success++; // Always succeeds
|
608
595
|
#else
|
609
|
-
|
610
|
-
// This is a workaround for https://bugs.ruby-lang.org/issues/19991 (for Ruby < 3.3)
|
596
|
+
// Passing in `gc_finalize_deferred_workaround` is a workaround for https://bugs.ruby-lang.org/issues/19991 (for Ruby < 3.3)
|
611
597
|
//
|
612
598
|
// TL;DR the `rb_postponed_job_register_one` API is not atomic (which is why it got replaced by `rb_postponed_job_trigger`)
|
613
599
|
// and in rare cases can cause VM crashes.
|
@@ -631,26 +617,13 @@ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED si
|
|
631
617
|
//
|
632
618
|
// Thus, our workaround is simple: we pass in objspace as our argument, just in case the clobbering happens.
|
633
619
|
// In the happy path, we never use this argument so it makes no difference. In the buggy path, we avoid crashing the VM.
|
634
|
-
|
635
|
-
|
636
|
-
// Officially, the result of rb_postponed_job_register_one is documented as being opaque, but in practice it does not
|
637
|
-
// seem to have changed between Ruby 2.3 and 3.2, and so we track it as a debugging mechanism
|
638
|
-
switch (result) {
|
639
|
-
case 0:
|
640
|
-
state->stats.postponed_job_full++; break;
|
641
|
-
case 1:
|
642
|
-
state->stats.postponed_job_success++; break;
|
643
|
-
case 2:
|
644
|
-
state->stats.postponed_job_skipped_already_existed++; break;
|
645
|
-
default:
|
646
|
-
state->stats.postponed_job_unknown_result++;
|
647
|
-
}
|
620
|
+
rb_postponed_job_register(0, sample_from_postponed_job, gc_finalize_deferred_workaround /* instead of NULL */);
|
648
621
|
#endif
|
649
622
|
}
|
650
623
|
|
651
624
|
// The actual sampling trigger loop always runs **without** the global vm lock.
|
652
625
|
static void *run_sampling_trigger_loop(void *state_ptr) {
|
653
|
-
|
626
|
+
cpu_and_wall_time_worker_state *state = (cpu_and_wall_time_worker_state *) state_ptr;
|
654
627
|
|
655
628
|
uint64_t minimum_time_between_signals = MILLIS_AS_NS(10);
|
656
629
|
|
@@ -709,13 +682,15 @@ static void *run_sampling_trigger_loop(void *state_ptr) {
|
|
709
682
|
|
710
683
|
// This is called by the Ruby VM when it wants to shut down the background thread
|
711
684
|
static void interrupt_sampling_trigger_loop(void *state_ptr) {
|
712
|
-
|
685
|
+
cpu_and_wall_time_worker_state *state = (cpu_and_wall_time_worker_state *) state_ptr;
|
713
686
|
|
714
687
|
atomic_store(&state->should_run, false);
|
715
688
|
}
|
716
689
|
|
690
|
+
// Note: If we ever want to get rid of the postponed job execution, remember not to clobber Ruby exceptions, as
|
691
|
+
// this function does this helpful job for us now -- https://github.com/ruby/ruby/commit/a98e343d39c4d7bf1e2190b076720f32d9f298b3.
|
717
692
|
static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused) {
|
718
|
-
|
693
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
719
694
|
|
720
695
|
// This can potentially happen if the CpuAndWallTimeWorker was stopped while the postponed job was waiting to be executed; nothing to do
|
721
696
|
if (state == NULL) return;
|
@@ -735,8 +710,8 @@ static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused) {
|
|
735
710
|
}
|
736
711
|
|
737
712
|
static VALUE rescued_sample_from_postponed_job(VALUE self_instance) {
|
738
|
-
|
739
|
-
TypedData_Get_Struct(self_instance,
|
713
|
+
cpu_and_wall_time_worker_state *state;
|
714
|
+
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
740
715
|
|
741
716
|
long wall_time_ns_before_sample = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
|
742
717
|
|
@@ -791,8 +766,8 @@ static VALUE _native_current_sigprof_signal_handler(DDTRACE_UNUSED VALUE self) {
|
|
791
766
|
}
|
792
767
|
|
793
768
|
static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
|
794
|
-
|
795
|
-
TypedData_Get_Struct(instance,
|
769
|
+
cpu_and_wall_time_worker_state *state;
|
770
|
+
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
796
771
|
|
797
772
|
// Final preparations: Setup signal handler and enable tracepoints. We run these here and not in `_native_sampling_loop`
|
798
773
|
// because they may raise exceptions.
|
@@ -842,7 +817,7 @@ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
|
|
842
817
|
// This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
|
843
818
|
// It SHOULD NOT be used for other purposes.
|
844
819
|
static VALUE _native_is_running(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
845
|
-
|
820
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
846
821
|
|
847
822
|
return (state != NULL && is_thread_alive(state->owner_thread) && state->self_instance == instance) ? Qtrue : Qfalse;
|
848
823
|
}
|
@@ -875,8 +850,8 @@ static VALUE _native_trigger_sample(DDTRACE_UNUSED VALUE self) {
|
|
875
850
|
// This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
|
876
851
|
// It SHOULD NOT be used for other purposes.
|
877
852
|
static VALUE _native_gc_tracepoint(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
878
|
-
|
879
|
-
TypedData_Get_Struct(instance,
|
853
|
+
cpu_and_wall_time_worker_state *state;
|
854
|
+
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
880
855
|
|
881
856
|
return state->gc_tracepoint;
|
882
857
|
}
|
@@ -902,7 +877,7 @@ static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused) {
|
|
902
877
|
int event = rb_tracearg_event_flag(rb_tracearg_from_tracepoint(tracepoint_data));
|
903
878
|
if (event != RUBY_INTERNAL_EVENT_GC_ENTER && event != RUBY_INTERNAL_EVENT_GC_EXIT) return; // Unknown event
|
904
879
|
|
905
|
-
|
880
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
906
881
|
|
907
882
|
// This should not happen in a normal situation because the tracepoint is always enabled after the instance is set
|
908
883
|
// and disabled before it is cleared, but just in case...
|
@@ -926,7 +901,7 @@ static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused) {
|
|
926
901
|
}
|
927
902
|
|
928
903
|
static void after_gc_from_postponed_job(DDTRACE_UNUSED void *_unused) {
|
929
|
-
|
904
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
930
905
|
|
931
906
|
// This can potentially happen if the CpuAndWallTimeWorker was stopped while the postponed job was waiting to be executed; nothing to do
|
932
907
|
if (state == NULL) return;
|
@@ -981,8 +956,8 @@ static VALUE _native_simulate_sample_from_postponed_job(DDTRACE_UNUSED VALUE sel
|
|
981
956
|
// In the future, if we add more other components with tracepoints, we will need to coordinate stopping all such
|
982
957
|
// tracepoints before doing the other cleaning steps.
|
983
958
|
static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
984
|
-
|
985
|
-
TypedData_Get_Struct(instance,
|
959
|
+
cpu_and_wall_time_worker_state *state;
|
960
|
+
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
986
961
|
|
987
962
|
// Disable all tracepoints, so that there are no more attempts to mutate the profile
|
988
963
|
disable_tracepoints(state);
|
@@ -1000,8 +975,8 @@ static VALUE _native_is_sigprof_blocked_in_current_thread(DDTRACE_UNUSED VALUE s
|
|
1000
975
|
}
|
1001
976
|
|
1002
977
|
static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
1003
|
-
|
1004
|
-
TypedData_Get_Struct(instance,
|
978
|
+
cpu_and_wall_time_worker_state *state;
|
979
|
+
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
1005
980
|
|
1006
981
|
unsigned long total_cpu_samples_attempted = state->stats.cpu_sampled + state->stats.cpu_skipped;
|
1007
982
|
VALUE effective_cpu_sample_rate =
|
@@ -1020,10 +995,6 @@ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
|
1020
995
|
ID2SYM(rb_intern("simulated_signal_delivery")), /* => */ UINT2NUM(state->stats.simulated_signal_delivery),
|
1021
996
|
ID2SYM(rb_intern("signal_handler_enqueued_sample")), /* => */ UINT2NUM(state->stats.signal_handler_enqueued_sample),
|
1022
997
|
ID2SYM(rb_intern("signal_handler_wrong_thread")), /* => */ UINT2NUM(state->stats.signal_handler_wrong_thread),
|
1023
|
-
ID2SYM(rb_intern("postponed_job_skipped_already_existed")), /* => */ UINT2NUM(state->stats.postponed_job_skipped_already_existed),
|
1024
|
-
ID2SYM(rb_intern("postponed_job_success")), /* => */ UINT2NUM(state->stats.postponed_job_success),
|
1025
|
-
ID2SYM(rb_intern("postponed_job_full")), /* => */ UINT2NUM(state->stats.postponed_job_full),
|
1026
|
-
ID2SYM(rb_intern("postponed_job_unknown_result")), /* => */ UINT2NUM(state->stats.postponed_job_unknown_result),
|
1027
998
|
ID2SYM(rb_intern("interrupt_thread_attempts")), /* => */ UINT2NUM(state->stats.interrupt_thread_attempts),
|
1028
999
|
|
1029
1000
|
// CPU Stats
|
@@ -1059,22 +1030,21 @@ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
|
1059
1030
|
}
|
1060
1031
|
|
1061
1032
|
static VALUE _native_stats_reset_not_thread_safe(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
1062
|
-
|
1063
|
-
TypedData_Get_Struct(instance,
|
1033
|
+
cpu_and_wall_time_worker_state *state;
|
1034
|
+
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
1064
1035
|
reset_stats_not_thread_safe(state);
|
1065
1036
|
return Qnil;
|
1066
1037
|
}
|
1067
1038
|
|
1068
1039
|
void *simulate_sampling_signal_delivery(DDTRACE_UNUSED void *_unused) {
|
1069
|
-
|
1040
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
1070
1041
|
|
1071
1042
|
// This can potentially happen if the CpuAndWallTimeWorker was stopped while the IdleSamplingHelper was trying to execute this action
|
1072
1043
|
if (state == NULL) return NULL;
|
1073
1044
|
|
1074
1045
|
state->stats.simulated_signal_delivery++;
|
1075
1046
|
|
1076
|
-
//
|
1077
|
-
// so that the simulated case is as close to the original one as well (including any metrics increases, etc).
|
1047
|
+
// `handle_sampling_signal` does a few things extra on top of `sample_from_postponed_job` so that's why we don't shortcut here
|
1078
1048
|
handle_sampling_signal(0, NULL, NULL);
|
1079
1049
|
|
1080
1050
|
return NULL; // Unused
|
@@ -1082,7 +1052,7 @@ void *simulate_sampling_signal_delivery(DDTRACE_UNUSED void *_unused) {
|
|
1082
1052
|
|
1083
1053
|
static void grab_gvl_and_sample(void) { rb_thread_call_with_gvl(simulate_sampling_signal_delivery, NULL); }
|
1084
1054
|
|
1085
|
-
static void reset_stats_not_thread_safe(
|
1055
|
+
static void reset_stats_not_thread_safe(cpu_and_wall_time_worker_state *state) {
|
1086
1056
|
// NOTE: This is not really thread safe so ongoing sampling operations that are concurrent with a reset can have their stats:
|
1087
1057
|
// * Lost (writes after stats retrieval but before reset).
|
1088
1058
|
// * Included in the previous stats window (writes before stats retrieval and reset).
|
@@ -1116,7 +1086,7 @@ static void sleep_for(uint64_t time_ns) {
|
|
1116
1086
|
}
|
1117
1087
|
|
1118
1088
|
static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self) {
|
1119
|
-
|
1089
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state;
|
1120
1090
|
|
1121
1091
|
bool are_allocations_being_tracked = state != NULL && state->allocation_profiling_enabled && state->allocation_counting_enabled;
|
1122
1092
|
|
@@ -1149,7 +1119,7 @@ static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self) {
|
|
1149
1119
|
// call `rb_tracearg_from_tracepoint(anything)` anywhere during this function or its callees to get the data, so that's
|
1150
1120
|
// why it's not being passed as an argument.
|
1151
1121
|
static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *unused2) {
|
1152
|
-
|
1122
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
1153
1123
|
|
1154
1124
|
// This should not happen in a normal situation because the tracepoint is always enabled after the instance is set
|
1155
1125
|
// and disabled before it is cleared, but just in case...
|
@@ -1171,6 +1141,16 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
|
|
1171
1141
|
return;
|
1172
1142
|
}
|
1173
1143
|
|
1144
|
+
// If Ruby is in the middle of raising an exception, we don't want to try to sample. This is because if we accidentally
|
1145
|
+
// trigger an exception inside the profiler code, bad things will happen (specifically, Ruby will try to kill off the
|
1146
|
+
// thread even though we may try to catch the exception).
|
1147
|
+
//
|
1148
|
+
// Note that "in the middle of raising an exception" means the exception itself has already been allocated.
|
1149
|
+
// What's getting allocated now is probably the backtrace objects (@ivoanjo or at least that's what I've observed)
|
1150
|
+
if (is_raised_flag_set(rb_thread_current())) {
|
1151
|
+
return;
|
1152
|
+
}
|
1153
|
+
|
1174
1154
|
// Hot path: Dynamic sampling rate is usually enabled and the sampling decision is usually false
|
1175
1155
|
if (RB_LIKELY(state->dynamic_sampling_rate_enabled && !discrete_dynamic_sampler_should_sample(&state->allocation_sampler))) {
|
1176
1156
|
state->stats.allocation_skipped++;
|
@@ -1197,10 +1177,6 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
|
|
1197
1177
|
&state->allocation_sampler, HANDLE_CLOCK_FAILURE(monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE))
|
1198
1178
|
);
|
1199
1179
|
|
1200
|
-
// @ivoanjo: Strictly speaking, this is not needed because Ruby should not call the same tracepoint while a previous
|
1201
|
-
// invocation is still pending, (e.g. it wouldn't call `on_newobj_event` while it's already running), but I decided
|
1202
|
-
// to keep this here for consistency -- every call to the thread context (other than the special gc calls which are
|
1203
|
-
// defined as not being able to allocate) sets this.
|
1204
1180
|
state->during_sample = true;
|
1205
1181
|
|
1206
1182
|
// Rescue against any exceptions that happen during sampling
|
@@ -1225,7 +1201,7 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
|
|
1225
1201
|
state->during_sample = false;
|
1226
1202
|
}
|
1227
1203
|
|
1228
|
-
static void disable_tracepoints(
|
1204
|
+
static void disable_tracepoints(cpu_and_wall_time_worker_state *state) {
|
1229
1205
|
if (state->gc_tracepoint != Qnil) {
|
1230
1206
|
rb_tracepoint_disable(state->gc_tracepoint);
|
1231
1207
|
}
|
@@ -1254,7 +1230,7 @@ static VALUE _native_with_blocked_sigprof(DDTRACE_UNUSED VALUE self) {
|
|
1254
1230
|
}
|
1255
1231
|
|
1256
1232
|
static VALUE rescued_sample_allocation(DDTRACE_UNUSED VALUE unused) {
|
1257
|
-
|
1233
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
1258
1234
|
|
1259
1235
|
// This should not happen in a normal situation because on_newobj_event already checked for this, but just in case...
|
1260
1236
|
if (state == NULL) return Qnil;
|
@@ -1283,7 +1259,7 @@ static VALUE rescued_sample_allocation(DDTRACE_UNUSED VALUE unused) {
|
|
1283
1259
|
return Qnil;
|
1284
1260
|
}
|
1285
1261
|
|
1286
|
-
static void delayed_error(
|
1262
|
+
static void delayed_error(cpu_and_wall_time_worker_state *state, const char *error) {
|
1287
1263
|
// If we can't raise an immediate exception at the calling site, use the asynchronous flow through the main worker loop.
|
1288
1264
|
stop_state(state, rb_exc_new_cstr(rb_eRuntimeError, error));
|
1289
1265
|
}
|
@@ -1291,8 +1267,8 @@ static void delayed_error(struct cpu_and_wall_time_worker_state *state, const ch
|
|
1291
1267
|
static VALUE _native_delayed_error(DDTRACE_UNUSED VALUE self, VALUE instance, VALUE error_msg) {
|
1292
1268
|
ENFORCE_TYPE(error_msg, T_STRING);
|
1293
1269
|
|
1294
|
-
|
1295
|
-
TypedData_Get_Struct(instance,
|
1270
|
+
cpu_and_wall_time_worker_state *state;
|
1271
|
+
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
1296
1272
|
|
1297
1273
|
delayed_error(state, rb_string_value_cstr(&error_msg));
|
1298
1274
|
|
@@ -1345,7 +1321,7 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) {
|
|
1345
1321
|
rb_postponed_job_register_one(0, after_gvl_running_from_postponed_job, NULL);
|
1346
1322
|
#endif
|
1347
1323
|
} else if (result == ON_GVL_RUNNING_DONT_SAMPLE) {
|
1348
|
-
|
1324
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
1349
1325
|
|
1350
1326
|
if (state == NULL) return; // This should not happen, but just in case...
|
1351
1327
|
|
@@ -1358,7 +1334,7 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) {
|
|
1358
1334
|
}
|
1359
1335
|
|
1360
1336
|
static void after_gvl_running_from_postponed_job(DDTRACE_UNUSED void *_unused) {
|
1361
|
-
|
1337
|
+
cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
|
1362
1338
|
|
1363
1339
|
// This can potentially happen if the CpuAndWallTimeWorker was stopped while the postponed job was waiting to be executed; nothing to do
|
1364
1340
|
if (state == NULL) return;
|
@@ -1372,8 +1348,8 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) {
|
|
1372
1348
|
}
|
1373
1349
|
|
1374
1350
|
static VALUE rescued_after_gvl_running_from_postponed_job(VALUE self_instance) {
|
1375
|
-
|
1376
|
-
TypedData_Get_Struct(self_instance,
|
1351
|
+
cpu_and_wall_time_worker_state *state;
|
1352
|
+
TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
1377
1353
|
|
1378
1354
|
long wall_time_ns_before_sample = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
|
1379
1355
|
thread_context_collector_sample_after_gvl_running(state->thread_context_collector_instance, rb_thread_current(), wall_time_ns_before_sample);
|
@@ -1394,8 +1370,8 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) {
|
|
1394
1370
|
}
|
1395
1371
|
|
1396
1372
|
static VALUE _native_gvl_profiling_hook_active(DDTRACE_UNUSED VALUE self, VALUE instance) {
|
1397
|
-
|
1398
|
-
TypedData_Get_Struct(instance,
|
1373
|
+
cpu_and_wall_time_worker_state *state;
|
1374
|
+
TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
|
1399
1375
|
|
1400
1376
|
return state->gvl_profiling_hook != NULL ? Qtrue : Qfalse;
|
1401
1377
|
}
|
@@ -333,7 +333,7 @@ static VALUE _native_should_sample(VALUE self, VALUE now);
|
|
333
333
|
static VALUE _native_after_sample(VALUE self, VALUE now);
|
334
334
|
static VALUE _native_state_snapshot(VALUE self);
|
335
335
|
|
336
|
-
typedef struct
|
336
|
+
typedef struct {
|
337
337
|
discrete_dynamic_sampler sampler;
|
338
338
|
} sampler_state;
|
339
339
|
|
@@ -16,7 +16,7 @@
|
|
16
16
|
// every event and is thus, in theory, susceptible to some pattern
|
17
17
|
// biases. In practice, the dynamic readjustment of sampling interval
|
18
18
|
// and randomized starting point should help with avoiding heavy biases.
|
19
|
-
typedef struct
|
19
|
+
typedef struct {
|
20
20
|
// --- Config ---
|
21
21
|
// Name of this sampler for debug logs.
|
22
22
|
const char *debug_name;
|
@@ -21,15 +21,15 @@
|
|
21
21
|
typedef enum { ACTION_WAIT, ACTION_RUN, ACTION_STOP } action;
|
22
22
|
|
23
23
|
// Contains state for a single CpuAndWallTimeWorker instance
|
24
|
-
struct
|
24
|
+
typedef struct {
|
25
25
|
pthread_mutex_t wakeup_mutex;
|
26
26
|
pthread_cond_t wakeup;
|
27
27
|
action requested_action;
|
28
28
|
void (*run_action_function)(void);
|
29
|
-
};
|
29
|
+
} idle_sampling_loop_state;
|
30
30
|
|
31
31
|
static VALUE _native_new(VALUE klass);
|
32
|
-
static void reset_state(
|
32
|
+
static void reset_state(idle_sampling_loop_state *state);
|
33
33
|
static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_instance);
|
34
34
|
static VALUE _native_stop(DDTRACE_UNUSED VALUE self, VALUE self_instance);
|
35
35
|
static void *run_idle_sampling_loop(void *state_ptr);
|
@@ -62,7 +62,7 @@ void collectors_idle_sampling_helper_init(VALUE profiling_module) {
|
|
62
62
|
rb_define_singleton_method(testing_module, "_native_idle_sampling_helper_request_action", _native_idle_sampling_helper_request_action, 1);
|
63
63
|
}
|
64
64
|
|
65
|
-
// This structure is used to define a Ruby object that stores a pointer to a
|
65
|
+
// This structure is used to define a Ruby object that stores a pointer to a idle_sampling_loop_state
|
66
66
|
// See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works
|
67
67
|
static const rb_data_type_t idle_sampling_helper_typed_data = {
|
68
68
|
.wrap_struct_name = "Datadog::Profiling::Collectors::IdleSamplingHelper",
|
@@ -76,7 +76,7 @@ static const rb_data_type_t idle_sampling_helper_typed_data = {
|
|
76
76
|
};
|
77
77
|
|
78
78
|
static VALUE _native_new(VALUE klass) {
|
79
|
-
|
79
|
+
idle_sampling_loop_state *state = ruby_xcalloc(1, sizeof(idle_sampling_loop_state));
|
80
80
|
|
81
81
|
// Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory
|
82
82
|
// being leaked.
|
@@ -90,7 +90,7 @@ static VALUE _native_new(VALUE klass) {
|
|
90
90
|
return TypedData_Wrap_Struct(klass, &idle_sampling_helper_typed_data, state);
|
91
91
|
}
|
92
92
|
|
93
|
-
static void reset_state(
|
93
|
+
static void reset_state(idle_sampling_loop_state *state) {
|
94
94
|
state->wakeup_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
|
95
95
|
state->wakeup = (pthread_cond_t) PTHREAD_COND_INITIALIZER;
|
96
96
|
state->requested_action = ACTION_WAIT;
|
@@ -101,8 +101,8 @@ static void reset_state(struct idle_sampling_loop_state *state) {
|
|
101
101
|
// a pristine state before recreating the worker thread (this includes resetting the mutex in case it was left
|
102
102
|
// locked halfway through the VM forking)
|
103
103
|
static VALUE _native_reset(DDTRACE_UNUSED VALUE self, VALUE self_instance) {
|
104
|
-
|
105
|
-
TypedData_Get_Struct(self_instance,
|
104
|
+
idle_sampling_loop_state *state;
|
105
|
+
TypedData_Get_Struct(self_instance, idle_sampling_loop_state, &idle_sampling_helper_typed_data, state);
|
106
106
|
|
107
107
|
reset_state(state);
|
108
108
|
|
@@ -110,8 +110,8 @@ static VALUE _native_reset(DDTRACE_UNUSED VALUE self, VALUE self_instance) {
|
|
110
110
|
}
|
111
111
|
|
112
112
|
static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_instance) {
|
113
|
-
|
114
|
-
TypedData_Get_Struct(self_instance,
|
113
|
+
idle_sampling_loop_state *state;
|
114
|
+
TypedData_Get_Struct(self_instance, idle_sampling_loop_state, &idle_sampling_helper_typed_data, state);
|
115
115
|
|
116
116
|
// Release GVL and run the loop waiting for requests
|
117
117
|
rb_thread_call_without_gvl(run_idle_sampling_loop, state, interrupt_idle_sampling_loop, state);
|
@@ -120,7 +120,7 @@ static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_in
|
|
120
120
|
}
|
121
121
|
|
122
122
|
static void *run_idle_sampling_loop(void *state_ptr) {
|
123
|
-
|
123
|
+
idle_sampling_loop_state *state = (idle_sampling_loop_state *) state_ptr;
|
124
124
|
int error = 0;
|
125
125
|
|
126
126
|
while (true) {
|
@@ -164,7 +164,7 @@ static void *run_idle_sampling_loop(void *state_ptr) {
|
|
164
164
|
}
|
165
165
|
|
166
166
|
static void interrupt_idle_sampling_loop(void *state_ptr) {
|
167
|
-
|
167
|
+
idle_sampling_loop_state *state = (idle_sampling_loop_state *) state_ptr;
|
168
168
|
int error = 0;
|
169
169
|
|
170
170
|
// Note about the error handling in this situation: Something bad happening at this stage is really really awkward to
|
@@ -189,8 +189,8 @@ static void interrupt_idle_sampling_loop(void *state_ptr) {
|
|
189
189
|
}
|
190
190
|
|
191
191
|
static VALUE _native_stop(DDTRACE_UNUSED VALUE self, VALUE self_instance) {
|
192
|
-
|
193
|
-
TypedData_Get_Struct(self_instance,
|
192
|
+
idle_sampling_loop_state *state;
|
193
|
+
TypedData_Get_Struct(self_instance, idle_sampling_loop_state, &idle_sampling_helper_typed_data, state);
|
194
194
|
|
195
195
|
ENFORCE_SUCCESS_GVL(pthread_mutex_lock(&state->wakeup_mutex));
|
196
196
|
state->requested_action = ACTION_STOP;
|
@@ -204,12 +204,12 @@ static VALUE _native_stop(DDTRACE_UNUSED VALUE self, VALUE self_instance) {
|
|
204
204
|
|
205
205
|
// Assumption: Function gets called without the global VM lock
|
206
206
|
void idle_sampling_helper_request_action(VALUE self_instance, void (*run_action_function)(void)) {
|
207
|
-
|
207
|
+
idle_sampling_loop_state *state;
|
208
208
|
if (!rb_typeddata_is_kind_of(self_instance, &idle_sampling_helper_typed_data)) {
|
209
209
|
grab_gvl_and_raise(rb_eTypeError, "Wrong argument for idle_sampling_helper_request_action");
|
210
210
|
}
|
211
211
|
// This should never fail the the above check passes
|
212
|
-
TypedData_Get_Struct(self_instance,
|
212
|
+
TypedData_Get_Struct(self_instance, idle_sampling_loop_state, &idle_sampling_helper_typed_data, state);
|
213
213
|
|
214
214
|
ENFORCE_SUCCESS_NO_GVL(pthread_mutex_lock(&state->wakeup_mutex));
|
215
215
|
if (state->requested_action == ACTION_WAIT) {
|