From: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
To: igt-dev@lists.freedesktop.org
Subject: [igt-dev] [PATCH i-g-t v4 01/77] lib: Introduce typed cleanups
Date: Wed, 5 Oct 2022 09:44:30 +0200 [thread overview]
Message-ID: <20221005074546.55955-2-mauro.chehab@linux.intel.com> (raw)
In-Reply-To: <20221005074546.55955-1-mauro.chehab@linux.intel.com>
From: Chris Wilson <chris@chris-wilson.co.uk>
Start introducing standard types with automatic cleanup courtesy of
gcc's __attribute__((cleanup)). As an example, we start with an fd
that will automatically call close() on going out of scope, and
crucially before atexit where we will want to check for resource leaks.
[mchehab: add test descriptions]
Suggested-by: Andrzej Hajda <andrzej.hajda@intel.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Andrzej Hajda <andrzej.hajda@intel.com>
Reviewed-by: Petri Latvala <petri.latvala@intel.com>
Acked-by: Nirmoy Das <nirmoy.das@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
---
lib/igt_core.c | 6 ++
lib/igt_core.h | 2 +
lib/igt_types.c | 17 ++++
lib/igt_types.h | 47 +++++++++++
lib/meson.build | 1 +
lib/tests/bad_subtest_type.c | 23 ++++++
lib/tests/igt_types.c | 153 +++++++++++++++++++++++++++++++++++
lib/tests/meson.build | 2 +
8 files changed, 251 insertions(+)
create mode 100644 lib/igt_types.c
create mode 100644 lib/igt_types.h
create mode 100644 lib/tests/bad_subtest_type.c
create mode 100644 lib/tests/igt_types.c
diff --git a/lib/igt_core.c b/lib/igt_core.c
index e7425326b7f0..dc6486c841f0 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -624,6 +624,12 @@ uint64_t igt_nsec_elapsed(struct timespec *start)
(uint64_t)NSEC_PER_SEC*(now.tv_sec - start->tv_sec));
}
+void __igt_assert_in_outer_scope(void)
+{
+ internal_assert(!in_subtest,
+ "must only be called outside of a subtest");
+}
+
bool __igt_fixture(void)
{
internal_assert(!in_fixture,
diff --git a/lib/igt_core.h b/lib/igt_core.h
index aa98e8ed8deb..f21723dec4bc 100644
--- a/lib/igt_core.h
+++ b/lib/igt_core.h
@@ -135,6 +135,8 @@ struct _GKeyFile *igt_load_igtrc(void);
*/
#define IGT_EXIT_ABORT 112
+void __igt_assert_in_outer_scope(void);
+
bool __igt_fixture(void);
void __igt_fixture_complete(void);
__noreturn void __igt_fixture_end(void);
diff --git a/lib/igt_types.c b/lib/igt_types.c
new file mode 100644
index 000000000000..392f30fcab23
--- /dev/null
+++ b/lib/igt_types.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: MIT
+/*
+* Copyright © 2022 Intel Corporation
+*/
+
+#include <unistd.h>
+
+#include "igt_types.h"
+
+void igt_cleanup_fd(volatile int *fd)
+{
+ if (!fd || *fd < 0)
+ return;
+
+ close(*fd);
+ *fd = -1;
+}
diff --git a/lib/igt_types.h b/lib/igt_types.h
new file mode 100644
index 000000000000..c4bc01ecdb3b
--- /dev/null
+++ b/lib/igt_types.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef IGT_TYPES_H
+#define IGT_TYPES_H
+
+/*
+ * GCC can automatically cleanup variables that go out of scope, but only
+ * through normal means. Breaking out of scope using longjmp (i.e. igt_skip)
+ * is not handled automatically by GCC. Such scoped variables must be tracked
+ * in an outer scope to the skipping subtest.
+ *
+ * BAD:
+ * igt_subtest("bad") {
+ * igt_fd_t(fd);
+ *
+ * fd = drm_open_driver();
+ * }
+ *
+ * GOOD:
+ * igt_subtest_group() {
+ * igt_fd_t(fd);
+ *
+ * igt_fixture {
+ * fd = drm_open_driver();
+ * }
+ *
+ * igt_subtest("good")
+ * ;
+ * }
+ *
+ * A rule of thumb is that anything that is initialised through a fixture can
+ * be combined with automatic cleanup.
+ */
+
+#define cleanup_with(fn) __attribute__((__cleanup__(fn)))
+
+/* Prevent use within the inner scope subtests, it will be broken by igt_skip */
+#define IGT_OUTER_SCOPE_INIT(x) ({ __igt_assert_in_outer_scope(); x; })
+
+void igt_cleanup_fd(volatile int *fd);
+#define igt_fd_t(x__) \
+ volatile int x__ cleanup_with(igt_cleanup_fd) = IGT_OUTER_SCOPE_INIT(-1)
+
+#endif /* IGT_TYPES_H */
diff --git a/lib/meson.build b/lib/meson.build
index 548835b5833f..c665bd25073a 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -38,6 +38,7 @@ lib_sources = [
'igt_sysrq.c',
'igt_taints.c',
'igt_thread.c',
+ 'igt_types.c',
'igt_vec.c',
'igt_vgem.c',
'igt_x86.c',
diff --git a/lib/tests/bad_subtest_type.c b/lib/tests/bad_subtest_type.c
new file mode 100644
index 000000000000..a7580f9dc701
--- /dev/null
+++ b/lib/tests/bad_subtest_type.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: MIT
+/*
+* Copyright © 2022 Intel Corporation
+*/
+
+#include "igt_core.h"
+#include "igt_types.h"
+
+IGT_TEST_DESCRIPTION("Test bad-scoped file descriptor variable");
+
+igt_main
+{
+ igt_describe("Check if using a scoped variable inside a subtest will abort it");
+ igt_subtest("bad-scoped-variable") {
+ /*
+ * Not allowed to nest a scoped variable inside a subtest as
+ * we expect to longjmp out of the subtest on failure/skip
+ * and automatic cleanup is not invoked for such jmps.
+ * So, this test is expected to fail with SIGABRT.
+ */
+ igt_fd_t(f);
+ }
+}
diff --git a/lib/tests/igt_types.c b/lib/tests/igt_types.c
new file mode 100644
index 000000000000..75dd58b9c042
--- /dev/null
+++ b/lib/tests/igt_types.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: MIT
+/*
+* Copyright © 2022 Intel Corporation
+*/
+
+#include "igt_core.h"
+#include "igt_types.h"
+
+IGT_TEST_DESCRIPTION("Test scoped variable handling");
+
+/* a lookalike of igt_fd_t for testing */
+#define scoped_int_t(x__) \
+ volatile int x__ cleanup_with(cleanup) = IGT_OUTER_SCOPE_INIT(-1)
+
+static int cleanup_called;
+
+static void cleanup(volatile int *x)
+{
+ cleanup_called++;
+ *x = -1;
+}
+
+static void delegate(void)
+{
+ scoped_int_t(x);
+
+ igt_fixture
+ x = 1;
+
+ igt_describe("Pretend to be doing a subtest");
+ igt_subtest("empty-subtest")
+ x = 2;
+
+ igt_fixture {
+ /* Check that we went through both blocks without cleanup */
+ igt_assert(!cleanup_called);
+ igt_assert(x == 2);
+ }
+}
+
+static void skip_delegate(void)
+{
+ scoped_int_t(x);
+
+ igt_fixture
+ x = 1;
+
+ igt_describe("Check if skipping a test will not update a scoped variable");
+
+ igt_subtest("skipped-subtest") {
+ igt_skip("Early skip for testing\n");
+ x = 2; /* not reached due to lonjmp from igt_skip */
+ }
+
+ igt_fixture {
+ /* Check that we went through both blocks without cleanup */
+ igt_assert(!cleanup_called);
+ igt_assert(x == 1);
+ }
+}
+
+igt_main
+{
+ /* Basic check that scopes will call their destructor */
+ cleanup_called = 0;
+ igt_fixture {
+ scoped_int_t(x);
+ }
+
+ igt_describe("Check if cleanup is called after fixture");
+ igt_subtest("cleanup-after-fixture")
+ igt_assert(cleanup_called);
+
+ /* But not before we go out of scope! */
+ cleanup_called = 0;
+ igt_subtest_group {
+ scoped_int_t(x);
+
+ igt_fixture {
+ x = 0xdeadbeef;
+ }
+
+ igt_describe("Check if cleanup not called before subtest group");
+ igt_subtest("cleanup-not-before-subtest-group") {
+ /* Check no scope destructor was called */
+ igt_assert(cleanup_called == 0);
+ /* Confirm that we did pass through a scoped block */
+ igt_assert_eq_u32(x, 0xdeadbeef);
+ }
+ }
+ igt_describe("Check if cleanup is called after subtest group");
+ igt_subtest("cleanup-after-subtest-group")
+ igt_assert(cleanup_called);
+
+ /* longjmp and __attribute__(cleanup) do not mix well together */
+#if 0 /* See bad_subtest_type, this is caught by an internal assertion */
+ cleanup_called = 0;
+ igt_describe("Check skipping a subtest");
+ igt_subtest("skip-subtest") {
+ scoped_int_t(x);
+
+ igt_skip("Checking scoped cleanup on skip\n");
+ }
+ igt_describe("Check cleanup after skipping a subtest");
+ igt_subtest("cleanup-after-skip")
+ igt_assert_f(!cleanup_called,
+ "scoped closure was not compatible with igt_skip\n");
+#endif
+
+ /*
+ * However, if we igt_skip inside another block (subtest-group), then we
+ * will get cleanup on the outer scope.
+ */
+ cleanup_called = 0;
+ igt_subtest_group {
+ scoped_int_t(x);
+
+ igt_describe("Check skipping a subtest group");
+ igt_subtest("skip-subtest-group")
+ igt_skip("Checking scoped cleanup after skip\n");
+ }
+ igt_describe("Check cleanup after skipping a subtest group");
+ igt_subtest("cleanup-after-skip-group")
+ igt_assert(cleanup_called);
+
+ /* Check the same holds true for function calls */
+ cleanup_called = 0;
+ delegate();
+ igt_describe("Check cleanup after delegation");
+ igt_subtest("cleanup-after-delegation")
+ igt_assert(cleanup_called);
+
+ cleanup_called = 0;
+ igt_subtest_group
+ delegate();
+ igt_describe("Check cleanup after group delegation");
+ igt_subtest("cleanup-after-group-delegation")
+ igt_assert(cleanup_called);
+
+ /* Check what happens with a igt_skip inside a function */
+ cleanup_called = 0;
+ skip_delegate();
+ igt_describe("Check cleanup after skipping delegation");
+ igt_subtest("cleanup-after-skipped-delegation")
+ igt_assert(cleanup_called);
+
+ cleanup_called = 0;
+ igt_subtest_group
+ skip_delegate();
+ igt_describe("Check cleanup after skipping group delegation");
+ igt_subtest("cleanup-after-group-skipped-delegation")
+ igt_assert(cleanup_called);
+}
diff --git a/lib/tests/meson.build b/lib/tests/meson.build
index ceaf548b2b2f..d5666c246146 100644
--- a/lib/tests/meson.build
+++ b/lib/tests/meson.build
@@ -19,10 +19,12 @@ lib_tests = [
'igt_stats',
'igt_subtest_group',
'igt_thread',
+ 'igt_types',
'i915_perf_data_alignment',
]
lib_fail_tests = [
+ 'bad_subtest_type',
'igt_no_subtest',
'igt_simple_test_subtests',
'igt_timeout',
--
2.37.3
next prev parent reply other threads:[~2022-10-05 7:46 UTC|newest]
Thread overview: 83+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-05 7:44 [igt-dev] [PATCH i-g-t v4 00/77] Ensure that file descriptors will be closed on exit Mauro Carvalho Chehab
2022-10-05 7:44 ` Mauro Carvalho Chehab [this message]
[not found] ` <Yz1WCjOSxGBbtEyt@kamilkon-desk1>
2022-10-05 10:22 ` [igt-dev] [PATCH i-g-t v4 01/77] lib: Introduce typed cleanups Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 02/77] i915/gem_basic: Close device before exit Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 03/77] i915/gem_flink_basic: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 04/77] i915/gem_linear_blits: " Mauro Carvalho Chehab
[not found] ` <8735c2sf1d.fsf@intel.com>
2022-10-05 13:13 ` Mauro Carvalho Chehab
[not found] ` <87wn9eqqju.fsf@intel.com>
2022-10-05 16:53 ` Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 05/77] i915/gem_blits: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 06/77] i915/gem_close: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 07/77] i915/gem_create: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 08/77] i915/gem_ctx_engines: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 09/77] i915/gem_ctx_shared: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 10/77] i915/gem_exec_alignment: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 11/77] i915/gem_render_copy: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 12/77] i915/gem_render_copy_redux: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 13/77] i915/gem_media_fill: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 14/77] i915/gem_userptr_blits: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 15/77] i915/gem_workarounds: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 16/77] i915/gem_unref_active_buffers: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 17/77] i915/gem_exec_endless: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 18/77] i915/gem_request_retire: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 19/77] i915/gem_unfence_active_buffers: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 20/77] i915/i915_pciid: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 21/77] kms_cursor_legacy: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 22/77] kms_flip: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 23/77] kms_pipe_crc_basic: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 24/77] kms_psr: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 25/77] kms_flip: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 26/77] kms_force_connector_basic: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 27/77] dumb_buffer: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 28/77] kms_atomic: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 29/77] kms_atomic_interruptible: " Mauro Carvalho Chehab
2022-10-05 7:44 ` [igt-dev] [PATCH i-g-t v4 30/77] kms_atomic_transition: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 31/77] i915/kms_big_fb: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 32/77] i915/kms_ccs: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 33/77] kms_color: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 34/77] kms_cursor_crc: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 35/77] i915/kms_big_joiner: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 36/77] i915/kms_cdclk: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 37/77] i915/kms_fence_pin_leak: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 38/77] i915/kms_flip_scaled_crc: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 39/77] i915/kms_flip_tiling: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 40/77] i915/kms_mmap_write_crc: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 41/77] i915/kms_pipe_b_c_ivb: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 42/77] i915/kms_psr2_sf: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 43/77] i915/kms_psr2_su: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 44/77] i915/kms_pwrite_crc: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 45/77] kms_flip_event_leak: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 46/77] kms_hdr: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 47/77] kms_invalid_mode: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 48/77] kms_panel_fitting: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 49/77] kms_plane: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 50/77] kms_plane_alpha_blend: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 51/77] kms_plane_cursor: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 52/77] kms_plane_multiple: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 53/77] kms_plane_scaling: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 54/77] kms_properties: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 55/77] kms_rotation_crc: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 56/77] kms_sequence: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 57/77] kms_universal_plane: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 58/77] kms_vblank: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 59/77] syncobj_wait: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 60/77] syncobj_basic: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 61/77] syncobj_timeline: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 62/77] drm_import_export: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 63/77] kms_dp_aux_dev: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 64/77] kms_hdmi_inject: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 65/77] kms_3d: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 66/77] kms_scaling_modes: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 67/77] kms_dither: " Mauro Carvalho Chehab
2022-10-05 8:44 ` Kamil Konieczny
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 68/77] drm_read: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 69/77] kms_cursor_edge_walk: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 70/77] kms_plane_lowres: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 71/77] kms_content_protection: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 72/77] feature_discovery: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 73/77] i915/i915_pm_dc: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 74/77] core_auth: Close(master) " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 75/77] i915/gem_exec_balancer: Close device " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 76/77] i915/gem_ctx_isolation: " Mauro Carvalho Chehab
2022-10-05 7:45 ` [igt-dev] [PATCH i-g-t v4 77/77] igt_core: add a line break at the end of some internal_assert Mauro Carvalho Chehab
2022-10-05 8:42 ` Kamil Konieczny
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20221005074546.55955-2-mauro.chehab@linux.intel.com \
--to=mauro.chehab@linux.intel.com \
--cc=igt-dev@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.