[PATCH 4/6] count: Employ new scheme for snippet of count_lim_sig

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>From 3db4be0993d4c955dfed6a625c622c33b52bf2a5 Mon Sep 17 00:00:00 2001
From: Akira Yokosawa <akiyks@xxxxxxxxx>
Date: Tue, 9 Oct 2018 01:45:32 +0900
Subject: [PATCH 4/6] count: Employ new scheme for snippet of count_lim_sig

Signed-off-by: Akira Yokosawa <akiyks@xxxxxxxxx>
---
 CodeSamples/count/count_lim_sig.c | 148 +++++++-------
 count/count.tex                   | 395 ++++++++++----------------------------
 2 files changed, 184 insertions(+), 359 deletions(-)

diff --git a/CodeSamples/count/count_lim_sig.c b/CodeSamples/count/count_lim_sig.c
index 5eae9ba..f22bfef 100644
--- a/CodeSamples/count/count_lim_sig.c
+++ b/CodeSamples/count/count_lim_sig.c
@@ -22,77 +22,81 @@
 #include "../api.h"
 #include <signal.h>
 
-#define THEFT_IDLE	0
-#define THEFT_REQ	1
-#define	THEFT_ACK	2
-#define THEFT_READY	3
+//\begin{snippet}[labelbase=ln:count:count_lim_sig:data,commandchars=\\\@\$]
+#define THEFT_IDLE   0					//\lnlbl{value:b}
+#define THEFT_REQ    1
+#define	THEFT_ACK    2
+#define THEFT_READY  3
 
 int __thread theft = THEFT_IDLE;
-int __thread counting = 0;
-unsigned long __thread counter = 0;
+int __thread counting = 0;				//\lnlbl{value:e}
+unsigned long __thread counter = 0;			//\lnlbl{var:b}
 unsigned long __thread countermax = 0;
 unsigned long globalcountmax = 10000;
 unsigned long globalcount = 0;
 unsigned long globalreserve = 0;
 unsigned long *counterp[NR_THREADS] = { NULL };
-unsigned long *countermaxp[NR_THREADS] = { NULL };
-int *theftp[NR_THREADS] = { NULL };
+unsigned long *countermaxp[NR_THREADS] = { NULL };	//\lnlbl{maxp}
+int *theftp[NR_THREADS] = { NULL };			//\lnlbl{theftp}
 DEFINE_SPINLOCK(gblcnt_mutex);
-#define MAX_COUNTERMAX 100
+#define MAX_COUNTERMAX 100				//\lnlbl{var:e}
+//\end{snippet}
 
-static void globalize_count(void)
+//\begin{snippet}[labelbase=ln:count:count_lim_sig:migration,commandchars=\\\@\$]
+static void globalize_count(void)		//\lnlbl{globalize:b}
 {
 	globalcount += counter;
 	counter = 0;
 	globalreserve -= countermax;
 	countermax = 0;
-}
+}						//\lnlbl{globalize:e}
 
-static void flush_local_count_sig(int unused)
+static void flush_local_count_sig(int unused)	//\lnlbl{flush_sig:b}
 {
-	if (READ_ONCE(theft) != THEFT_REQ)
-		return;
-	smp_mb();
-	WRITE_ONCE(theft, THEFT_ACK);
-	if (!counting) {
-		WRITE_ONCE(theft, THEFT_READY);
+	if (READ_ONCE(theft) != THEFT_REQ)	//\lnlbl{flush_sig:check:REQ}
+		return;				//\lnlbl{flush_sig:return:n}
+	smp_mb();				//\lnlbl{flush_sig:mb:1}
+	WRITE_ONCE(theft, THEFT_ACK);		//\lnlbl{flush_sig:set:ACK}
+	if (!counting) {			//\lnlbl{flush_sig:check:fast}
+		WRITE_ONCE(theft, THEFT_READY);	//\lnlbl{flush_sig:set:READY}
 	}
 	smp_mb();
-}
+}						//\lnlbl{flush_sig:e}
 
