From: Akira Yokosawa <akiyks@gmail.com>
To: "Paul E. McKenney" <paulmck@linux.ibm.com>
Cc: perfbook@vger.kernel.org, Akira Yokosawa <akiyks@gmail.com>
Subject: [PATCH 3/7] SMPdesign: Employ new scheme for snippet of lockhdeq.c and locktdeq.c
Date: Sun, 4 Nov 2018 09:11:12 +0900 [thread overview]
Message-ID: <0246eeae-facf-ef68-6da9-159693b851ec@gmail.com> (raw)
In-Reply-To: <fc130ee3-dbd0-b0d1-41a6-b49baa6b00e5@gmail.com>
From 966f43a286dedd32a577409fa54221b42f50d8cd Mon Sep 17 00:00:00 2001
From: Akira Yokosawa <akiyks@gmail.com>
Date: Mon, 29 Oct 2018 21:07:28 +0900
Subject: [PATCH 3/7] SMPdesign: Employ new scheme for snippet of lockhdeq.c and locktdeq.c
Signed-off-by: Akira Yokosawa <akiyks@gmail.com>
---
CodeSamples/SMPdesign/lockhdeq.c | 34 +++---
CodeSamples/SMPdesign/locktdeq.c | 70 ++++++------
SMPdesign/partexercises.tex | 237 +++++++++++++--------------------------
3 files changed, 132 insertions(+), 209 deletions(-)
diff --git a/CodeSamples/SMPdesign/lockhdeq.c b/CodeSamples/SMPdesign/lockhdeq.c
index 8ba635b..1b57423 100644
--- a/CodeSamples/SMPdesign/lockhdeq.c
+++ b/CodeSamples/SMPdesign/lockhdeq.c
@@ -166,19 +166,20 @@ void init_pdeq(struct pdeq *d)
init_deq(&d->bkt[i]);
}
-struct cds_list_head *pdeq_pop_l(struct pdeq *d)
+//\begin{snippet}[labelbase=ln:SMPdesign:lockhdeq:pop_push,commandchars=\\\@\$]
+struct cds_list_head *pdeq_pop_l(struct pdeq *d)//\lnlbl{popl:b}
{
struct cds_list_head *e;
int i;
- spin_lock(&d->llock);
- i = moveright(d->lidx);
- e = deq_pop_l(&d->bkt[i]);
- if (e != NULL)
- d->lidx = i;
- spin_unlock(&d->llock);
- return e;
-}
+ spin_lock(&d->llock); //\lnlbl{popl:acq}
+ i = moveright(d->lidx); //\lnlbl{popl:idx}
+ e = deq_pop_l(&d->bkt[i]); //\lnlbl{popl:deque}
+ if (e != NULL) //\lnlbl{popl:check}
+ d->lidx = i; //\lnlbl{popl:record}
+ spin_unlock(&d->llock); //\lnlbl{popl:rel}
+ return e; //\lnlbl{popl:return}
+} //\lnlbl{popl:e}
struct cds_list_head *pdeq_pop_r(struct pdeq *d)
{
@@ -194,16 +195,16 @@ struct cds_list_head *pdeq_pop_r(struct pdeq *d)
return e;
}
-void pdeq_push_l(struct cds_list_head *e, struct pdeq *d)
+void pdeq_push_l(struct cds_list_head *e, struct pdeq *d)//\lnlbl{pushl:b}
{
int i;
- spin_lock(&d->llock);
- i = d->lidx;
- deq_push_l(e, &d->bkt[i]);
- d->lidx = moveleft(d->lidx);
- spin_unlock(&d->llock);
-}
+ spin_lock(&d->llock); //\lnlbl{pushl:acq}
+ i = d->lidx; //\lnlbl{pushl:idx}
+ deq_push_l(e, &d->bkt[i]); //\lnlbl{pushl:enque}
+ d->lidx = moveleft(d->lidx); //\lnlbl{pushl:update}
+ spin_unlock(&d->llock); //\lnlbl{pushl:rel}
+} //\lnlbl{pushl:e}
void pdeq_push_r(struct cds_list_head *e, struct pdeq *d)
{
@@ -215,6 +216,7 @@ void pdeq_push_r(struct cds_list_head *e, struct pdeq *d)
d->ridx = moveright(d->ridx);
spin_unlock(&d->rlock);
}
+//\end{snippet}
#ifdef TEST
#define DEQ_AND_PDEQ
diff --git a/CodeSamples/SMPdesign/locktdeq.c b/CodeSamples/SMPdesign/locktdeq.c
index 335a68b..4a0ca51 100644
--- a/CodeSamples/SMPdesign/locktdeq.c
+++ b/CodeSamples/SMPdesign/locktdeq.c
@@ -99,58 +99,60 @@ void init_pdeq(struct pdeq *d)
init_deq(&d->rdeq);
}
-struct cds_list_head *pdeq_pop_l(struct pdeq *d)
+//\begin{snippet}[labelbase=ln:SMPdesign:locktdeq:pop_push,commandchars=\\\@\$]
+struct cds_list_head *pdeq_pop_l(struct pdeq *d) //\lnlbl{popl:b}
{
struct cds_list_head *e;
- spin_lock(&d->llock);
- e = deq_pop_l(&d->ldeq);
+ spin_lock(&d->llock); //\lnlbl{popl:acq:l}
+ e = deq_pop_l(&d->ldeq); //\lnlbl{popl:deq:ll}
if (e == NULL) {
- spin_lock(&d->rlock);
- e = deq_pop_l(&d->rdeq);
- cds_list_splice(&d->rdeq.chain, &d->ldeq.chain);
- CDS_INIT_LIST_HEAD(&d->rdeq.chain);
- spin_unlock(&d->rlock);
- }
- spin_unlock(&d->llock);
+ spin_lock(&d->rlock); //\lnlbl{popl:acq:r}
+ e = deq_pop_l(&d->rdeq); //\lnlbl{popl:deq:lr}
+ cds_list_splice(&d->rdeq.chain, &d->ldeq.chain);//\lnlbl{popl:move}
+ CDS_INIT_LIST_HEAD(&d->rdeq.chain); //\lnlbl{popl:init:r}
+ spin_unlock(&d->rlock); //\lnlbl{popl:rel:r}
+ } //\lnlbl{popl:skip}
+ spin_unlock(&d->llock); //\lnlbl{popl:rel:l}
return e;
-}
+} //\lnlbl{popl:e}
-struct cds_list_head *pdeq_pop_r(struct pdeq *d)
+struct cds_list_head *pdeq_pop_r(struct pdeq *d) //\lnlbl{popr:b}
{
struct cds_list_head *e;
- spin_lock(&d->rlock);
- e = deq_pop_r(&d->rdeq);
- if (e == NULL) {
- spin_unlock(&d->rlock);
- spin_lock(&d->llock);
- spin_lock(&d->rlock);
- e = deq_pop_r(&d->rdeq);
- if (e == NULL) {
- e = deq_pop_r(&d->ldeq);
- cds_list_splice(&d->ldeq.chain, &d->rdeq.chain);
- CDS_INIT_LIST_HEAD(&d->ldeq.chain);
+ spin_lock(&d->rlock); //\lnlbl{popr:acq:r1}
+ e = deq_pop_r(&d->rdeq); //\lnlbl{popr:deq:rr1}
+ if (e == NULL) { //\lnlbl{popr:check1}
+ spin_unlock(&d->rlock); //\lnlbl{popr:rel:r1}
+ spin_lock(&d->llock); //\lnlbl{popr:acq:l}
+ spin_lock(&d->rlock); //\lnlbl{popr:acq:r2}
+ e = deq_pop_r(&d->rdeq); //\lnlbl{popr:deq:rr2}
+ if (e == NULL) { //\lnlbl{popr:check2}
+ e = deq_pop_r(&d->ldeq); //\lnlbl{popr:deq:rl}
+ cds_list_splice(&d->ldeq.chain, &d->rdeq.chain);//\lnlbl{popr:move}
+ CDS_INIT_LIST_HEAD(&d->ldeq.chain); //\lnlbl{popr:init:l}
}
- spin_unlock(&d->llock);
- }
- spin_unlock(&d->rlock);
+ spin_unlock(&d->llock); //\lnlbl{popr:rel:l}
+ } //\lnlbl{popr:skip2}
+ spin_unlock(&d->rlock); //\lnlbl{popr:rel:r2}
return e;
-}
+} //\lnlbl{popr:e}
-void pdeq_push_l(struct cds_list_head *e, struct pdeq *d)
+void pdeq_push_l(struct cds_list_head *e, struct pdeq *d) //\lnlbl{pushl:b}
{
- spin_lock(&d->llock);
- deq_push_l(e, &d->ldeq);
- spin_unlock(&d->llock);
-}
+ spin_lock(&d->llock); //\lnlbl{pushl:acq:l}
+ deq_push_l(e, &d->ldeq); //\lnlbl{pushl:que:l}
+ spin_unlock(&d->llock); //\lnlbl{pushl:rel:l}
+} //\lnlbl{pushl:e}
-void pdeq_push_r(struct cds_list_head *e, struct pdeq *d)
+void pdeq_push_r(struct cds_list_head *e, struct pdeq *d) //\lnlbl{pushr:b}
{
spin_lock(&d->rlock);
deq_push_r(e, &d->rdeq);
spin_unlock(&d->rlock);
-}
+} //\lnlbl{pushr:e}
+//\end{snippet}
#ifdef TEST
#include "deqtorture.h"
diff --git a/SMPdesign/partexercises.tex b/SMPdesign/partexercises.tex
index 5b5fd5a..5ce7e86 100644
--- a/SMPdesign/partexercises.tex
+++ b/SMPdesign/partexercises.tex
@@ -361,65 +361,11 @@ A high-performance implementation would of course use padding or special
alignment directives to avoid false sharing.
\end{lineref}
-\begin{listing*}[bp]
-{ \scriptsize
-\begin{verbbox}
- 1 struct cds_list_head *pdeq_pop_l(struct pdeq *d)
- 2 {
- 3 struct cds_list_head *e;
- 4 int i;
- 5
- 6 spin_lock(&d->llock);
- 7 i = moveright(d->lidx);
- 8 e = deq_pop_l(&d->bkt[i]);
- 9 if (e != NULL)
- 10 d->lidx = i;
- 11 spin_unlock(&d->llock);
- 12 return e;
- 13 }
- 14
- 15 struct cds_list_head *pdeq_pop_r(struct pdeq *d)
- 16 {
- 17 struct cds_list_head *e;
- 18 int i;
- 19
- 20 spin_lock(&d->rlock);
- 21 i = moveleft(d->ridx);
- 22 e = deq_pop_r(&d->bkt[i]);
- 23 if (e != NULL)
- 24 d->ridx = i;
- 25 spin_unlock(&d->rlock);
- 26 return e;
- 27 }
- 28
- 29 void pdeq_push_l(struct cds_list_head *e, struct pdeq *d)
- 30 {
- 31 int i;
- 32
- 33 spin_lock(&d->llock);
- 34 i = d->lidx;
- 35 deq_push_l(e, &d->bkt[i]);
- 36 d->lidx = moveleft(d->lidx);
- 37 spin_unlock(&d->llock);
- 38 }
- 39
- 40 void pdeq_push_r(struct cds_list_head *e, struct pdeq *d)
- 41 {
- 42 int i;
- 43
- 44 spin_lock(&d->rlock);
- 45 i = d->ridx;
- 46 deq_push_r(e, &d->bkt[i]);
- 47 d->ridx = moveright(d->ridx);
- 48 spin_unlock(&d->rlock);
- 49 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\begin{listing}[tbp]
+\input{CodeSamples/SMPdesign/lockhdeq@pop_push.fcv}
\caption{Lock-Based Parallel Double-Ended Queue Implementation}
\label{lst:SMPdesign:Lock-Based Parallel Double-Ended Queue Implementation}
-\end{listing*}
+\end{listing}
Listing~\ref{lst:SMPdesign:Lock-Based Parallel Double-Ended Queue Implementation}
(\path{lockhdeq.c})
@@ -430,22 +376,34 @@ shows the implementation of the enqueue and dequeue functions.\footnote{
Discussion will focus on the left-hand operations, as the right-hand
operations are trivially derived from them.
-Lines~1-13 show \co{pdeq_pop_l()}, which left\-/dequeues and returns
+\begin{lineref}[ln:SMPdesign:lockhdeq:pop_push:popl]
+Lines~\lnref{b}-\lnref{e} show \co{pdeq_pop_l()},
+which left\-/dequeues and returns
an element if possible, returning \co{NULL} otherwise.
-Line~6 acquires the left-hand spinlock, and line~7 computes the
+Line~\lnref{acq} acquires the left-hand spinlock,
+and line~\lnref{idx} computes the
index to be dequeued from.
-Line~8 dequeues the element, and, if line~9 finds the result to be
-non-\co{NULL}, line~10 records the new left-hand index.
-Either way, line~11 releases the lock, and, finally, line~12 returns
+Line~\lnref{deque} dequeues the element, and,
+if line~\lnref{check} finds the result to be
+non-\co{NULL}, line~\lnref{record} records the new left-hand index.
+Either way, line~\lnref{rel} releases the lock, and,
+finally, line~\lnref{return} returns
the element if there was one, or \co{NULL} otherwise.
+\end{lineref}
-Lines~29-38 shows \co{pdeq_push_l()}, which left-enqueues the specified
+\begin{lineref}[ln:SMPdesign:lockhdeq:pop_push:pushl]
+Lines~\lnref{b}-\lnref{e} shows \co{pdeq_push_l()},
+which left-enqueues the specified
element.
-Line~33 acquires the left-hand lock, and line~34 picks up the left-hand
+Line~\lnref{acq} acquires the left-hand lock,
+and line~\lnref{idx} picks up the left-hand
index.
-Line~35 left-enqueues the specified element onto the double-ended queue
+Line~\lnref{enque} left-enqueues the specified element
+onto the double-ended queue
indexed by the left-hand index.
-Line~36 then updates the left-hand index and line~37 releases the lock.
+Line~\lnref{update} then updates the left-hand index
+and line~\lnref{rel} releases the lock.
+\end{lineref}
As noted earlier, the right-hand operations are completely analogous
to their left-handed counterparts, so their analysis is left as an
@@ -500,72 +458,11 @@ the previous section, the compound implementation will build on
a sequential implementation of a double-ended queue that uses
neither locks nor atomic operations.
-\begin{listing*}[bp]
-{ \scriptsize
-\begin{verbbox}
- 1 struct cds_list_head *pdeq_pop_l(struct pdeq *d)
- 2 {
- 3 struct cds_list_head *e;
- 4
- 5 spin_lock(&d->llock);
- 6 e = deq_pop_l(&d->ldeq);
- 7 if (e == NULL) {
- 8 spin_lock(&d->rlock);
- 9 e = deq_pop_l(&d->rdeq);
- 10 cds_list_splice(&d->rdeq.chain, &d->ldeq.chain);
- 11 CDS_INIT_LIST_HEAD(&d->rdeq.chain);
- 12 spin_unlock(&d->rlock);
- 13 }
- 14 spin_unlock(&d->llock);
- 15 return e;
- 16 }
- 17
- 18 struct cds_list_head *pdeq_pop_r(struct pdeq *d)
- 19 {
- 20 struct cds_list_head *e;
- 21
- 22 spin_lock(&d->rlock);
- 23 e = deq_pop_r(&d->rdeq);
- 24 if (e == NULL) {
- 25 spin_unlock(&d->rlock);
- 26 spin_lock(&d->llock);
- 27 spin_lock(&d->rlock);
- 28 e = deq_pop_r(&d->rdeq);
- 29 if (e == NULL) {
- 30 e = deq_pop_r(&d->ldeq);
- 31 cds_list_splice(&d->ldeq.chain, &d->rdeq.chain);
- 32 CDS_INIT_LIST_HEAD(&d->ldeq.chain);
- 33 }
- 34 spin_unlock(&d->llock);
- 35 }
- 36 spin_unlock(&d->rlock);
- 37 return e;
- 38 }
- 39
- 40 void pdeq_push_l(struct cds_list_head *e, struct pdeq *d)
- 41 {
- 42 int i;
- 43
- 44 spin_lock(&d->llock);
- 45 deq_push_l(e, &d->ldeq);
- 46 spin_unlock(&d->llock);
- 47 }
- 48
- 49 void pdeq_push_r(struct cds_list_head *e, struct pdeq *d)
- 50 {
- 51 int i;
- 52
- 53 spin_lock(&d->rlock);
- 54 deq_push_r(e, &d->rdeq);
- 55 spin_unlock(&d->rlock);
- 56 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\begin{listing}[tbp]
+\input{CodeSamples/SMPdesign/locktdeq@pop_push.fcv}
\caption{Compound Parallel Double-Ended Queue Implementation}
\label{lst:SMPdesign:Compound Parallel Double-Ended Queue Implementation}
-\end{listing*}
+\end{listing}
Listing~\ref{lst:SMPdesign:Compound Parallel Double-Ended Queue Implementation}
shows the implementation.
@@ -583,50 +480,66 @@ and \co{pdeq_pop_r()} implementations separately.
(see Section~\ref{sec:SMPdesign:Dining Philosophers Problem}).
} \QuickQuizEnd
-The \co{pdeq_pop_l()} implementation is shown on lines~1-16
+\begin{lineref}[ln:SMPdesign:locktdeq:pop_push:popl]
+The \co{pdeq_pop_l()} implementation is shown on
+lines~\lnref{b}-\lnref{e}
of the figure.
-Line~5 acquires the left-hand lock, which line~14 releases.
-Line~6 attempts to left-dequeue an element from the left-hand underlying
-double-ended queue, and, if successful, skips lines~8-13 to simply
+Line~\lnref{acq:l} acquires the left-hand lock,
+which line~\lnref{rel:l} releases.
+Line~\lnref{deq:ll} attempts to left-dequeue an element
+from the left-hand underlying
+double-ended queue, and, if successful,
+skips lines~\lnref{acq:r}-\lnref{skip} to simply
return this element.
-Otherwise, line~8 acquires the right-hand lock, line~9
+Otherwise, line~\lnref{acq:r} acquires the right-hand lock, line~\lnref{deq:lr}
left-dequeues an element from the right-hand queue,
-and line~10 moves any remaining elements on the right-hand
-queue to the left-hand queue, line~11 initializes the right-hand queue,
-and line~12 releases the right-hand lock.
-The element, if any, that was dequeued on line~10 will be returned.
+and line~\lnref{move} moves any remaining elements on the right-hand
+queue to the left-hand queue, line~\lnref{init:r} initializes
+the right-hand queue,
+and line~\lnref{rel:r} releases the right-hand lock.
+The element, if any, that was dequeued on line~\lnref{deq:lr} will be returned.
+\end{lineref}
-The \co{pdeq_pop_r()} implementation is shown on lines~18-38
+\begin{lineref}[ln:SMPdesign:locktdeq:pop_push:popr]
+The \co{pdeq_pop_r()} implementation is shown on lines~\lnref{b}-\lnref{e}
of the figure.
-As before, line~22 acquires the right-hand lock (and line~36
-releases it), and line~23 attempts to right-dequeue an element
-from the right-hand queue, and, if successful, skips lines~24-35
+As before, line~\lnref{acq:r1} acquires the right-hand lock
+(and line~\lnref{rel:r2}
+releases it), and line~\lnref{deq:rr1} attempts to right-dequeue an element
+from the right-hand queue, and, if successful,
+skips lines~\lnref{rel:r1}-\lnref{skip2}
to simply return this element.
-However, if line~24 determines that there was no element to dequeue,
-line~25 releases the right-hand lock and lines~26-27 acquire both
+However, if line~\lnref{check1} determines that there was no element to dequeue,
+line~\lnref{rel:r1} releases the right-hand lock and
+lines~\lnref{acq:l}-\lnref{acq:r2} acquire both
locks in the proper order.
-Line~28 then attempts to right-dequeue an element from the right-hand
-list again, and if line~29 determines that this second attempt has
-failed, line~30 right-dequeues an element from the left-hand queue
-(if there is one available), line~31 moves any remaining elements
-from the left-hand queue to the right-hand queue, and line~32
+Line~\lnref{deq:rr2} then attempts to right-dequeue an element
+from the right-hand
+list again, and if line~\lnref{check2} determines that this second attempt has
+failed, line~\lnref{deq:rl} right-dequeues an element from the left-hand queue
+(if there is one available), line~\lnref{move} moves any remaining elements
+from the left-hand queue to the right-hand queue, and line~\lnref{init:l}
initializes the left-hand queue.
-Either way, line~34 releases the left-hand lock.
+Either way, line~\lnref{rel:l} releases the left-hand lock.
+\end{lineref}
\QuickQuiz{}
Why is it necessary to retry the right-dequeue operation
- on line~28 of
+ on line~\ref{ln:SMPdesign:locktdeq:pop_push:popr:deq:rr2} of
Listing~\ref{lst:SMPdesign:Compound Parallel Double-Ended Queue Implementation}?
\QuickQuizAnswer{
+ \begin{lineref}[ln:SMPdesign:locktdeq:pop_push:popr]
This retry is necessary because some other thread might have
enqueued an element between the time that this thread dropped
- \co{d->rlock} on line~25 and the time that it reacquired this
- same lock on line~27.
+ \co{d->rlock} on line~\lnref{rel:r1} and the time that it reacquired this
+ same lock on line~\lnref{acq:r2}.
+ \end{lineref}
} \QuickQuizEnd
\QuickQuiz{}
Surely the left-hand lock must \emph{sometimes} be available!!!
- So why is it necessary that line~25 of
+ So why is it necessary that
+ line~\ref{ln:SMPdesign:locktdeq:pop_push:popr:rel:r1} of
Listing~\ref{lst:SMPdesign:Compound Parallel Double-Ended Queue Implementation}
unconditionally release the right-hand lock?
\QuickQuizAnswer{
@@ -638,13 +551,19 @@ Either way, line~34 releases the left-hand lock.
it is worthwhile) is left as an exercise for the reader.
} \QuickQuizEnd
-The \co{pdeq_push_l()} implementation is shown on lines~40-47 of
+\begin{lineref}[ln:SMPdesign:locktdeq:pop_push:pushl]
+The \co{pdeq_push_l()} implementation is shown on
+lines~\lnref{b}-\lnref{e} of
Listing~\ref{lst:SMPdesign:Compound Parallel Double-Ended Queue Implementation}.
-Line~44 acquires the left-hand spinlock, line~45 left-enqueues the
-element onto the left-hand queue, and finally line~46 releases
+Line~\lnref{acq:l} acquires the left-hand spinlock,
+line~\lnref{que:l} left-enqueues the
+element onto the left-hand queue, and finally line~\lnref{rel:l} releases
the lock.
-The \co{pdeq_enqueue_r()} implementation (shown on lines~49-56)
+\end{lineref}
+\begin{lineref}[ln:SMPdesign:locktdeq:pop_push:pushr]
+The \co{pdeq_push_r()} implementation (shown on lines~\lnref{b}-\lnref{e})
is quite similar.
+\end{lineref}
\QuickQuiz{}
But in the case where data is flowing in only one direction,
--
2.7.4
next prev parent reply other threads:[~2018-11-04 0:11 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-11-04 0:07 [PATCH 0/7] Further conversion of code snippets (howto, cpu, SMPdesign) Akira Yokosawa
2018-11-04 0:08 ` [PATCH 1/7] howto, cpu: Employ new scheme for command/code snippets Akira Yokosawa
2018-11-04 0:09 ` [PATCH 2/7] SMPdesign: Employ new scheme for snippet of lockhdeq.c Akira Yokosawa
2018-11-04 0:11 ` Akira Yokosawa [this message]
2018-11-04 0:11 ` [PATCH 4/7] SMPdesign: Employ new scheme for inline snippets Akira Yokosawa
2018-11-04 0:13 ` [PATCH 5/7] SMPdesign: Employ new scheme for snippets from smpalloc.c Akira Yokosawa
2018-11-04 0:13 ` [PATCH 6/7] SMPdesign/beyond: Employ new scheme for inline pseudocode snippets Akira Yokosawa
2018-11-04 0:15 ` [PATCH 7/7] CodeSamples/SMPdesign/maze: Substitute {READ/WRITE}_ONCE() for ACCESS_ONCE() Akira Yokosawa
2018-11-04 20:30 ` [PATCH 0/7] Further conversion of code snippets (howto, cpu, SMPdesign) Paul E. McKenney
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=0246eeae-facf-ef68-6da9-159693b851ec@gmail.com \
--to=akiyks@gmail.com \
--cc=paulmck@linux.ibm.com \
--cc=perfbook@vger.kernel.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.