-static void flush_local_count(void)
+static void flush_local_count(void)			//\lnlbl{flush:b}
 {
 	int t;
 	thread_id_t tid;
 
-	for_each_tid(t, tid)
-		if (theftp[t] != NULL) {
-			if (*countermaxp[t] == 0) {
-				WRITE_ONCE(*theftp[t], THEFT_READY);
-				continue;
+	for_each_tid(t, tid)				//\lnlbl{flush:loop:b}
+		if (theftp[t] != NULL) {		//\lnlbl{flush:skip}
+			if (*countermaxp[t] == 0) {	//\lnlbl{flush:checkmax}
+				WRITE_ONCE(*theftp[t], THEFT_READY);//\lnlbl{flush:READY}
+				continue;		//\lnlbl{flush:next}
 			}
-			WRITE_ONCE(*theftp[t], THEFT_REQ);
-			pthread_kill(tid, SIGUSR1);
-		}
-	for_each_tid(t, tid) {
-		if (theftp[t] == NULL)
-			continue;
-		while (READ_ONCE(*theftp[t]) != THEFT_READY) {
-			poll(NULL, 0, 1);
-			if (READ_ONCE(*theftp[t]) == THEFT_REQ)
-				pthread_kill(tid, SIGUSR1);
-		}
-		globalcount += *counterp[t];
+			WRITE_ONCE(*theftp[t], THEFT_REQ);//\lnlbl{flush:REQ}
+			pthread_kill(tid, SIGUSR1);	//\lnlbl{flush:signal}
+		}					//\lnlbl{flush:loop:e}
+	for_each_tid(t, tid) {				//\lnlbl{flush:loop2:b}
+		if (theftp[t] == NULL)			//\lnlbl{flush:skip:nonexist}
+			continue;			//\lnlbl{flush:next2}
+		while (READ_ONCE(*theftp[t]) != THEFT_READY) {//\lnlbl{flush:loop3:b}
+			poll(NULL, 0, 1);		//\lnlbl{flush:block}
+			if (READ_ONCE(*theftp[t]) == THEFT_REQ)//\lnlbl{flush:check:REQ}
+				pthread_kill(tid, SIGUSR1);//\lnlbl{flush:signal2}
+		}					//\lnlbl{flush:loop3:e}
+		globalcount += *counterp[t];		//\lnlbl{flush:thiev:b}
 		*counterp[t] = 0;
 		globalreserve -= *countermaxp[t];
-		*countermaxp[t] = 0;
-		WRITE_ONCE(*theftp[t], THEFT_IDLE);
-	}
-}
+		*countermaxp[t] = 0;			//\lnlbl{flush:thiev:e}
+		WRITE_ONCE(*theftp[t], THEFT_IDLE);	//\lnlbl{flush:IDLE}
+	}						//\lnlbl{flush:loop2:e}
+}							//\lnlbl{flush:e}
 
-static void balance_count(void)
+static void balance_count(void)				//\lnlbl{balance:b}
 {
-	countermax = globalcountmax - globalcount - globalreserve;
+	countermax = globalcountmax - globalcount -
+	             globalreserve;
 	countermax /= num_online_threads();
 	if (countermax > MAX_COUNTERMAX)
 		countermax = MAX_COUNTERMAX;
@@ -101,42 +105,49 @@ static void balance_count(void)
 	if (counter > globalcount)
 		counter = globalcount;
 	globalcount -= counter;
-}
+}							//\lnlbl{balance:e}
+//\end{snippet}
 
-int add_count(unsigned long delta)
+//\begin{snippet}[labelbase=ln:count:count_lim_sig:add,commandchars=\\\@\$]
+int add_count(unsigned long delta)			//\lnlbl{b}
 {
 	int fastpath = 0;
 
-	counting = 1;
-	barrier();
-	if (countermax - counter >= delta && READ_ONCE(theft) <= THEFT_REQ) {
-		counter += delta;
-		fastpath = 1;
+	counting = 1;					//\lnlbl{fast:b}
+	barrier();					//\lnlbl{barrier:1}
+	if (countermax - counter >= delta &&		//\lnlbl{check:b}
+	    READ_ONCE(theft) <= THEFT_REQ) {		//\lnlbl{check:e}
+		counter += delta;			//\lnlbl{add:f}
+		fastpath = 1;				//\lnlbl{fasttaken}
 	}
-	barrier();
-	counting = 0;
-	barrier();
-	if (READ_ONCE(theft) == THEFT_ACK) {
-		smp_mb();
-		WRITE_ONCE(theft, THEFT_READY);
+	barrier();					//\lnlbl{barrier:2}
+	counting = 0;					//\lnlbl{clearcnt}
+	barrier();					//\lnlbl{barrier:3}
+	if (READ_ONCE(theft) == THEFT_ACK) {		//\lnlbl{check:ACK}
+		smp_mb();				//\lnlbl{mb}
+		WRITE_ONCE(theft, THEFT_READY);		//\lnlbl{READY}
 	}
 	if (fastpath)
-		return 1;
-	spin_lock(&gblcnt_mutex);
+		return 1;				//\lnlbl{return:fs}
+	spin_lock(&gblcnt_mutex);			//\lnlbl{acquire}
 	globalize_count();
-	if (globalcountmax - globalcount - globalreserve < delta) {
+	if (globalcountmax - globalcount -
+	    globalreserve < delta) {
 		flush_local_count();
-		if (globalcountmax - globalcount - globalreserve < delta) {
-			spin_unlock(&gblcnt_mutex);
-			return 0;
+		if (globalcountmax - globalcount -
+		    globalreserve < delta) {
+			spin_unlock(&gblcnt_mutex);	//\lnlbl{release:f}
+			return 0;			//\lnlbl{return:sf}
 		}
 	}
 	globalcount += delta;
 	balance_count();
 	spin_unlock(&gblcnt_mutex);
-	return 1;
-}
+	return 1;					//\lnlbl{return:ss}
+}							//\lnlbl{e}
+//\end{snippet}
 
+//\begin{snippet}[labelbase=ln:count:count_lim_sig:sub,commandchars=\\\@\$]
 int sub_count(unsigned long delta)
 {
 	int fastpath = 0;
@@ -170,7 +181,9 @@ int sub_count(unsigned long delta)
 	spin_unlock(&gblcnt_mutex);
 	return 1;
 }
+//\end{snippet}
 
+//\begin{snippet}[labelbase=ln:count:count_lim_sig:read,commandchars=\\\@\$]
 unsigned long read_count(void)
 {
 	int t;
@@ -184,8 +197,10 @@ unsigned long read_count(void)
 	spin_unlock(&gblcnt_mutex);
 	return sum;
 }
+//\end{snippet}
 
-void count_init(void)
+//\begin{snippet}[labelbase=ln:count:count_lim_sig:initialization,commandchars=\\\@\$]
+void count_init(void)					//\lnlbl{init:b}
 {
 	struct sigaction sa;
 
@@ -196,7 +211,7 @@ void count_init(void)
 		perror("sigaction");
 		exit(EXIT_FAILURE);
 	}
-}
+}							//\lnlbl{init:e}
 
 void count_register_thread(void)
 {
@@ -220,6 +235,7 @@ void count_unregister_thread(int nthreadsexpected)
 	theftp[idx] = NULL;
 	spin_unlock(&gblcnt_mutex);
 }
+//\end{snippet}
 
 void count_cleanup(void)
 {
diff --git a/count/count.tex b/count/count.tex
index bdda590..d8d60db 100644
--- a/count/count.tex
+++ b/count/count.tex
@@ -2342,131 +2342,54 @@ The slowpath then sets that thread's \co{theft} state to IDLE.
 \label{sec:count:Signal-Theft Limit Counter Implementation}
 
 \begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
-  1 #define THEFT_IDLE  0
-  2 #define THEFT_REQ   1
-  3 #define THEFT_ACK   2
-  4 #define THEFT_READY 3
-  5 
-  6 int __thread theft = THEFT_IDLE;
-  7 int __thread counting = 0;
-  8 unsigned long __thread counter = 0;
-  9 unsigned long __thread countermax = 0;
- 10 unsigned long globalcountmax = 10000;
- 11 unsigned long globalcount = 0;
- 12 unsigned long globalreserve = 0;
- 13 unsigned long *counterp[NR_THREADS] = { NULL };
- 14 unsigned long *countermaxp[NR_THREADS] = { NULL };
- 15 int *theftp[NR_THREADS] = { NULL };
- 16 DEFINE_SPINLOCK(gblcnt_mutex);
- 17 #define MAX_COUNTERMAX 100
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/count/count_lim_sig@xxxxxxxx}
 \caption{Signal-Theft Limit Counter Data}
 \label{lst:count:Signal-Theft Limit Counter Data}
 \end{listing}
 
+\begin{lineref}[ln:count:count_lim_sig:data]
 Listing~\ref{lst:count:Signal-Theft Limit Counter Data}
 (\path{count_lim_sig.c})
 shows the data structures used by the signal-theft based counter
 implementation.
-Lines~1-7 define the states and values for the per-thread theft state machine
+Lines~\lnref{value:b}-\lnref{value:e} define the states and values
+for the per-thread theft state machine
 described in the preceding section.
-Lines~8-17 are similar to earlier implementations, with the addition of
-lines~14 and~15 to allow remote access to a thread's \co{countermax}
+Lines~\lnref{var:b}-\lnref{var:e} are similar to earlier implementations,
+with the addition of
+lines~\lnref{maxp} and~\lnref{theftp} to allow remote access to a
+thread's \co{countermax}
 and \co{theft} variables, respectively.
+\end{lineref}
 
 \begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
-  1 static void globalize_count(void)
-  2 {
-  3   globalcount += counter;
-  4   counter = 0;
-  5   globalreserve -= countermax;
-  6   countermax = 0;
-  7 }
-  8 
-  9 static void flush_local_count_sig(int unused)
- 10 {
- 11   if (READ_ONCE(theft) != THEFT_REQ)
- 12     return;
- 13   smp_mb();
- 14   WRITE_ONCE(theft, THEFT_ACK);
- 15   if (!counting) {
- 16     WRITE_ONCE(theft, THEFT_READY);
- 17   }
- 18   smp_mb();
- 19 }
- 20 
- 21 static void flush_local_count(void)
- 22 {
- 23   int t;
- 24   thread_id_t tid;
- 25 
- 26   for_each_tid(t, tid)
- 27     if (theftp[t] != NULL) {
- 28       if (*countermaxp[t] == 0) {
- 29         WRITE_ONCE(*theftp[t], THEFT_READY);
- 30         continue;
- 31       }
- 32       WRITE_ONCE(*theftp[t], THEFT_REQ);
- 33       pthread_kill(tid, SIGUSR1);
- 34     }
- 35   for_each_tid(t, tid) {
- 36     if (theftp[t] == NULL)
- 37       continue;
- 38     while (READ_ONCE(*theftp[t]) != THEFT_READY) {
- 39       poll(NULL, 0, 1);
- 40       if (READ_ONCE(*theftp[t]) == THEFT_REQ)
- 41         pthread_kill(tid, SIGUSR1);
- 42     }
- 43     globalcount += *counterp[t];
- 44     *counterp[t] = 0;
- 45     globalreserve -= *countermaxp[t];
- 46     *countermaxp[t] = 0;
- 47     WRITE_ONCE(*theftp[t], THEFT_IDLE);
- 48   }
- 49 }
- 50 
- 51 static void balance_count(void)
- 52 {
- 53   countermax = globalcountmax -
- 54     globalcount - globalreserve;
- 55   countermax /= num_online_threads();
- 56   if (countermax > MAX_COUNTERMAX)
- 57     countermax = MAX_COUNTERMAX;
- 58   globalreserve += countermax;
- 59   counter = countermax / 2;
- 60   if (counter > globalcount)
- 61     counter = globalcount;
- 62   globalcount -= counter;
- 63 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/count/count_lim_sig@xxxxxxxxxxxxx}
 \caption{Signal-Theft Limit Counter Value-Migration Functions}
 \label{lst:count:Signal-Theft Limit Counter Value-Migration Functions}
 \end{listing}
 
+\begin{lineref}[ln:count:count_lim_sig:migration:globalize]
 Listing~\ref{lst:count:Signal-Theft Limit Counter Value-Migration Functions}
 shows the functions responsible for migrating counts between per-thread
 variables and the global variables.
-Lines~1-7 shows \co{globalize_count()}, which is identical to earlier
+Lines~\lnref{b}-\lnref{e} shows \co{globalize_count()},
+which is identical to earlier
 implementations.
-Lines~9-19 shows \co{flush_local_count_sig()}, which is the signal
+\end{lineref}
+\begin{lineref}[ln:count:count_lim_sig:migration:flush_sig]
+Lines~\lnref{b}-\lnref{e} shows \co{flush_local_count_sig()},
+which is the signal
 handler used in the theft process.
-Lines~11 and~12 check to see if the \co{theft} state is REQ, and, if not
+Lines~\lnref{check:REQ} and~\lnref{return:n} check to see if
+the \co{theft} state is REQ, and, if not
 returns without change.
-Line~13 executes a memory barrier to ensure that the sampling of the
+Line~\lnref{mb:1} executes a memory barrier to ensure that the sampling of the
 theft variable happens before any change to that variable.
-Line~14 sets the \co{theft} state to ACK, and, if line~15 sees that
-this thread's fastpaths are not running, line~16 sets the \co{theft}
+Line~\lnref{set:ACK} sets the \co{theft} state to ACK, and, if
+line~\lnref{check:fast} sees that
+this thread's fastpaths are not running, line~\lnref{set:READY} sets the \co{theft}
 state to READY.
+\end{lineref}
 
 \QuickQuiz{}
 	In Listing~\ref{lst:count:Signal-Theft Limit Counter Value-Migration Functions}
@@ -2475,42 +2398,44 @@ state to READY.
 	the uses of the
 	\co{theft} per-thread variable?
 \QuickQuizAnswer{
-	The first one (on line~11) can be argued to be unnecessary.
-	The last two (lines~14 and~16) are important.
+	\begin{lineref}[ln:count:count_lim_sig:migration:flush_sig]
+	The first one (on line~\lnref{check:REQ}) can be argued to be unnecessary.
+	The last two (lines~\lnref{set:ACK} and~\lnref{set:READY}) are important.
 	If these are removed, the compiler would be within its rights
-	to rewrite lines~14-17 as follows:
-
-	\vspace{5pt}
-	\begin{minipage}[t]{\columnwidth}
-	\small
-	\begin{verbatim}
- 14   theft = THEFT_READY;
- 15   if (counting) {
- 16     theft = THEFT_ACK;
- 17   }
-	\end{verbatim}
-	\end{minipage}
-	\vspace{5pt}
+	to rewrite lines~\lnref{set:ACK}-\lnref{set:READY} as follows:
+	\end{lineref}
+
+\begin{VerbatimN}[firstnumber=14]
+theft = THEFT_READY;
+if (counting) {
+	theft = THEFT_ACK;
+}
+\end{VerbatimN}
 
 	This would be fatal, as the slowpath might see the transient
 	value of \co{THEFT_READY}, and start stealing before the
 	corresponding thread was ready.
 } \QuickQuizEnd
 
-Lines~21-49 shows \co{flush_local_count()}, which is called from the
+\begin{lineref}[ln:count:count_lim_sig:migration:flush]
+Lines~\lnref{b}-\lnref{e} shows \co{flush_local_count()}, which is called from the
 slowpath to flush all threads' local counts.
-The loop spanning lines~26-34 advances the \co{theft} state for each
+The loop spanning
+lines~\lnref{loop:b}-{loop:e} advances the \co{theft} state for each
 thread that has local count, and also sends that thread a signal.
-Line~27 skips any non-existent threads.
-Otherwise, line~28 checks to see if the current thread holds any local
-count, and, if not, line~29 sets the thread's \co{theft} state to READY
-and line~30 skips to the next thread.
-Otherwise, line~32 sets the thread's \co{theft} state to REQ and
-line~33 sends the thread a signal.
+Line~\lnref{skip} skips any non-existent threads.
+Otherwise, line~\lnref{checkmax} checks to see if the current thread holds any local
+count, and, if not, line~\lnref{READY} sets the thread's \co{theft} state to READY
+and line~\lnref{next} skips to the next thread.
+Otherwise, line~\lnref{REQ} sets the thread's \co{theft} state to REQ and
+line~\lnref{signal} sends the thread a signal.
+\end{lineref}
 
 \QuickQuiz{}
 	In Listing~\ref{lst:count:Signal-Theft Limit Counter Value-Migration Functions},
-	why is it safe for line~28 to directly access the other thread's
+	why is it safe for
+        line~\ref{ln:count:count_lim_sig:migration:flush:checkmax}
+        to directly access the other thread's
 	\co{countermax} variable?
 \QuickQuizAnswer{
 	Because the other thread is not permitted to change the value
@@ -2524,7 +2449,9 @@ line~33 sends the thread a signal.
 
 \QuickQuiz{}
 	In Listing~\ref{lst:count:Signal-Theft Limit Counter Value-Migration Functions},
-	why doesn't line~33 check for the current thread sending itself
+	why doesn't
+        line~\ref{ln:count:count_lim_sig:migration:flush:signal}
+        check for the current thread sending itself
 	a signal?
 \QuickQuizAnswer{
 	There is no need for an additional check.
@@ -2544,19 +2471,26 @@ line~33 sends the thread a signal.
 	handler and the code interrupted by the signal.
 } \QuickQuizEnd
 
-The loop spanning lines~35-48 waits until each thread reaches READY state,
+\begin{lineref}[ln:count:count_lim_sig:migration:flush]
+The loop spanning lines~\lnref{loop2:b}-\lnref{loop2:e} waits until each
+thread reaches READY state,
 then steals that thread's count.
-Lines~36-37 skip any non-existent threads, and the loop spanning
-lines~38-42 wait until the current thread's \co{theft} state becomes READY.
-Line~39 blocks for a millisecond to avoid priority-inversion problems,
-and if line~40 determines that the thread's signal has not yet arrived,
-line~41 resends the signal.
-Execution reaches line~43 when the thread's \co{theft} state becomes
-READY, so lines~43-46 do the thieving.
-Line~47 then sets the thread's \co{theft} state back to IDLE.
+Lines~\lnref{skip:nonexist}-\lnref{next2} skip any non-existent threads,
+and the loop spanning
+lines~\lnref{loop3:b}-\lnref{loop3:e} wait until the current
+thread's \co{theft} state becomes READY.
+Line~\lnref{block} blocks for a millisecond to avoid priority-inversion problems,
+and if line~\lnref{check:REQ} determines that the thread's signal has not yet arrived,
+line~\lnref{signal2} resends the signal.
+Execution reaches line~\lnref{thiev:b} when the thread's \co{theft} state becomes
+READY, so lines~\lnref{thiev:b}-\lnref{thiev:e} do the thieving.
+Line~\lnref{IDLE} then sets the thread's \co{theft} state back to IDLE.
+\end{lineref}
 
 \QuickQuiz{}
-	In Listing~\ref{lst:count:Signal-Theft Limit Counter Value-Migration Functions}, why does line~41 resend the signal?
+	In Listing~\ref{lst:count:Signal-Theft Limit Counter Value-Migration Functions},
+        why does line~\ref{ln:count:count_lim_sig:migration:flush:signal2}
+        resend the signal?
 \QuickQuizAnswer{
 	Because many operating systems over several decades have
 	had the property of losing the occasional signal.
@@ -2568,153 +2502,66 @@ Line~47 then sets the thread's \co{theft} state back to IDLE.
 	\emph{Your} user application hanging!
 } \QuickQuizEnd
 
-Lines~51-63 show \co{balance_count()}, which is similar to that of
+\begin{lineref}[ln:count:count_lim_sig:migration:balance]
+Lines~\lnref{b}-\lnref{e} show \co{balance_count()}, which is similar to that of
 earlier examples.
+\end{lineref}
 
 \begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
-  1 int add_count(unsigned long delta)
-  2 {
-  3   int fastpath = 0;
-  4 
-  5   counting = 1;
-  6   barrier();
-  7   if (countermax - counter >= delta &&
-  8       READ_ONCE(theft) <= THEFT_REQ) {
-  9     counter += delta;
- 10     fastpath = 1;
- 11   }
- 12   barrier();
- 13   counting = 0;
- 14   barrier();
- 15   if (READ_ONCE(theft) == THEFT_ACK) {
- 16     smp_mb();
- 17     WRITE_ONCE(theft, THEFT_READY);
- 18   }
- 19   if (fastpath)
- 20     return 1;
- 21   spin_lock(&gblcnt_mutex);
- 22   globalize_count();
- 23   if (globalcountmax - globalcount -
- 24       globalreserve < delta) {
- 25     flush_local_count();
- 26     if (globalcountmax - globalcount -
- 27         globalreserve < delta) {
- 28       spin_unlock(&gblcnt_mutex);
- 29       return 0;
- 30     }
- 31   }
- 32   globalcount += delta;
- 33   balance_count();
- 34   spin_unlock(&gblcnt_mutex);
- 35   return 1;
- 36 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/count/count_lim_sig@xxxxxxx}
 \caption{Signal-Theft Limit Counter Add Function}
 \label{lst:count:Signal-Theft Limit Counter Add Function}
 \end{listing}
 
 \begin{listing}[tb]
-{ \scriptsize
-\begin{verbbox}
- 38 int sub_count(unsigned long delta)
- 39 {
- 40   int fastpath = 0;
- 41 
- 42   counting = 1;
- 43   barrier();
- 44   if (counter >= delta &&
- 45       READ_ONCE(theft) <= THEFT_REQ) {
- 46     counter -= delta;
- 47     fastpath = 1;
- 48   }
- 49   barrier();
- 50   counting = 0;
- 51   barrier();
- 52   if (READ_ONCE(theft) == THEFT_ACK) {
- 53     smp_mb();
- 54     WRITE_ONCE(theft, THEFT_READY);
- 55   }
- 56   if (fastpath)
- 57     return 1;
- 58   spin_lock(&gblcnt_mutex);
- 59   globalize_count();
- 60   if (globalcount < delta) {
- 61     flush_local_count();
- 62     if (globalcount < delta) {
- 63       spin_unlock(&gblcnt_mutex);
- 64       return 0;
- 65     }
- 66   }
- 67   globalcount -= delta;
- 68   balance_count();
- 69   spin_unlock(&gblcnt_mutex);
- 70   return 1;
- 71 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/count/count_lim_sig@xxxxxxx}
 \caption{Signal-Theft Limit Counter Subtract Function}
 \label{lst:count:Signal-Theft Limit Counter Subtract Function}
 \end{listing}
 
+\begin{lineref}[ln:count:count_lim_sig:add]
 Listing~\ref{lst:count:Signal-Theft Limit Counter Add Function}
 shows the \co{add_count()} function.
-The fastpath spans lines~5-20, and the slowpath lines~21-35.
-Line~5 sets the per-thread \co{counting} variable to 1 so that
+The fastpath spans lines~\lnref{fast:b}-\lnref{return:fs}, and the slowpath
+lines~\lnref{acquire}-\lnref{return:ss}.
+Line~\lnref{fast:b} sets the per-thread \co{counting} variable to 1 so that
 any subsequent signal handlers interrupting this thread will
 set the \co{theft} state to ACK rather than READY, allowing this
 fastpath to complete properly.
-Line~6 prevents the compiler from reordering any of the fastpath body
+Line~\lnref{barrier:1} prevents the compiler from reordering any of the fastpath body
 to precede the setting of \co{counting}.
-Lines~7 and~8 check to see if the per-thread data can accommodate
+Lines~\lnref{check:b} and~\lnref{check:e} check to see
+if the per-thread data can accommodate
 the \co{add_count()} and if there is no ongoing theft in progress,
-and if so line~9 does the fastpath addition and line~10 notes that
+and if so line~\lnref{add:f} does the fastpath addition and
+line~\lnref{fasttaken} notes that
 the fastpath was taken.
 
-In either case, line~12 prevents the compiler from reordering the
-fastpath body to follow line~13, which permits any subsequent signal
+In either case, line~\lnref{barrier:2} prevents the compiler from reordering the
+fastpath body to follow line~\lnref{clearcnt}, which permits any subsequent signal
 handlers to undertake theft.
-Line~14 again disables compiler reordering, and then line~15
+Line~\lnref{barrier:3} again disables compiler reordering, and then
+line~\lnref{check:ACK}
 checks to see if the signal handler deferred the \co{theft}
-state-change to READY, and, if so, line~16 executes a memory
-barrier to ensure that any CPU that sees line~17 setting state to
-READY also sees the effects of line~9.
-If the fastpath addition at line~9 was executed, then line~20 returns
+state-change to READY, and, if so, line~\lnref{mb} executes a memory
+barrier to ensure that any CPU that sees line~\lnref{READY} setting state to
+READY also sees the effects of line~\lnref{add:f}.
+If the fastpath addition at line~\lnref{add:f} was executed, then
+line~\lnref{return:fs} returns
 success.
+\end{lineref}
 
 \begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
-  1 unsigned long read_count(void)
-  2 {
-  3   int t;
-  4   unsigned long sum;
-  5 
-  6   spin_lock(&gblcnt_mutex);
-  7   sum = globalcount;
-  8   for_each_thread(t)
-  9     if (counterp[t] != NULL)
- 10       sum += *counterp[t];
- 11   spin_unlock(&gblcnt_mutex);
- 12   return sum;
- 13 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/count/count_lim_sig@xxxxxxxx}
 \caption{Signal-Theft Limit Counter Read Function}
 \label{lst:count:Signal-Theft Limit Counter Read Function}
 \end{listing}
 
-Otherwise, we fall through to the slowpath starting at line~21.
+\begin{lineref}[ln:count:count_lim_sig:add]
+Otherwise, we fall through to the slowpath starting at line~\lnref{acquire}.
 The structure of the slowpath is similar to those of earlier examples,
 so its analysis is left as an exercise to the reader.
+\end{lineref}
 Similarly, the structure of \co{sub_count()} on
 Listing~\ref{lst:count:Signal-Theft Limit Counter Subtract Function}
 is the same
@@ -2724,52 +2571,13 @@ left as an exercise for the reader, as is the analysis of
 Listing~\ref{lst:count:Signal-Theft Limit Counter Read Function}.
 
 \begin{listing}[tbp]
-{ \scriptsize
-\begin{verbbox}
-  1 void count_init(void)
-  2 {
-  3   struct sigaction sa;
-  4 
-  5   sa.sa_handler = flush_local_count_sig;
-  6   sigemptyset(&sa.sa_mask);
-  7   sa.sa_flags = 0;
-  8   if (sigaction(SIGUSR1, &sa, NULL) != 0) {
-  9     perror("sigaction");
- 10     exit(-1);
- 11   }
- 12 }
- 13 
- 14 void count_register_thread(void)
- 15 {
- 16   int idx = smp_thread_id();
- 17 
- 18   spin_lock(&gblcnt_mutex);
- 19   counterp[idx] = &counter;
- 20   countermaxp[idx] = &countermax;
- 21   theftp[idx] = &theft;
- 22   spin_unlock(&gblcnt_mutex);
- 23 }
- 24 
- 25 void count_unregister_thread(int nthreadsexpected)
- 26 {
- 27   int idx = smp_thread_id();
- 28 
- 29   spin_lock(&gblcnt_mutex);
- 30   globalize_count();
- 31   counterp[idx] = NULL;
- 32   countermaxp[idx] = NULL;
- 33   theftp[idx] = NULL;
- 34   spin_unlock(&gblcnt_mutex);
- 35 }
-\end{verbbox}
-}
-\centering
-\theverbbox
+\input{CodeSamples/count/count_lim_sig@xxxxxxxxxxxxxxxxxx}
 \caption{Signal-Theft Limit Counter Initialization Functions}
 \label{lst:count:Signal-Theft Limit Counter Initialization Functions}
 \end{listing}
 
-Lines~1-12 of
+\begin{lineref}[ln:count:count_lim_sig:initialization:init]
+Lines~\lnref{b}-\lnref{e} of
 Listing~\ref{lst:count:Signal-Theft Limit Counter Initialization Functions}
 show \co{count_init()}, which set up \co{flush_local_count_sig()}
 as the signal handler for \co{SIGUSR1},
@@ -2778,6 +2586,7 @@ to invoke \co{flush_local_count_sig()}.
 The code for thread registry and unregistry is similar to that of
 earlier examples, so its analysis is left as an exercise for the
 reader.
+\end{lineref}
 
 \subsection{Signal-Theft Limit Counter Discussion}
 
-- 
2.7.4





[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux