1b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Copyright 2006 Google Inc. All Rights Reserved.
2b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Licensed under the Apache License, Version 2.0 (the "License");
4b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// you may not use this file except in compliance with the License.
5b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// You may obtain a copy of the License at
6b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
7b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//      http://www.apache.org/licenses/LICENSE-2.0
8b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
9b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Unless required by applicable law or agreed to in writing, software
10b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// distributed under the License is distributed on an "AS IS" BASIS,
11b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// See the License for the specific language governing permissions and
13b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// limitations under the License.
14b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
15b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// worker.cc : individual tasks that can be run in combination to
16b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// stress the system
17b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
18b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <errno.h>
19b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <pthread.h>
20b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <sched.h>
21b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <signal.h>
22b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <stdlib.h>
23b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <stdio.h>
24b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <stdint.h>
25b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <string.h>
26b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <time.h>
27b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <unistd.h>
28b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
29b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <sys/select.h>
30b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <sys/stat.h>
31b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <sys/types.h>
32b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <sys/times.h>
33b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
34b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// These are necessary, but on by default
35b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// #define __USE_GNU
36b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// #define __USE_LARGEFILE64
37b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <fcntl.h>
38b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <sys/socket.h>
39b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <netdb.h>
40b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <arpa/inet.h>
41b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <linux/unistd.h>  // for gettid
42b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
43b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// For size of block device
44b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <sys/ioctl.h>
45b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <linux/fs.h>
46b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// For asynchronous I/O
478f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_LIBAIO_H
48b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <libaio.h>
498f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
50b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
51b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <sys/syscall.h>
52b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
53b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <set>
54b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <string>
55b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
56b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// This file must work with autoconf on its public version,
57b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// so these includes are correct.
58b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include "error_diag.h"  // NOLINT
59b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include "os.h"          // NOLINT
60b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include "pattern.h"     // NOLINT
61b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include "queue.h"       // NOLINT
62b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include "sat.h"         // NOLINT
63b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include "sattypes.h"    // NOLINT
64b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include "worker.h"      // NOLINT
65b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
66b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Syscalls
67b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Why ubuntu, do you hate gettid so bad?
68b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#if !defined(__NR_gettid)
69b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  #define __NR_gettid             224
70b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#endif
71b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
72b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#define gettid() syscall(__NR_gettid)
73b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#if !defined(CPU_SETSIZE)
74b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson_syscall3(int, sched_getaffinity, pid_t, pid,
75b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          unsigned int, len, cpu_set_t*, mask)
76b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson_syscall3(int, sched_setaffinity, pid_t, pid,
77b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          unsigned int, len, cpu_set_t*, mask)
78b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#endif
79b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
80b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonnamespace {
81b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Get HW core ID from cpuid instruction.
82b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  inline int apicid(void) {
83b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int cpu;
84b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#if defined(STRESSAPPTEST_CPU_X86_64) || defined(STRESSAPPTEST_CPU_I686)
85b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    __asm __volatile("cpuid" : "=b" (cpu) : "a" (1) : "cx", "dx");
86b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#elif defined(STRESSAPPTEST_CPU_ARMV7A)
87b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  #warning "Unsupported CPU type ARMV7A: unable to determine core ID."
88b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    cpu = 0;
89b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#else
90b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  #warning "Unsupported CPU type: unable to determine core ID."
91b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    cpu = 0;
92b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#endif
93b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return (cpu >> 24);
94b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
95b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
96b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Work around the sad fact that there are two (gnu, xsi) incompatible
97b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // versions of strerror_r floating around google. Awesome.
98b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool sat_strerror(int err, char *buf, int len) {
99b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    buf[0] = 0;
100b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    char *errmsg = reinterpret_cast<char*>(strerror_r(err, buf, len));
101b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int retval = reinterpret_cast<int64>(errmsg);
102b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (retval == 0)
103b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return true;
104b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (retval == -1)
105b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
106b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (errmsg != buf) {
107b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      strncpy(buf, errmsg, len);
108b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      buf[len - 1] = 0;
109b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
110b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return true;
111b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
112b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
113b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
114b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  inline uint64 addr_to_tag(void *address) {
115b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return reinterpret_cast<uint64>(address);
116b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
117b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
118b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
119b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#if !defined(O_DIRECT)
120b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Sometimes this isn't available.
121b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Disregard if it's not defined.
122b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  #define O_DIRECT            0
123b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#endif
124b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
125b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// A struct to hold captured errors, for later reporting.
126b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonstruct ErrorRecord {
127b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 actual;  // This is the actual value read.
128b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 reread;  // This is the actual value, reread.
129b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 expected;  // This is what it should have been.
130b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 *vaddr;  // This is where it was (or wasn't).
131b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  char *vbyteaddr;  // This is byte specific where the data was (or wasn't).
132b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 paddr;  // This is the bus address, if available.
133b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 *tagvaddr;  // This holds the tag value if this data was tagged.
134b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 tagpaddr;  // This holds the physical address corresponding to the tag.
135b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson};
136b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
137b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// This is a helper function to create new threads with pthreads.
138b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonstatic void *ThreadSpawnerGeneric(void *ptr) {
139b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  WorkerThread *worker = static_cast<WorkerThread*>(ptr);
140b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  worker->StartRoutine();
141b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return NULL;
142b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
143b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
144b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid WorkerStatus::Initialize() {
145b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(0 == pthread_mutex_init(&num_workers_mutex_, NULL));
146b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(0 == pthread_rwlock_init(&status_rwlock_, NULL));
1478f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef _POSIX_BARRIERS
148b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(0 == pthread_barrier_init(&pause_barrier_, NULL,
149b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                       num_workers_ + 1));
1508f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
151b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
152b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
153b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid WorkerStatus::Destroy() {
154b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(0 == pthread_mutex_destroy(&num_workers_mutex_));
155b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(0 == pthread_rwlock_destroy(&status_rwlock_));
1568f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef _POSIX_BARRIERS
157b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(0 == pthread_barrier_destroy(&pause_barrier_));
1588f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
159b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
160b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
161b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid WorkerStatus::PauseWorkers() {
162b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (SetStatus(PAUSE) != PAUSE)
163b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    WaitOnPauseBarrier();
164b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
165b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
166b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid WorkerStatus::ResumeWorkers() {
167b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (SetStatus(RUN) == PAUSE)
168b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    WaitOnPauseBarrier();
169b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
170b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
171b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid WorkerStatus::StopWorkers() {
172b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (SetStatus(STOP) == PAUSE)
173b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    WaitOnPauseBarrier();
174b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
175b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
176b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerStatus::ContinueRunning() {
177b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // This loop is an optimization.  We use it to immediately re-check the status
178b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // after resuming from a pause, instead of returning and waiting for the next
179b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // call to this function.
180b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (;;) {
181b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    switch (GetStatus()) {
182b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      case RUN:
183b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        return true;
184b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      case PAUSE:
185b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        // Wait for the other workers to call this function so that
186b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        // PauseWorkers() can return.
187b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        WaitOnPauseBarrier();
188b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        // Wait for ResumeWorkers() to be called.
189b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        WaitOnPauseBarrier();
190b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        break;
191b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      case STOP:
192b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        return false;
193b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
194b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
195b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
196b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
197b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerStatus::ContinueRunningNoPause() {
198b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return (GetStatus() != STOP);
199b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
200b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
201b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid WorkerStatus::RemoveSelf() {
202b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Acquire a read lock on status_rwlock_ while (status_ != PAUSE).
203b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (;;) {
204b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    AcquireStatusReadLock();
205b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (status_ != PAUSE)
206b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
207b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // We need to obey PauseWorkers() just like ContinueRunning() would, so that
208b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // the other threads won't wait on pause_barrier_ forever.
209b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    ReleaseStatusLock();
210b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Wait for the other workers to call this function so that PauseWorkers()
211b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // can return.
212b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    WaitOnPauseBarrier();
213b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Wait for ResumeWorkers() to be called.
214b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    WaitOnPauseBarrier();
215b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
216b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
217b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // This lock would be unnecessary if we held a write lock instead of a read
218b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // lock on status_rwlock_, but that would also force all threads calling
219b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // ContinueRunning() to wait on this one.  Using a separate lock avoids that.
220b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  AcquireNumWorkersLock();
221b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Decrement num_workers_ and reinitialize pause_barrier_, which we know isn't
222b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // in use because (status != PAUSE).
2238f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef _POSIX_BARRIERS
224b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(0 == pthread_barrier_destroy(&pause_barrier_));
225b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(0 == pthread_barrier_init(&pause_barrier_, NULL, num_workers_));
2268f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
227b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  --num_workers_;
228b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  ReleaseNumWorkersLock();
229b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
230b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Release status_rwlock_.
231b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  ReleaseStatusLock();
232b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
233b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
234b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
235b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Parent thread class.
236b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonWorkerThread::WorkerThread() {
237b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = false;
238b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_copied_ = 0;
239b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  errorcount_ = 0;
240b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  runduration_usec_ = 1;
241b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  priority_ = Normal;
242b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  worker_status_ = NULL;
243b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  thread_spawner_ = &ThreadSpawnerGeneric;
244b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  tag_mode_ = false;
245b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
246b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
247b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonWorkerThread::~WorkerThread() {}
248b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
249b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Constructors. Just init some default values.
250b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonFillThread::FillThread() {
251b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  num_pages_to_fill_ = 0;
252b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
253b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
254b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Initialize file name to empty.
255b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonFileThread::FileThread() {
256b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  filename_ = "";
257b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  devicename_ = "";
258b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pass_ = 0;
259b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  page_io_ = true;
260b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  crc_page_ = -1;
261b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  local_page_ = NULL;
262b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
263b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
264b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// If file thread used bounce buffer in memory, account for the extra
265b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// copy for memory bandwidth calculation.
266b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonfloat FileThread::GetMemoryCopiedData() {
267b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!os_->normal_mem())
268b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return GetCopiedData();
269b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  else
270b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return 0;
271b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
272b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
273b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Initialize target hostname to be invalid.
274b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonNetworkThread::NetworkThread() {
275b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  snprintf(ipaddr_, sizeof(ipaddr_), "Unknown");
276b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sock_ = 0;
277b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
278b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
279b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Initialize?
280b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonNetworkSlaveThread::NetworkSlaveThread() {
281b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
282b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
283b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Initialize?
284b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonNetworkListenThread::NetworkListenThread() {
285b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
286b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
287b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Init member variables.
288b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid WorkerThread::InitThread(int thread_num_init,
289b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              class Sat *sat_init,
290b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              class OsLayer *os_init,
291b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              class PatternList *patternlist_init,
292b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              WorkerStatus *worker_status) {
293b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(worker_status);
294b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  worker_status->AddWorkers(1);
295b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
296b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  thread_num_ = thread_num_init;
297b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_ = sat_init;
298b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_ = os_init;
299b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  patternlist_ = patternlist_init;
300b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  worker_status_ = worker_status;
301b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
302b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  AvailableCpus(&cpu_mask_);
303b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  tag_ = 0xffffffff;
304b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
305b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  tag_mode_ = sat_->tag_mode();
306b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
307b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
308b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
309b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Use pthreads to prioritize a system thread.
310b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::InitPriority() {
311b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // This doesn't affect performance that much, and may not be too safe.
312b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
313b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool ret = BindToCpus(&cpu_mask_);
314b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!ret)
315b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(11, "Log: Bind to %s failed.\n",
316b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              cpuset_format(&cpu_mask_).c_str());
317b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
318b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(11, "Log: Thread %d running on apic ID %d mask %s (%s).\n",
319b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, apicid(),
320b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            CurrentCpusFormat().c_str(),
321b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            cpuset_format(&cpu_mask_).c_str());
322b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#if 0
323b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (priority_ == High) {
324b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    sched_param param;
325b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    param.sched_priority = 1;
326b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Set the priority; others are unchanged.
327b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Log: Changing priority to SCHED_FIFO %d\n",
328b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              param.sched_priority);
329b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (sched_setscheduler(0, SCHED_FIFO, &param)) {
330b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      char buf[256];
331b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      sat_strerror(errno, buf, sizeof(buf));
332b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: sched_setscheduler "
333b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                   "failed - error %d %s\n",
334b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                errno, buf);
335b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
336b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
337b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#endif
338b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
339b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
340b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
341b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Use pthreads to create a system thread.
342b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonint WorkerThread::SpawnThread() {
343b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Create the new thread.
344b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int result = pthread_create(&thread_, NULL, thread_spawner_, this);
345b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (result) {
346b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    char buf[256];
347b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    sat_strerror(result, buf, sizeof(buf));
348b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: pthread_create "
349b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  "failed - error %d %s\n", result,
350b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              buf);
351b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
352b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
353b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
354b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
355b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // 0 is pthreads success.
356b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
357b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
358b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
359b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Kill the worker thread with SIGINT.
360b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::KillThread() {
361b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return (pthread_kill(thread_, SIGINT) == 0);
362b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
363b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
364b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Block until thread has exited.
365b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::JoinThread() {
366b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int result = pthread_join(thread_, NULL);
367b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
368b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (result) {
369b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: pthread_join failed - error %d\n", result);
370b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
371b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
372b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
373b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // 0 is pthreads success.
374b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return (!result);
375b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
376b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
377b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
378b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid WorkerThread::StartRoutine() {
379b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  InitPriority();
380b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  StartThreadTimer();
381b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  Work();
382b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  StopThreadTimer();
383b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  worker_status_->RemoveSelf();
384b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
385b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
386b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
387b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Thread work loop. Execute until marked finished.
388b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::Work() {
389b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  do {
390b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(9, "Log: ...\n");
391b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Sleep for 1 second.
392b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    sat_sleep(1);
393b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } while (IsReadyToRun());
394b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
395b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return false;
396b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
397b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
398b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
399b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Returns CPU mask of CPUs available to this process,
400b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Conceptually, each bit represents a logical CPU, ie:
401b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//   mask = 3  (11b):   cpu0, 1
402b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//   mask = 13 (1101b): cpu0, 2, 3
403b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::AvailableCpus(cpu_set_t *cpuset) {
404b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  CPU_ZERO(cpuset);
4058f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_SCHED_GETAFFINITY
406b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return sched_getaffinity(getppid(), sizeof(*cpuset), cpuset) == 0;
4078f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#else
4088f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson  return 0;
4098f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
410b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
411b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
412b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
413b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Returns CPU mask of CPUs this thread is bound to,
414b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Conceptually, each bit represents a logical CPU, ie:
415b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//   mask = 3  (11b):   cpu0, 1
416b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//   mask = 13 (1101b): cpu0, 2, 3
417b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::CurrentCpus(cpu_set_t *cpuset) {
418b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  CPU_ZERO(cpuset);
4198f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_SCHED_GETAFFINITY
420b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return sched_getaffinity(0, sizeof(*cpuset), cpuset) == 0;
4218f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#else
4228f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson  return 0;
4238f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
424b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
425b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
426b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
427b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Bind worker thread to specified CPU(s)
428b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//   Args:
429b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//     thread_mask: cpu_set_t representing CPUs, ie
430b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//                  mask = 1  (01b):   cpu0
431b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//                  mask = 3  (11b):   cpu0, 1
432b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//                  mask = 13 (1101b): cpu0, 2, 3
433b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//
434b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//   Returns true on success, false otherwise.
435b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::BindToCpus(const cpu_set_t *thread_mask) {
436b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  cpu_set_t process_mask;
437b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  AvailableCpus(&process_mask);
438b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (cpuset_isequal(thread_mask, &process_mask))
439b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return true;
440b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
441b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(11, "Log: available CPU mask - %s\n",
442b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            cpuset_format(&process_mask).c_str());
443b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!cpuset_issubset(thread_mask, &process_mask)) {
444b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Invalid cpu_mask, ie cpu not allocated to this process or doesn't exist.
445b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Log: requested CPUs %s not a subset of available %s\n",
446b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              cpuset_format(thread_mask).c_str(),
447b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              cpuset_format(&process_mask).c_str());
448b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
449b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
4508f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_SCHED_GETAFFINITY
451b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return (sched_setaffinity(gettid(), sizeof(*thread_mask), thread_mask) == 0);
4528f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#else
4538f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson  return 0;
4548f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
455b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
456b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
457b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
458b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// A worker thread can yield itself to give up CPU until it's scheduled again.
459b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson//   Returns true on success, false on error.
460b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::YieldSelf() {
461b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return (sched_yield() == 0);
462b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
463b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
464b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
465b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Fill this page with its pattern.
466b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::FillPage(struct page_entry *pe) {
467b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Error check arguments.
468b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (pe == 0) {
469b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Fill Page entry null\n");
470b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return 0;
471b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
472b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
473b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Mask is the bitmask of indexes used by the pattern.
474b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // It is the pattern size -1. Size is always a power of 2.
475b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 *memwords = static_cast<uint64*>(pe->addr);
476b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int length = sat_->page_length();
477b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
478b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (tag_mode_) {
479b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Select tag or data as appropriate.
480b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int i = 0; i < length / wordsize_; i++) {
481b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      datacast_t data;
482b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
483b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if ((i & 0x7) == 0) {
484b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        data.l64 = addr_to_tag(&memwords[i]);
485b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      } else {
486b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        data.l32.l = pe->pattern->pattern(i << 1);
487b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        data.l32.h = pe->pattern->pattern((i << 1) + 1);
488b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
489b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      memwords[i] = data.l64;
490b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
491b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else {
492b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Just fill in untagged data directly.
493b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int i = 0; i < length / wordsize_; i++) {
494b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      datacast_t data;
495b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
496b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l32.l = pe->pattern->pattern(i << 1);
497b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l32.h = pe->pattern->pattern((i << 1) + 1);
498b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      memwords[i] = data.l64;
499b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
500b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
501b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
502b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return 1;
503b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
504b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
505b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
506b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Tell the thread how many pages to fill.
507b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid FillThread::SetFillPages(int64 num_pages_to_fill_init) {
508b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  num_pages_to_fill_ = num_pages_to_fill_init;
509b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
510b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
511b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Fill this page with a random pattern.
512b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FillThread::FillPageRandom(struct page_entry *pe) {
513b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Error check arguments.
514b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (pe == 0) {
515b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Fill Page entry null\n");
516b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return 0;
517b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
518b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if ((patternlist_ == 0) || (patternlist_->Size() == 0)) {
519b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: No data patterns available\n");
520b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return 0;
521b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
522b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
523b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Choose a random pattern for this block.
524b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pe->pattern = patternlist_->GetRandomPattern();
525b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (pe->pattern == 0) {
526b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Null data pattern\n");
527b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return 0;
528b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
529b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
530b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Actually fill the page.
531b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return FillPage(pe);
532b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
533b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
534b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
535b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Memory fill work loop. Execute until alloted pages filled.
536b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FillThread::Work() {
537b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool result = true;
538b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
539b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting fill thread %d\n", thread_num_);
540b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
541b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // We want to fill num_pages_to_fill pages, and
542b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // stop when we've filled that many.
543b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // We also want to capture early break
544b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct page_entry pe;
545b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 loops = 0;
546b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (IsReadyToRun() && (loops < num_pages_to_fill_)) {
547b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->GetEmpty(&pe);
548b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
549b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: fill_thread failed to pop pages, "
550b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "bailing\n");
551b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
552b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
553b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
554b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Fill the page with pattern
555b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && FillPageRandom(&pe);
556b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) break;
557b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
558b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Put the page back on the queue.
559b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->PutValid(&pe);
560b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
561b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: fill_thread failed to push pages, "
562b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "bailing\n");
563b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
564b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
565b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    loops++;
566b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
567b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
568b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Fill in thread status.
569b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_copied_ = loops;
570b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = result;
571b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Completed %d: Fill thread. Status %d, %d pages filled\n",
572b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, status_, pages_copied_);
573b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return result;
574b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
575b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
576b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
577b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Print error information about a data miscompare.
578b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid WorkerThread::ProcessError(struct ErrorRecord *error,
579b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                int priority,
580b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                const char *message) {
581b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  char dimm_string[256] = "";
582b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
583b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int apic_id = apicid();
584b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
585b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Determine if this is a write or read error.
586b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_->Flush(error->vaddr);
587b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  error->reread = *(error->vaddr);
588b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
589b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  char *good = reinterpret_cast<char*>(&(error->expected));
590b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  char *bad = reinterpret_cast<char*>(&(error->actual));
591b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
592b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(error->expected != error->actual);
593b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  unsigned int offset = 0;
594b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (offset = 0; offset < (sizeof(error->expected) - 1); offset++) {
595b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (good[offset] != bad[offset])
596b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
597b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
598b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
599b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  error->vbyteaddr = reinterpret_cast<char*>(error->vaddr) + offset;
600b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
601b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Find physical address if possible.
602b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  error->paddr = os_->VirtualToPhysical(error->vbyteaddr);
603b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
604b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Pretty print DIMM mapping if available.
605b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_->FindDimm(error->paddr, dimm_string, sizeof(dimm_string));
606b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
607b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Report parseable error.
608b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (priority < 5) {
609b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Run miscompare error through diagnoser for logging and reporting.
610b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    os_->error_diagnoser_->AddMiscompareError(dimm_string,
611b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                              reinterpret_cast<uint64>
612b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                              (error->vaddr), 1);
613b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
614b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(priority,
615b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "%s: miscompare on CPU %d(0x%s) at %p(0x%llx:%s): "
616b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "read:0x%016llx, reread:0x%016llx expected:0x%016llx\n",
617b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              message,
618b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              apic_id,
619b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              CurrentCpusFormat().c_str(),
620b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->vaddr,
621b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->paddr,
622b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              dimm_string,
623b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->actual,
624b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->reread,
625b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->expected);
626b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
627b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
628b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
629b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Overwrite incorrect data with correct data to prevent
630b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // future miscompares when this data is reused.
631b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  *(error->vaddr) = error->expected;
632b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_->Flush(error->vaddr);
633b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
634b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
635b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
636b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
637b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Print error information about a data miscompare.
638b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid FileThread::ProcessError(struct ErrorRecord *error,
639b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              int priority,
640b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              const char *message) {
641b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  char dimm_string[256] = "";
642b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
643b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Determine if this is a write or read error.
644b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_->Flush(error->vaddr);
645b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  error->reread = *(error->vaddr);
646b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
647b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  char *good = reinterpret_cast<char*>(&(error->expected));
648b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  char *bad = reinterpret_cast<char*>(&(error->actual));
649b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
650b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(error->expected != error->actual);
651b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  unsigned int offset = 0;
652b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (offset = 0; offset < (sizeof(error->expected) - 1); offset++) {
653b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (good[offset] != bad[offset])
654b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
655b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
656b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
657b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  error->vbyteaddr = reinterpret_cast<char*>(error->vaddr) + offset;
658b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
659b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Find physical address if possible.
660b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  error->paddr = os_->VirtualToPhysical(error->vbyteaddr);
661b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
662b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Pretty print DIMM mapping if available.
663b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_->FindDimm(error->paddr, dimm_string, sizeof(dimm_string));
664b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
665b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // If crc_page_ is valid, ie checking content read back from file,
666b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // track src/dst memory addresses. Otherwise catagorize as general
667b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // mememory miscompare for CRC checking everywhere else.
668b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (crc_page_ != -1) {
669b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int miscompare_byteoffset = static_cast<char*>(error->vbyteaddr) -
670b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                static_cast<char*>(page_recs_[crc_page_].dst);
671b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    os_->error_diagnoser_->AddHDDMiscompareError(devicename_,
672b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                                 crc_page_,
673b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                                 miscompare_byteoffset,
674b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                                 page_recs_[crc_page_].src,
675b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                                 page_recs_[crc_page_].dst);
676b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else {
677b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    os_->error_diagnoser_->AddMiscompareError(dimm_string,
678b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                              reinterpret_cast<uint64>
679b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                              (error->vaddr), 1);
680b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
681b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
682b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(priority,
683b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            "%s: miscompare on %s at %p(0x%llx:%s): read:0x%016llx, "
684b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            "reread:0x%016llx expected:0x%016llx\n",
685b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            message,
686b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            devicename_.c_str(),
687b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            error->vaddr,
688b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            error->paddr,
689b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            dimm_string,
690b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            error->actual,
691b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            error->reread,
692b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            error->expected);
693b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
694b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Overwrite incorrect data with correct data to prevent
695b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // future miscompares when this data is reused.
696b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  *(error->vaddr) = error->expected;
697b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_->Flush(error->vaddr);
698b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
699b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
700b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
701b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Do a word by word result check of a region.
702b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Print errors on mismatches.
703b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonint WorkerThread::CheckRegion(void *addr,
704b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              class Pattern *pattern,
705b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              int64 length,
706b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              int offset,
707b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              int64 pattern_offset) {
708b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 *memblock = static_cast<uint64*>(addr);
709b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const int kErrorLimit = 128;
710b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int errors = 0;
711b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int overflowerrors = 0;  // Count of overflowed errors.
712b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool page_error = false;
713b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  string errormessage("Hardware Error");
714b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct ErrorRecord
715b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    recorded[kErrorLimit];  // Queued errors for later printing.
716b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
717b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // For each word in the data region.
718b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int i = 0; i < length / wordsize_; i++) {
719b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 actual = memblock[i];
720b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 expected;
721b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
722b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Determine the value that should be there.
723b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    datacast_t data;
724b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int index = 2 * i + pattern_offset;
725b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    data.l32.l = pattern->pattern(index);
726b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    data.l32.h = pattern->pattern(index + 1);
727b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    expected = data.l64;
728b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Check tags if necessary.
729b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (tag_mode_ && ((reinterpret_cast<uint64>(&memblock[i]) & 0x3f) == 0)) {
730b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      expected = addr_to_tag(&memblock[i]);
731b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
732b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
733b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
734b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // If the value is incorrect, save an error record for later printing.
735b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (actual != expected) {
736b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (errors < kErrorLimit) {
737b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        recorded[errors].actual = actual;
738b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        recorded[errors].expected = expected;
739b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        recorded[errors].vaddr = &memblock[i];
740b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        errors++;
741b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      } else {
742b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        page_error = true;
743b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        // If we have overflowed the error queue, just print the errors now.
744b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        logprintf(10, "Log: Error record overflow, too many miscompares!\n");
745b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        errormessage = "Page Error";
746b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        break;
747b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
748b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
749b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
750b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
751b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Find if this is a whole block corruption.
752b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (page_error && !tag_mode_) {
753b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int patsize = patternlist_->Size();
754b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int pat = 0; pat < patsize; pat++) {
755b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      class Pattern *altpattern = patternlist_->GetPattern(pat);
756b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      const int kGood = 0;
757b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      const int kBad = 1;
758b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      const int kGoodAgain = 2;
759b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      const int kNoMatch = 3;
760b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      int state = kGood;
761b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      unsigned int badstart = 0;
762b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      unsigned int badend = 0;
763b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
764b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Don't match against ourself!
765b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (pattern == altpattern)
766b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        continue;
767b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
768b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      for (int i = 0; i < length / wordsize_; i++) {
769b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        uint64 actual = memblock[i];
770b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        datacast_t expected;
771b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        datacast_t possible;
772b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
773b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        // Determine the value that should be there.
774b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        int index = 2 * i + pattern_offset;
775b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
776b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        expected.l32.l = pattern->pattern(index);
777b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        expected.l32.h = pattern->pattern(index + 1);
778b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
779b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        possible.l32.l = pattern->pattern(index);
780b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        possible.l32.h = pattern->pattern(index + 1);
781b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
782b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        if (state == kGood) {
783b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          if (actual == expected.l64) {
784b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            continue;
785b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          } else if (actual == possible.l64) {
786b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            badstart = i;
787b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            badend = i;
788b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            state = kBad;
789b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            continue;
790b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          } else {
791b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            state = kNoMatch;
792b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            break;
793b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          }
794b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        } else if (state == kBad) {
795b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          if (actual == possible.l64) {
796b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            badend = i;
797b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            continue;
798b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          } else if (actual == expected.l64) {
799b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            state = kGoodAgain;
800b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            continue;
801b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          } else {
802b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            state = kNoMatch;
803b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            break;
804b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          }
805b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        } else if (state == kGoodAgain) {
806b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          if (actual == expected.l64) {
807b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            continue;
808b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          } else {
809b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            state = kNoMatch;
810b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            break;
811b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          }
812b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        }
813b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
814b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
815b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if ((state == kGoodAgain) || (state == kBad)) {
816b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        unsigned int blockerrors = badend - badstart + 1;
817b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        errormessage = "Block Error";
818b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        ProcessError(&recorded[0], 0, errormessage.c_str());
819b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        logprintf(0, "Block Error: (%p) pattern %s instead of %s, "
820b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  "%d bytes from offset 0x%x to 0x%x\n",
821b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  &memblock[badstart],
822b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  altpattern->name(), pattern->name(),
823b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  blockerrors * wordsize_,
824b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  offset + badstart * wordsize_,
825b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  offset + badend * wordsize_);
826b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        errorcount_ += blockerrors;
827b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        return blockerrors;
828b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
829b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
830b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
831b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
832b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
833b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Process error queue after all errors have been recorded.
834b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int err = 0; err < errors; err++) {
835b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int priority = 5;
836b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (errorcount_ + err < 30)
837b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      priority = 0;  // Bump up the priority for the first few errors.
838b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    ProcessError(&recorded[err], priority, errormessage.c_str());
839b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
840b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
841b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (page_error) {
842b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // For each word in the data region.
843b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int error_recount = 0;
844b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int i = 0; i < length / wordsize_; i++) {
845b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      uint64 actual = memblock[i];
846b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      uint64 expected;
847b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      datacast_t data;
848b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Determine the value that should be there.
849b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      int index = 2 * i + pattern_offset;
850b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
851b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l32.l = pattern->pattern(index);
852b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l32.h = pattern->pattern(index + 1);
853b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      expected = data.l64;
854b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
855b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Check tags if necessary.
856b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (tag_mode_ && ((reinterpret_cast<uint64>(&memblock[i]) & 0x3f) == 0)) {
857b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        expected = addr_to_tag(&memblock[i]);
858b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
859b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
860b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // If the value is incorrect, save an error record for later printing.
861b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (actual != expected) {
862b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        if (error_recount < kErrorLimit) {
863b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // We already reported these.
864b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          error_recount++;
865b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        } else {
866b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // If we have overflowed the error queue, print the errors now.
867b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          struct ErrorRecord er;
868b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          er.actual = actual;
869b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          er.expected = expected;
870b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          er.vaddr = &memblock[i];
871b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
872b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // Do the error printout. This will take a long time and
873b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // likely change the machine state.
874b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          ProcessError(&er, 12, errormessage.c_str());
875b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          overflowerrors++;
876b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        }
877b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
878b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
879b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
880b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
881b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Keep track of observed errors.
882b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  errorcount_ += errors + overflowerrors;
883b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return errors + overflowerrors;
884b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
885b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
886b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonfloat WorkerThread::GetCopiedData() {
887b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return pages_copied_ * sat_->page_length() / kMegabyte;
888b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
889b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
890b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Calculate the CRC of a region.
891b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Result check if the CRC mismatches.
892b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonint WorkerThread::CrcCheckPage(struct page_entry *srcpe) {
893b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const int blocksize = 4096;
894b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const int blockwords = blocksize / wordsize_;
895b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int errors = 0;
896b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
897b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const AdlerChecksum *expectedcrc = srcpe->pattern->crc();
898b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 *memblock = static_cast<uint64*>(srcpe->addr);
899b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int blocks = sat_->page_length() / blocksize;
900b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int currentblock = 0; currentblock < blocks; currentblock++) {
901b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 *memslice = memblock + currentblock * blockwords;
902b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
903b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    AdlerChecksum crc;
904b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (tag_mode_) {
905b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      AdlerAddrCrcC(memslice, blocksize, &crc, srcpe);
906b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else {
907b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      CalculateAdlerChecksum(memslice, blocksize, &crc);
908b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
909b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
910b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // If the CRC does not match, we'd better look closer.
911b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!crc.Equals(*expectedcrc)) {
912b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(11, "Log: CrcCheckPage Falling through to slow compare, "
913b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "CRC mismatch %s != %s\n",
914b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                crc.ToHexString().c_str(),
915b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                expectedcrc->ToHexString().c_str());
916b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      int errorcount = CheckRegion(memslice,
917b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   srcpe->pattern,
918b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   blocksize,
919b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   currentblock * blocksize, 0);
920b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (errorcount == 0) {
921b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        logprintf(0, "Log: CrcCheckPage CRC mismatch %s != %s, "
922b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                     "but no miscompares found.\n",
923b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  crc.ToHexString().c_str(),
924b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  expectedcrc->ToHexString().c_str());
925b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
926b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      errors += errorcount;
927b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
928b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
929b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
930b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // For odd length transfers, we should never hit this.
931b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int leftovers = sat_->page_length() % blocksize;
932b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (leftovers) {
933b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 *memslice = memblock + blocks * blockwords;
934b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    errors += CheckRegion(memslice,
935b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                          srcpe->pattern,
936b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                          leftovers,
937b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                          blocks * blocksize, 0);
938b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
939b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return errors;
940b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
941b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
942b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
943b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Print error information about a data miscompare.
944b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid WorkerThread::ProcessTagError(struct ErrorRecord *error,
945b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   int priority,
946b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   const char *message) {
947b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  char dimm_string[256] = "";
948b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  char tag_dimm_string[256] = "";
949b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool read_error = false;
950b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
951b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int apic_id = apicid();
952b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
953b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Determine if this is a write or read error.
954b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_->Flush(error->vaddr);
955b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  error->reread = *(error->vaddr);
956b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
957b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Distinguish read and write errors.
958b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (error->actual != error->reread) {
959b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    read_error = true;
960b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
961b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
962b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(error->expected != error->actual);
963b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
964b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  error->vbyteaddr = reinterpret_cast<char*>(error->vaddr);
965b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
966b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Find physical address if possible.
967b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  error->paddr = os_->VirtualToPhysical(error->vbyteaddr);
968b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  error->tagpaddr = os_->VirtualToPhysical(error->tagvaddr);
969b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
970b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Pretty print DIMM mapping if available.
971b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_->FindDimm(error->paddr, dimm_string, sizeof(dimm_string));
972b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Pretty print DIMM mapping if available.
973b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_->FindDimm(error->tagpaddr, tag_dimm_string, sizeof(tag_dimm_string));
974b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
975b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Report parseable error.
976b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (priority < 5) {
977b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(priority,
978b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "%s: Tag from %p(0x%llx:%s) (%s) "
979b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "miscompare on CPU %d(0x%s) at %p(0x%llx:%s): "
980b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "read:0x%016llx, reread:0x%016llx expected:0x%016llx\n",
981b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              message,
982b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->tagvaddr, error->tagpaddr,
983b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              tag_dimm_string,
984b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              read_error ? "read error" : "write error",
985b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              apic_id,
986b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              CurrentCpusFormat().c_str(),
987b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->vaddr,
988b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->paddr,
989b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              dimm_string,
990b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->actual,
991b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->reread,
992b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->expected);
993b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
994b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
995b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  errorcount_ += 1;
996b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
997b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Overwrite incorrect data with correct data to prevent
998b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // future miscompares when this data is reused.
999b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  *(error->vaddr) = error->expected;
1000b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_->Flush(error->vaddr);
1001b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1002b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1003b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1004b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Print out and log a tag error.
1005b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::ReportTagError(
1006b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 *mem64,
1007b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 actual,
1008b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 tag) {
1009b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct ErrorRecord er;
1010b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  er.actual = actual;
1011b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1012b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  er.expected = tag;
1013b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  er.vaddr = mem64;
1014b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1015b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Generate vaddr from tag.
1016b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  er.tagvaddr = reinterpret_cast<uint64*>(actual);
1017b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1018b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  ProcessTagError(&er, 0, "Hardware Error");
1019b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1020b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1021b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1022b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// C implementation of Adler memory copy, with memory tagging.
1023b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::AdlerAddrMemcpyC(uint64 *dstmem64,
1024b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                    uint64 *srcmem64,
1025b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                    unsigned int size_in_bytes,
1026b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                    AdlerChecksum *checksum,
1027b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                    struct page_entry *pe) {
1028b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Use this data wrapper to access memory with 64bit read/write.
1029b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  datacast_t data;
1030b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  datacast_t dstdata;
1031b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  unsigned int count = size_in_bytes / sizeof(data);
1032b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1033b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (count > ((1U) << 19)) {
1034b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Size is too large, must be strictly less than 512 KB.
1035b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
1036b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1037b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1038b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 a1 = 1;
1039b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 a2 = 1;
1040b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 b1 = 0;
1041b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 b2 = 0;
1042b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1043b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  class Pattern *pattern = pe->pattern;
1044b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1045b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  unsigned int i = 0;
1046b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (i < count) {
1047b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Process 64 bits at a time.
1048b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if ((i & 0x7) == 0) {
1049b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l64 = srcmem64[i];
1050b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      dstdata.l64 = dstmem64[i];
1051b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      uint64 src_tag = addr_to_tag(&srcmem64[i]);
1052b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      uint64 dst_tag = addr_to_tag(&dstmem64[i]);
1053b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Detect if tags have been corrupted.
1054b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (data.l64 != src_tag)
1055b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        ReportTagError(&srcmem64[i], data.l64, src_tag);
1056b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (dstdata.l64 != dst_tag)
1057b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        ReportTagError(&dstmem64[i], dstdata.l64, dst_tag);
1058b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1059b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l32.l = pattern->pattern(i << 1);
1060b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l32.h = pattern->pattern((i << 1) + 1);
1061b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      a1 = a1 + data.l32.l;
1062b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      b1 = b1 + a1;
1063b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      a1 = a1 + data.l32.h;
1064b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      b1 = b1 + a1;
1065b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1066b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l64  = dst_tag;
1067b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      dstmem64[i] = data.l64;
1068b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1069b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else {
1070b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l64 = srcmem64[i];
1071b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      a1 = a1 + data.l32.l;
1072b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      b1 = b1 + a1;
1073b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      a1 = a1 + data.l32.h;
1074b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      b1 = b1 + a1;
1075b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      dstmem64[i] = data.l64;
1076b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1077b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    i++;
1078b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1079b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    data.l64 = srcmem64[i];
1080b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    a2 = a2 + data.l32.l;
1081b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    b2 = b2 + a2;
1082b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    a2 = a2 + data.l32.h;
1083b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    b2 = b2 + a2;
1084b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    dstmem64[i] = data.l64;
1085b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    i++;
1086b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1087b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  checksum->Set(a1, a2, b1, b2);
1088b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1089b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1090b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1091b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// x86_64 SSE2 assembly implementation of Adler memory copy, with address
1092b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// tagging added as a second step. This is useful for debugging failures
1093b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// that only occur when SSE / nontemporal writes are used.
1094b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::AdlerAddrMemcpyWarm(uint64 *dstmem64,
1095b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                       uint64 *srcmem64,
1096b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                       unsigned int size_in_bytes,
1097b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                       AdlerChecksum *checksum,
1098b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                       struct page_entry *pe) {
1099b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Do ASM copy, ignore checksum.
1100b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  AdlerChecksum ignored_checksum;
1101b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  os_->AdlerMemcpyWarm(dstmem64, srcmem64, size_in_bytes, &ignored_checksum);
1102b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1103b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Force cache flush.
1104b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int length = size_in_bytes / sizeof(*dstmem64);
1105b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int i = 0; i < length; i += sizeof(*dstmem64)) {
1106b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    os_->FastFlush(dstmem64 + i);
1107b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    os_->FastFlush(srcmem64 + i);
1108b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1109b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Check results.
1110b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  AdlerAddrCrcC(srcmem64, size_in_bytes, checksum, pe);
1111b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Patch up address tags.
1112b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  TagAddrC(dstmem64, size_in_bytes);
1113b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1114b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1115b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1116b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Retag pages..
1117b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::TagAddrC(uint64 *memwords,
1118b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                            unsigned int size_in_bytes) {
1119b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Mask is the bitmask of indexes used by the pattern.
1120b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // It is the pattern size -1. Size is always a power of 2.
1121b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1122b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Select tag or data as appropriate.
1123b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int length = size_in_bytes / wordsize_;
1124b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int i = 0; i < length; i += 8) {
1125b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    datacast_t data;
1126b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    data.l64 = addr_to_tag(&memwords[i]);
1127b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    memwords[i] = data.l64;
1128b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1129b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1130b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1131b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1132b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// C implementation of Adler memory crc.
1133b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool WorkerThread::AdlerAddrCrcC(uint64 *srcmem64,
1134b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                 unsigned int size_in_bytes,
1135b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                 AdlerChecksum *checksum,
1136b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                 struct page_entry *pe) {
1137b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Use this data wrapper to access memory with 64bit read/write.
1138b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  datacast_t data;
1139b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  unsigned int count = size_in_bytes / sizeof(data);
1140b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1141b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (count > ((1U) << 19)) {
1142b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Size is too large, must be strictly less than 512 KB.
1143b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
1144b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1145b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1146b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 a1 = 1;
1147b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 a2 = 1;
1148b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 b1 = 0;
1149b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 b2 = 0;
1150b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1151b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  class Pattern *pattern = pe->pattern;
1152b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1153b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  unsigned int i = 0;
1154b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (i < count) {
1155b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Process 64 bits at a time.
1156b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if ((i & 0x7) == 0) {
1157b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l64 = srcmem64[i];
1158b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      uint64 src_tag = addr_to_tag(&srcmem64[i]);
1159b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Check that tags match expected.
1160b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (data.l64 != src_tag)
1161b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        ReportTagError(&srcmem64[i], data.l64, src_tag);
1162b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1163b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l32.l = pattern->pattern(i << 1);
1164b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l32.h = pattern->pattern((i << 1) + 1);
1165b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      a1 = a1 + data.l32.l;
1166b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      b1 = b1 + a1;
1167b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      a1 = a1 + data.l32.h;
1168b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      b1 = b1 + a1;
1169b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else {
1170b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data.l64 = srcmem64[i];
1171b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      a1 = a1 + data.l32.l;
1172b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      b1 = b1 + a1;
1173b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      a1 = a1 + data.l32.h;
1174b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      b1 = b1 + a1;
1175b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1176b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    i++;
1177b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1178b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    data.l64 = srcmem64[i];
1179b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    a2 = a2 + data.l32.l;
1180b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    b2 = b2 + a2;
1181b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    a2 = a2 + data.l32.h;
1182b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    b2 = b2 + a2;
1183b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    i++;
1184b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1185b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  checksum->Set(a1, a2, b1, b2);
1186b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1187b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1188b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1189b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Copy a block of memory quickly, while keeping a CRC of the data.
1190b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Result check if the CRC mismatches.
1191b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonint WorkerThread::CrcCopyPage(struct page_entry *dstpe,
1192b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              struct page_entry *srcpe) {
1193b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int errors = 0;
1194b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const int blocksize = 4096;
1195b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const int blockwords = blocksize / wordsize_;
1196b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int blocks = sat_->page_length() / blocksize;
1197b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1198b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Base addresses for memory copy
1199b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 *targetmembase = static_cast<uint64*>(dstpe->addr);
1200b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 *sourcemembase = static_cast<uint64*>(srcpe->addr);
1201b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Remember the expected CRC
1202b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const AdlerChecksum *expectedcrc = srcpe->pattern->crc();
1203b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1204b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int currentblock = 0; currentblock < blocks; currentblock++) {
1205b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 *targetmem = targetmembase + currentblock * blockwords;
1206b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 *sourcemem = sourcemembase + currentblock * blockwords;
1207b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1208b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    AdlerChecksum crc;
1209b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (tag_mode_) {
1210b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      AdlerAddrMemcpyC(targetmem, sourcemem, blocksize, &crc, srcpe);
1211b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else {
1212b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      AdlerMemcpyC(targetmem, sourcemem, blocksize, &crc);
1213b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1214b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1215b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Investigate miscompares.
1216b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!crc.Equals(*expectedcrc)) {
1217b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(11, "Log: CrcCopyPage Falling through to slow compare, "
1218b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "CRC mismatch %s != %s\n", crc.ToHexString().c_str(),
1219b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                expectedcrc->ToHexString().c_str());
1220b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      int errorcount = CheckRegion(sourcemem,
1221b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   srcpe->pattern,
1222b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   blocksize,
1223b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   currentblock * blocksize, 0);
1224b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (errorcount == 0) {
1225b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        logprintf(0, "Log: CrcCopyPage CRC mismatch %s != %s, "
1226b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                     "but no miscompares found. Retrying with fresh data.\n",
1227b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  crc.ToHexString().c_str(),
1228b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  expectedcrc->ToHexString().c_str());
1229b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        if (!tag_mode_) {
1230b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // Copy the data originally read from this region back again.
1231b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // This data should have any corruption read originally while
1232b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // calculating the CRC.
1233b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          memcpy(sourcemem, targetmem, blocksize);
1234b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          errorcount = CheckRegion(sourcemem,
1235b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   srcpe->pattern,
1236b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   blocksize,
1237b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   currentblock * blocksize, 0);
1238b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          if (errorcount == 0) {
1239b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            int apic_id = apicid();
1240b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            logprintf(0, "Process Error: CPU %d(0x%s) CrcCopyPage "
1241b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                         "CRC mismatch %s != %s, "
1242b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                         "but no miscompares found on second pass.\n",
1243b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                      apic_id, CurrentCpusFormat().c_str(),
1244b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                      crc.ToHexString().c_str(),
1245b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                      expectedcrc->ToHexString().c_str());
1246b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            struct ErrorRecord er;
1247b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            er.actual = sourcemem[0];
1248b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            er.expected = 0x0;
1249b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            er.vaddr = sourcemem;
1250b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            ProcessError(&er, 0, "Hardware Error");
1251b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          }
1252b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        }
1253b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
1254b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      errors += errorcount;
1255b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1256b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1257b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1258b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // For odd length transfers, we should never hit this.
1259b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int leftovers = sat_->page_length() % blocksize;
1260b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (leftovers) {
1261b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 *targetmem = targetmembase + blocks * blockwords;
1262b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 *sourcemem = sourcemembase + blocks * blockwords;
1263b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1264b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    errors += CheckRegion(sourcemem,
1265b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                          srcpe->pattern,
1266b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                          leftovers,
1267b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                          blocks * blocksize, 0);
1268b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int leftoverwords = leftovers / wordsize_;
1269b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int i = 0; i < leftoverwords; i++) {
1270b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      targetmem[i] = sourcemem[i];
1271b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1272b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1273b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1274b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Update pattern reference to reflect new contents.
1275b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  dstpe->pattern = srcpe->pattern;
1276b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1277b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Clean clean clean the errors away.
1278b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (errors) {
1279b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // TODO(nsanders): Maybe we should patch rather than fill? Filling may
1280b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // cause bad data to be propogated across the page.
1281b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    FillPage(dstpe);
1282b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1283b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return errors;
1284b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1285b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1286b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1287b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1288b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Invert a block of memory quickly, traversing downwards.
1289b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonint InvertThread::InvertPageDown(struct page_entry *srcpe) {
1290b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const int blocksize = 4096;
1291b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const int blockwords = blocksize / wordsize_;
1292b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int blocks = sat_->page_length() / blocksize;
1293b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1294b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Base addresses for memory copy
1295b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  unsigned int *sourcemembase = static_cast<unsigned int *>(srcpe->addr);
1296b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1297b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int currentblock = blocks-1; currentblock >= 0; currentblock--) {
1298b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    unsigned int *sourcemem = sourcemembase + currentblock * blockwords;
1299b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int i = blockwords - 32; i >= 0; i -= 32) {
1300b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      for (int index = i + 31; index >= i; --index) {
1301b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        unsigned int actual = sourcemem[index];
1302b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        sourcemem[index] = ~actual;
1303b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
1304b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      OsLayer::FastFlush(&sourcemem[i]);
1305b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1306b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1307b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1308b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return 0;
1309b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1310b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1311b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Invert a block of memory, traversing upwards.
1312b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonint InvertThread::InvertPageUp(struct page_entry *srcpe) {
1313b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const int blocksize = 4096;
1314b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const int blockwords = blocksize / wordsize_;
1315b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int blocks = sat_->page_length() / blocksize;
1316b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1317b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Base addresses for memory copy
1318b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  unsigned int *sourcemembase = static_cast<unsigned int *>(srcpe->addr);
1319b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1320b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int currentblock = 0; currentblock < blocks; currentblock++) {
1321b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    unsigned int *sourcemem = sourcemembase + currentblock * blockwords;
1322b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int i = 0; i < blockwords; i += 32) {
1323b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      for (int index = i; index <= i + 31; ++index) {
1324b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        unsigned int actual = sourcemem[index];
1325b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        sourcemem[index] = ~actual;
1326b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
1327b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      OsLayer::FastFlush(&sourcemem[i]);
1328b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1329b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1330b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return 0;
1331b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1332b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1333b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Copy a block of memory quickly, while keeping a CRC of the data.
1334b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Result check if the CRC mismatches. Warm the CPU while running
1335b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonint WorkerThread::CrcWarmCopyPage(struct page_entry *dstpe,
1336b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                  struct page_entry *srcpe) {
1337b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int errors = 0;
1338b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const int blocksize = 4096;
1339b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const int blockwords = blocksize / wordsize_;
1340b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int blocks = sat_->page_length() / blocksize;
1341b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1342b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Base addresses for memory copy
1343b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 *targetmembase = static_cast<uint64*>(dstpe->addr);
1344b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 *sourcemembase = static_cast<uint64*>(srcpe->addr);
1345b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Remember the expected CRC
1346b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const AdlerChecksum *expectedcrc = srcpe->pattern->crc();
1347b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1348b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int currentblock = 0; currentblock < blocks; currentblock++) {
1349b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 *targetmem = targetmembase + currentblock * blockwords;
1350b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 *sourcemem = sourcemembase + currentblock * blockwords;
1351b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1352b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    AdlerChecksum crc;
1353b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (tag_mode_) {
1354b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      AdlerAddrMemcpyWarm(targetmem, sourcemem, blocksize, &crc, srcpe);
1355b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else {
1356b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      os_->AdlerMemcpyWarm(targetmem, sourcemem, blocksize, &crc);
1357b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1358b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1359b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Investigate miscompares.
1360b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!crc.Equals(*expectedcrc)) {
1361b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(11, "Log: CrcWarmCopyPage Falling through to slow compare, "
1362b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "CRC mismatch %s != %s\n", crc.ToHexString().c_str(),
1363b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                expectedcrc->ToHexString().c_str());
1364b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      int errorcount = CheckRegion(sourcemem,
1365b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   srcpe->pattern,
1366b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   blocksize,
1367b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   currentblock * blocksize, 0);
1368b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (errorcount == 0) {
1369b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        logprintf(0, "Log: CrcWarmCopyPage CRC mismatch %s != %s, "
1370b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                     "but no miscompares found. Retrying with fresh data.\n",
1371b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  crc.ToHexString().c_str(),
1372b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  expectedcrc->ToHexString().c_str());
1373b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        if (!tag_mode_) {
1374b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // Copy the data originally read from this region back again.
1375b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // This data should have any corruption read originally while
1376b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // calculating the CRC.
1377b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          memcpy(sourcemem, targetmem, blocksize);
1378b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          errorcount = CheckRegion(sourcemem,
1379b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   srcpe->pattern,
1380b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   blocksize,
1381b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                   currentblock * blocksize, 0);
1382b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          if (errorcount == 0) {
1383b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            int apic_id = apicid();
1384b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            logprintf(0, "Process Error: CPU %d(0x%s) CrciWarmCopyPage "
1385b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                         "CRC mismatch %s != %s, "
1386b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                         "but no miscompares found on second pass.\n",
1387b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                      apic_id, CurrentCpusFormat().c_str(),
1388b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                      crc.ToHexString().c_str(),
1389b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                      expectedcrc->ToHexString().c_str());
1390b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            struct ErrorRecord er;
1391b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            er.actual = sourcemem[0];
1392b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            er.expected = 0x0;
1393b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            er.vaddr = sourcemem;
1394b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            ProcessError(&er, 0, "Hardware Error");
1395b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          }
1396b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        }
1397b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
1398b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      errors += errorcount;
1399b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1400b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1401b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1402b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // For odd length transfers, we should never hit this.
1403b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int leftovers = sat_->page_length() % blocksize;
1404b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (leftovers) {
1405b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 *targetmem = targetmembase + blocks * blockwords;
1406b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 *sourcemem = sourcemembase + blocks * blockwords;
1407b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1408b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    errors += CheckRegion(sourcemem,
1409b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                          srcpe->pattern,
1410b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                          leftovers,
1411b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                          blocks * blocksize, 0);
1412b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int leftoverwords = leftovers / wordsize_;
1413b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int i = 0; i < leftoverwords; i++) {
1414b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      targetmem[i] = sourcemem[i];
1415b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1416b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1417b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1418b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Update pattern reference to reflect new contents.
1419b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  dstpe->pattern = srcpe->pattern;
1420b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1421b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Clean clean clean the errors away.
1422b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (errors) {
1423b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // TODO(nsanders): Maybe we should patch rather than fill? Filling may
1424b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // cause bad data to be propogated across the page.
1425b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    FillPage(dstpe);
1426b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1427b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return errors;
1428b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1429b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1430b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1431b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1432b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Memory check work loop. Execute until done, then exhaust pages.
1433b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool CheckThread::Work() {
1434b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct page_entry pe;
1435b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool result = true;
1436b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 loops = 0;
1437b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1438b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting Check thread %d\n", thread_num_);
1439b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1440b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // We want to check all the pages, and
1441b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // stop when there aren't any left.
1442b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (true) {
1443b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->GetValid(&pe);
1444b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
1445b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (IsReadyToRunNoPause())
1446b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        logprintf(0, "Process Error: check_thread failed to pop pages, "
1447b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  "bailing\n");
1448b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      else
1449b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        result = true;
1450b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
1451b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1452b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1453b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Do the result check.
1454b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    CrcCheckPage(&pe);
1455b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1456b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Push pages back on the valid queue if we are still going,
1457b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // throw them out otherwise.
1458b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (IsReadyToRunNoPause())
1459b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      result = result && sat_->PutValid(&pe);
1460b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    else
1461b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      result = result && sat_->PutEmpty(&pe);
1462b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
1463b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: check_thread failed to push pages, "
1464b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "bailing\n");
1465b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
1466b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1467b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    loops++;
1468b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1469b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1470b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_copied_ = loops;
1471b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = result;
1472b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Completed %d: Check thread. Status %d, %d pages checked\n",
1473b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, status_, pages_copied_);
1474b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return result;
1475b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1476b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1477b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1478b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Memory copy work loop. Execute until marked done.
1479b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool CopyThread::Work() {
1480b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct page_entry src;
1481b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct page_entry dst;
1482b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool result = true;
1483b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 loops = 0;
1484b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1485b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting copy thread %d: cpu %s, mem %x\n",
1486b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, cpuset_format(&cpu_mask_).c_str(), tag_);
1487b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1488b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (IsReadyToRun()) {
1489b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Pop the needed pages.
1490b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->GetValid(&src, tag_);
1491b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->GetEmpty(&dst, tag_);
1492b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
1493b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: copy_thread failed to pop pages, "
1494b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "bailing\n");
1495b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
1496b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1497b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1498b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Force errors for unittests.
1499b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (sat_->error_injection()) {
1500b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (loops == 8) {
1501b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        char *addr = reinterpret_cast<char*>(src.addr);
1502b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        int offset = random() % sat_->page_length();
1503b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        addr[offset] = 0xba;
1504b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
1505b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1506b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1507b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // We can use memcpy, or CRC check while we copy.
1508b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (sat_->warm()) {
1509b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      CrcWarmCopyPage(&dst, &src);
1510b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else if (sat_->strict()) {
1511b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      CrcCopyPage(&dst, &src);
1512b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else {
1513b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      memcpy(dst.addr, src.addr, sat_->page_length());
1514b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      dst.pattern = src.pattern;
1515b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1516b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1517b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->PutValid(&dst);
1518b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->PutEmpty(&src);
1519b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1520b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Copy worker-threads yield themselves at the end of each copy loop,
1521b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // to avoid threads from preempting each other in the middle of the inner
1522b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // copy-loop. Cooperations between Copy worker-threads results in less
1523b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // unnecessary cache thrashing (which happens when context-switching in the
1524b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // middle of the inner copy-loop).
1525b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    YieldSelf();
1526b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1527b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
1528b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: copy_thread failed to push pages, "
1529b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "bailing\n");
1530b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
1531b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1532b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    loops++;
1533b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1534b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1535b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_copied_ = loops;
1536b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = result;
1537b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Completed %d: Copy thread. Status %d, %d pages copied\n",
1538b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, status_, pages_copied_);
1539b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return result;
1540b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1541b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1542b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Memory invert work loop. Execute until marked done.
1543b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool InvertThread::Work() {
1544b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct page_entry src;
1545b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool result = true;
1546b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 loops = 0;
1547b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1548b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting invert thread %d\n", thread_num_);
1549b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1550b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (IsReadyToRun()) {
1551b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Pop the needed pages.
1552b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->GetValid(&src);
1553b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
1554b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: invert_thread failed to pop pages, "
1555b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "bailing\n");
1556b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
1557b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1558b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1559b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (sat_->strict())
1560b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      CrcCheckPage(&src);
1561b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1562b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // For the same reason CopyThread yields itself (see YieldSelf comment
1563b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // in CopyThread::Work(), InvertThread yields itself after each invert
1564b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // operation to improve cooperation between different worker threads
1565b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // stressing the memory/cache.
1566b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    InvertPageUp(&src);
1567b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    YieldSelf();
1568b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    InvertPageDown(&src);
1569b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    YieldSelf();
1570b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    InvertPageDown(&src);
1571b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    YieldSelf();
1572b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    InvertPageUp(&src);
1573b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    YieldSelf();
1574b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1575b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (sat_->strict())
1576b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      CrcCheckPage(&src);
1577b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1578b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->PutValid(&src);
1579b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
1580b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: invert_thread failed to push pages, "
1581b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "bailing\n");
1582b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
1583b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1584b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    loops++;
1585b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1586b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1587b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_copied_ = loops * 2;
1588b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = result;
1589b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Completed %d: Copy thread. Status %d, %d pages copied\n",
1590b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, status_, pages_copied_);
1591b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return result;
1592b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1593b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1594b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1595b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Set file name to use for File IO.
1596b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid FileThread::SetFile(const char *filename_init) {
1597b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  filename_ = filename_init;
1598b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  devicename_ = os_->FindFileDevice(filename_);
1599b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1600b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1601b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Open the file for access.
1602b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::OpenFile(int *pfile) {
1603613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  bool no_O_DIRECT = false;
1604613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  int flags = O_RDWR | O_CREAT | O_SYNC;
1605613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  int fd = open(filename_.c_str(), flags | O_DIRECT, 0644);
1606613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  if (O_DIRECT != 0 && fd < 0 && errno == EINVAL) {
1607613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson    no_O_DIRECT = true;
1608613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson    fd = open(filename_.c_str(), flags, 0644); // Try without O_DIRECT
1609613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  }
1610b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (fd < 0) {
1611b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Failed to create file %s!!\n",
1612b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              filename_.c_str());
1613b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    pages_copied_ = 0;
1614b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
1615b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1616613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  if (no_O_DIRECT)
1617613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson    os_->ActivateFlushPageCache(); // Not using O_DIRECT fixed EINVAL
1618b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  *pfile = fd;
1619b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1620b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1621b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1622b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Close the file.
1623b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::CloseFile(int fd) {
1624b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  close(fd);
1625b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1626b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1627b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1628b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Check sector tagging.
1629b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::SectorTagPage(struct page_entry *src, int block) {
1630b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int page_length = sat_->page_length();
1631b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct FileThread::SectorTag *tag =
1632b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    (struct FileThread::SectorTag *)(src->addr);
1633b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1634b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Tag each sector.
1635b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  unsigned char magic = ((0xba + thread_num_) & 0xff);
1636b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int sec = 0; sec < page_length / 512; sec++) {
1637b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    tag[sec].magic = magic;
1638b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    tag[sec].block = block & 0xff;
1639b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    tag[sec].sector = sec & 0xff;
1640b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    tag[sec].pass = pass_ & 0xff;
1641b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1642b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1643b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1644b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1645b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::WritePageToFile(int fd, struct page_entry *src) {
1646b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int page_length = sat_->page_length();
1647b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Fill the file with our data.
1648b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 size = write(fd, src->addr, page_length);
1649b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1650b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (size != page_length) {
1651b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    os_->ErrorReport(devicename_.c_str(), "write-error", 1);
1652b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    errorcount_++;
1653b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Block Error: file_thread failed to write, "
1654b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "bailing\n");
1655b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
1656b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1657b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1658b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1659b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1660b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Write the data to the file.
1661b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::WritePages(int fd) {
1662b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int strict = sat_->strict();
1663b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1664b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Start fresh at beginning of file for each batch of pages.
1665b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  lseek64(fd, 0, SEEK_SET);
1666b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int i = 0; i < sat_->disk_pages(); i++) {
1667b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    struct page_entry src;
1668b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!GetValidPage(&src))
1669b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
1670b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Save expected pattern.
1671b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    page_recs_[i].pattern = src.pattern;
1672b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    page_recs_[i].src = src.addr;
1673b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1674b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Check data correctness.
1675b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (strict)
1676b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      CrcCheckPage(&src);
1677b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1678b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    SectorTagPage(&src, i);
1679b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1680b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    bool result = WritePageToFile(fd, &src);
1681b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1682b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!PutEmptyPage(&src))
1683b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
1684b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1685b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result)
1686b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
1687b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1688613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  return os_->FlushPageCache(); // If O_DIRECT worked, this will be a NOP.
1689b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1690b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1691b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Copy data from file into memory block.
1692b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::ReadPageFromFile(int fd, struct page_entry *dst) {
1693b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int page_length = sat_->page_length();
1694b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1695b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Do the actual read.
1696b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 size = read(fd, dst->addr, page_length);
1697b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (size != page_length) {
1698b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    os_->ErrorReport(devicename_.c_str(), "read-error", 1);
1699b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Block Error: file_thread failed to read, "
1700b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "bailing\n");
1701b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    errorcount_++;
1702b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
1703b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1704b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1705b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1706b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1707b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Check sector tagging.
1708b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::SectorValidatePage(const struct PageRec &page,
1709b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                    struct page_entry *dst, int block) {
1710b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Error injection.
1711b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  static int calls = 0;
1712b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  calls++;
1713b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1714b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Do sector tag compare.
1715b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int firstsector = -1;
1716b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int lastsector = -1;
1717b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool badsector = false;
1718b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int page_length = sat_->page_length();
1719b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1720b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Cast data block into an array of tagged sectors.
1721b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct FileThread::SectorTag *tag =
1722b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  (struct FileThread::SectorTag *)(dst->addr);
1723b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1724b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(sizeof(*tag) == 512);
1725b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1726b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Error injection.
1727b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (sat_->error_injection()) {
1728b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (calls == 2) {
1729b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      for (int badsec = 8; badsec < 17; badsec++)
1730b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        tag[badsec].pass = 27;
1731b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1732b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (calls == 18) {
1733b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      (static_cast<int32*>(dst->addr))[27] = 0xbadda7a;
1734b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1735b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1736b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1737b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Check each sector for the correct tag we added earlier,
1738b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // then revert the tag to the to normal data pattern.
1739b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  unsigned char magic = ((0xba + thread_num_) & 0xff);
1740b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int sec = 0; sec < page_length / 512; sec++) {
1741b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Check magic tag.
1742b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if ((tag[sec].magic != magic) ||
1743b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        (tag[sec].block != (block & 0xff)) ||
1744b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        (tag[sec].sector != (sec & 0xff)) ||
1745b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        (tag[sec].pass != (pass_ & 0xff))) {
1746b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Offset calculation for tag location.
1747b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      int offset = sec * sizeof(SectorTag);
1748b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (tag[sec].block != (block & 0xff))
1749b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        offset += 1 * sizeof(uint8);
1750b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      else if (tag[sec].sector != (sec & 0xff))
1751b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        offset += 2 * sizeof(uint8);
1752b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      else if (tag[sec].pass != (pass_ & 0xff))
1753b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        offset += 3 * sizeof(uint8);
1754b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1755b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Run sector tag error through diagnoser for logging and reporting.
1756b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      errorcount_ += 1;
1757b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      os_->error_diagnoser_->AddHDDSectorTagError(devicename_, tag[sec].block,
1758b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                                  offset,
1759b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                                  tag[sec].sector,
1760b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                                  page.src, page.dst);
1761b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1762b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(5, "Sector Error: Sector tag @ 0x%x, pass %d/%d. "
1763b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "sec %x/%x, block %d/%d, magic %x/%x, File: %s \n",
1764b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                block * page_length + 512 * sec,
1765b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                (pass_ & 0xff), (unsigned int)tag[sec].pass,
1766b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                sec, (unsigned int)tag[sec].sector,
1767b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                block, (unsigned int)tag[sec].block,
1768b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                magic, (unsigned int)tag[sec].magic,
1769b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                filename_.c_str());
1770b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1771b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Keep track of first and last bad sector.
1772b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (firstsector == -1)
1773b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        firstsector = (block * page_length / 512) + sec;
1774b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      lastsector = (block * page_length / 512) + sec;
1775b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      badsector = true;
1776b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1777b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Patch tag back to proper pattern.
1778b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    unsigned int *addr = (unsigned int *)(&tag[sec]);
1779b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    *addr = dst->pattern->pattern(512 * sec / sizeof(*addr));
1780b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1781b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1782b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // If we found sector errors:
1783b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (badsector == true) {
1784b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(5, "Log: file sector miscompare at offset %x-%x. File: %s\n",
1785b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              firstsector * 512,
1786b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              ((lastsector + 1) * 512) - 1,
1787b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              filename_.c_str());
1788b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1789b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Either exit immediately, or patch the data up and continue.
1790b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (sat_->stop_on_error()) {
1791b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      exit(1);
1792b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else {
1793b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Patch up bad pages.
1794b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      for (int block = (firstsector * 512) / page_length;
1795b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          block <= (lastsector * 512) / page_length;
1796b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          block++) {
1797b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        unsigned int *memblock = static_cast<unsigned int *>(dst->addr);
1798b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        int length = page_length / wordsize_;
1799b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        for (int i = 0; i < length; i++) {
1800b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          memblock[i] = dst->pattern->pattern(i);
1801b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        }
1802b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
1803b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1804b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1805b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1806b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1807b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1808b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Get memory for an incoming data transfer..
1809b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::PagePrepare() {
1810b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // We can only do direct IO to SAT pages if it is normal mem.
1811b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  page_io_ = os_->normal_mem();
1812b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1813b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Init a local buffer if we need it.
1814b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!page_io_) {
18158f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_POSIX_MEMALIGN
1816b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int result = posix_memalign(&local_page_, 512, sat_->page_length());
18178f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#else
18188f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson    local_page_ = memalign(512, sat_->page_length());
18198f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson    int result = (local_page_ == 0);
18208f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
1821b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (result) {
1822b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: disk thread posix_memalign "
1823b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                   "returned %d (fail)\n",
1824b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                result);
1825b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      status_ = false;
1826b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
1827b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1828b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1829b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1830b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1831b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1832b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1833b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Remove memory allocated for data transfer.
1834b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::PageTeardown() {
1835b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Free a local buffer if we need to.
1836b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!page_io_) {
1837b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    free(local_page_);
1838b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1839b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1840b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1841b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1842b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1843b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1844b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Get memory for an incoming data transfer..
1845b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::GetEmptyPage(struct page_entry *dst) {
1846b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (page_io_) {
1847b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!sat_->GetEmpty(dst))
1848b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
1849b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else {
1850b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    dst->addr = local_page_;
1851b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    dst->offset = 0;
1852b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    dst->pattern = 0;
1853b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1854b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1855b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1856b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1857b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Get memory for an outgoing data transfer..
1858b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::GetValidPage(struct page_entry *src) {
1859b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct page_entry tmp;
1860b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!sat_->GetValid(&tmp))
1861b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
1862b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (page_io_) {
1863b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    *src = tmp;
1864b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return true;
1865b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else {
1866b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    src->addr = local_page_;
1867b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    src->offset = 0;
1868b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    CrcCopyPage(src, &tmp);
1869b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!sat_->PutValid(&tmp))
1870b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
1871b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1872b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1873b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1874b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1875b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1876b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Throw out a used empty page.
1877b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::PutEmptyPage(struct page_entry *src) {
1878b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (page_io_) {
1879b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!sat_->PutEmpty(src))
1880b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
1881b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1882b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1883b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1884b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1885b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Throw out a used, filled page.
1886b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::PutValidPage(struct page_entry *src) {
1887b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (page_io_) {
1888b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!sat_->PutValid(src))
1889b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
1890b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1891b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1892b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1893b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1894b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Copy data from file into memory blocks.
1895b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::ReadPages(int fd) {
1896b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int page_length = sat_->page_length();
1897b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int strict = sat_->strict();
1898b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool result = true;
1899b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1900b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Read our data back out of the file, into it's new location.
1901b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  lseek64(fd, 0, SEEK_SET);
1902b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int i = 0; i < sat_->disk_pages(); i++) {
1903b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    struct page_entry dst;
1904b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!GetEmptyPage(&dst))
1905b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
1906b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Retrieve expected pattern.
1907b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    dst.pattern = page_recs_[i].pattern;
1908b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Update page recordpage record.
1909b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    page_recs_[i].dst = dst.addr;
1910b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1911b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Read from the file into destination page.
1912b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!ReadPageFromFile(fd, &dst)) {
1913b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        PutEmptyPage(&dst);
1914b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        return false;
1915b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1916b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1917b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    SectorValidatePage(page_recs_[i], &dst, i);
1918b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1919b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Ensure that the transfer ended up with correct data.
1920b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (strict) {
1921b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Record page index currently CRC checked.
1922b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      crc_page_ = i;
1923b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      int errors = CrcCheckPage(&dst);
1924b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (errors) {
1925b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        logprintf(5, "Log: file miscompare at block %d, "
1926b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  "offset %x-%x. File: %s\n",
1927b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  i, i * page_length, ((i + 1) * page_length) - 1,
1928b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  filename_.c_str());
1929b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        result = false;
1930b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
1931b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      crc_page_ = -1;
1932b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      errorcount_ += errors;
1933b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
1934b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!PutValidPage(&dst))
1935b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
1936b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1937b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return result;
1938b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1939b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1940b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// File IO work loop. Execute until marked done.
1941b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool FileThread::Work() {
1942b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool result = true;
1943b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 loops = 0;
1944b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1945b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting file thread %d, file %s, device %s\n",
1946b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_,
1947b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            filename_.c_str(),
1948b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            devicename_.c_str());
1949b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1950b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!PagePrepare()) {
1951b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
1952b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
1953b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1954b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1955b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Open the data IO file.
1956b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int fd = 0;
1957b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!OpenFile(&fd)) {
1958b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
1959b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
1960b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1961b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1962b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pass_ = 0;
1963b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1964b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Load patterns into page records.
1965b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  page_recs_ = new struct PageRec[sat_->disk_pages()];
1966b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (int i = 0; i < sat_->disk_pages(); i++) {
1967b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    page_recs_[i].pattern = new struct Pattern();
1968b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1969b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1970b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Loop until done.
1971b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (IsReadyToRun()) {
1972b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Do the file write.
1973b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!(result = result && WritePages(fd)))
1974b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
1975b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1976b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Do the file read.
1977b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!(result = result && ReadPages(fd)))
1978b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
1979b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1980b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    loops++;
1981b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    pass_ = loops;
1982b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
1983b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1984b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_copied_ = loops * sat_->disk_pages();
1985b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1986b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Clean up.
1987b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  CloseFile(fd);
1988b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  PageTeardown();
1989b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1990b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Completed %d: file thread status %d, %d pages copied\n",
1991b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, status_, pages_copied_);
1992b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Failure to read from device indicates hardware,
1993b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // rather than procedural SW error.
1994b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = true;
1995b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
1996b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
1997b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
1998b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkThread::IsNetworkStopSet() {
1999b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return !IsReadyToRunNoPause();
2000b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2001b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2002b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkSlaveThread::IsNetworkStopSet() {
2003b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // This thread has no completion status.
2004b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // It finishes whever there is no more data to be
2005b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // passed back.
2006b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2007b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2008b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2009b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Set ip name to use for Network IO.
2010b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid NetworkThread::SetIP(const char *ipaddr_init) {
2011b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  strncpy(ipaddr_, ipaddr_init, 256);
2012b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2013b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2014b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Create a socket.
2015b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return 0 on error.
2016b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkThread::CreateSocket(int *psocket) {
2017b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int sock = socket(AF_INET, SOCK_STREAM, 0);
2018b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (sock == -1) {
2019b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Cannot open socket\n");
2020b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    pages_copied_ = 0;
2021b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
2022b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2023b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2024b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  *psocket = sock;
2025b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2026b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2027b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2028b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Close the socket.
2029b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkThread::CloseSocket(int sock) {
2030b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  close(sock);
2031b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2032b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2033b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2034b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Initiate the tcp connection.
2035b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkThread::Connect(int sock) {
2036b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct sockaddr_in dest_addr;
2037b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  dest_addr.sin_family = AF_INET;
2038b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  dest_addr.sin_port = htons(kNetworkPort);
2039b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  memset(&(dest_addr.sin_zero), '\0', sizeof(dest_addr.sin_zero));
2040b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2041b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Translate dot notation to u32.
2042b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (inet_aton(ipaddr_, &dest_addr.sin_addr) == 0) {
2043b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Cannot resolve %s\n", ipaddr_);
2044b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    pages_copied_ = 0;
2045b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
2046b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2047b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2048b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2049b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (-1 == connect(sock, reinterpret_cast<struct sockaddr *>(&dest_addr),
2050b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                    sizeof(struct sockaddr))) {
2051b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Cannot connect %s\n", ipaddr_);
2052b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    pages_copied_ = 0;
2053b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
2054b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2055b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2056b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2057b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2058b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2059b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Initiate the tcp connection.
2060b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkListenThread::Listen() {
2061b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct sockaddr_in sa;
2062b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2063b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  memset(&(sa.sin_zero), '\0', sizeof(sa.sin_zero));
2064b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2065b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sa.sin_family = AF_INET;
2066b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sa.sin_addr.s_addr = INADDR_ANY;
2067b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sa.sin_port = htons(kNetworkPort);
2068b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2069b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (-1 == bind(sock_, (struct sockaddr*)&sa, sizeof(struct sockaddr))) {
2070b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    char buf[256];
2071b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    sat_strerror(errno, buf, sizeof(buf));
2072b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Cannot bind socket: %s\n", buf);
2073b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    pages_copied_ = 0;
2074b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
2075b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2076b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2077b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  listen(sock_, 3);
2078b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2079b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2080b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2081b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Wait for a connection from a network traffic generation thread.
2082b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkListenThread::Wait() {
2083b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    fd_set rfds;
2084b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    struct timeval tv;
2085b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int retval;
2086b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2087b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Watch sock_ to see when it has input.
2088b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    FD_ZERO(&rfds);
2089b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    FD_SET(sock_, &rfds);
2090b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Wait up to five seconds.
2091b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    tv.tv_sec = 5;
2092b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    tv.tv_usec = 0;
2093b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2094b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    retval = select(sock_ + 1, &rfds, NULL, NULL, &tv);
2095b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2096b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return (retval > 0);
2097b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2098b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2099b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Wait for a connection from a network traffic generation thread.
2100b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkListenThread::GetConnection(int *pnewsock) {
2101b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct sockaddr_in sa;
2102b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  socklen_t size = sizeof(struct sockaddr_in);
2103b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2104b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int newsock = accept(sock_, reinterpret_cast<struct sockaddr *>(&sa), &size);
2105b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (newsock < 0)  {
2106b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Did not receive connection\n");
2107b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    pages_copied_ = 0;
2108b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
2109b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2110b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2111b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  *pnewsock = newsock;
2112b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2113b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2114b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2115b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Send a page, return false if a page was not sent.
2116b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkThread::SendPage(int sock, struct page_entry *src) {
2117b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int page_length = sat_->page_length();
2118b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  char *address = static_cast<char*>(src->addr);
2119b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2120b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Send our data over the network.
2121b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int size = page_length;
2122b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (size) {
2123b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int transferred = send(sock, address + (page_length - size), size, 0);
2124b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if ((transferred == 0) || (transferred == -1)) {
2125b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (!IsNetworkStopSet()) {
2126b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        char buf[256] = "";
2127b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        sat_strerror(errno, buf, sizeof(buf));
2128b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        logprintf(0, "Process Error: Thread %d, "
2129b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                     "Network write failed, bailing. (%s)\n",
2130b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  thread_num_, buf);
2131b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        status_ = false;
2132b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
2133b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
2134b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2135b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    size = size - transferred;
2136b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2137b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2138b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2139b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2140b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Receive a page. Return false if a page was not received.
2141b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkThread::ReceivePage(int sock, struct page_entry *dst) {
2142b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int page_length = sat_->page_length();
2143b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  char *address = static_cast<char*>(dst->addr);
2144b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2145b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Maybe we will get our data back again, maybe not.
2146b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int size = page_length;
2147b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (size) {
2148b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int transferred = recv(sock, address + (page_length - size), size, 0);
2149b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if ((transferred == 0) || (transferred == -1)) {
2150b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Typically network slave thread should exit as network master
2151b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // thread stops sending data.
2152b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (IsNetworkStopSet()) {
2153b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        int err = errno;
2154b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        if (transferred == 0 && err == 0) {
2155b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // Two system setups will not sync exactly,
2156b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // allow early exit, but log it.
2157b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          logprintf(0, "Log: Net thread did not receive any data, exiting.\n");
2158b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        } else {
2159b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          char buf[256] = "";
2160b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          sat_strerror(err, buf, sizeof(buf));
2161b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // Print why we failed.
2162b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          logprintf(0, "Process Error: Thread %d, "
2163b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                       "Network read failed, bailing (%s).\n",
2164b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                    thread_num_, buf);
2165b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          status_ = false;
2166b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          // Print arguments and results.
2167b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          logprintf(0, "Log: recv(%d, address %x, size %x, 0) == %x, err %d\n",
2168b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                    sock, address + (page_length - size),
2169b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                    size, transferred, err);
2170b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          if ((transferred == 0) &&
2171b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              (page_length - size < 512) &&
2172b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              (page_length - size > 0)) {
2173b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            // Print null terminated data received, to see who's been
2174b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            // sending us supicious unwanted data.
2175b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            address[page_length - size] = 0;
2176b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            logprintf(0, "Log: received  %d bytes: '%s'\n",
2177b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                      page_length - size, address);
2178b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          }
2179b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        }
2180b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
2181b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
2182b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2183b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    size = size - transferred;
2184b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2185b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2186b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2187b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2188b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Network IO work loop. Execute until marked done.
2189b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return true if the thread ran as expected.
2190b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkThread::Work() {
2191b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting network thread %d, ip %s\n",
2192b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_,
2193b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            ipaddr_);
2194b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2195b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Make a socket.
2196b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int sock = 0;
2197b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!CreateSocket(&sock))
2198b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2199b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2200b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Network IO loop requires network slave thread to have already initialized.
2201b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // We will sleep here for awhile to ensure that the slave thread will be
2202b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // listening by the time we connect.
2203b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Sleep for 15 seconds.
2204b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_sleep(15);
2205b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting execution of network thread %d, ip %s\n",
2206b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_,
2207b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            ipaddr_);
2208b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2209b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2210b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Connect to a slave thread.
2211b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!Connect(sock))
2212b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2213b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2214b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Loop until done.
2215b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool result = true;
2216b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int strict = sat_->strict();
2217b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 loops = 0;
2218b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (IsReadyToRun()) {
2219b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    struct page_entry src;
2220b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    struct page_entry dst;
2221b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->GetValid(&src);
2222b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->GetEmpty(&dst);
2223b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
2224b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: net_thread failed to pop pages, "
2225b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "bailing\n");
2226b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
2227b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2228b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2229b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Check data correctness.
2230b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (strict)
2231b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      CrcCheckPage(&src);
2232b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2233b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Do the network write.
2234b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!(result = result && SendPage(sock, &src)))
2235b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
2236b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2237b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Update pattern reference to reflect new contents.
2238b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    dst.pattern = src.pattern;
2239b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2240b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Do the network read.
2241b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!(result = result && ReceivePage(sock, &dst)))
2242b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
2243b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2244b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Ensure that the transfer ended up with correct data.
2245b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (strict)
2246b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      CrcCheckPage(&dst);
2247b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2248b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Return all of our pages to the queue.
2249b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->PutValid(&dst);
2250b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->PutEmpty(&src);
2251b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
2252b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: net_thread failed to push pages, "
2253b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "bailing\n");
2254b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
2255b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2256b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    loops++;
2257b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2258b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2259b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_copied_ = loops;
2260b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = result;
2261b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2262b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Clean up.
2263b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  CloseSocket(sock);
2264b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2265b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Completed %d: network thread status %d, "
2266b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson               "%d pages copied\n",
2267b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, status_, pages_copied_);
2268b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return result;
2269b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2270b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2271b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Spawn slave threads for incoming connections.
2272b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkListenThread::SpawnSlave(int newsock, int threadid) {
2273b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(12, "Log: Listen thread spawning slave\n");
2274b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2275b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Spawn slave thread, to reflect network traffic back to sender.
2276b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  ChildWorker *child_worker = new ChildWorker;
2277b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  child_worker->thread.SetSock(newsock);
2278b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  child_worker->thread.InitThread(threadid, sat_, os_, patternlist_,
2279b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                  &child_worker->status);
2280b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  child_worker->status.Initialize();
2281b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  child_worker->thread.SpawnThread();
2282b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  child_workers_.push_back(child_worker);
2283b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2284b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2285b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2286b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2287b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Reap slave threads.
2288b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkListenThread::ReapSlaves() {
2289b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool result = true;
2290b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Gather status and reap threads.
2291b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(12, "Log: Joining all outstanding threads\n");
2292b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2293b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (size_t i = 0; i < child_workers_.size(); i++) {
2294b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    NetworkSlaveThread& child_thread = child_workers_[i]->thread;
2295b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(12, "Log: Joining slave thread %d\n", i);
2296b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    child_thread.JoinThread();
2297b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (child_thread.GetStatus() != 1) {
2298b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: Slave Thread %d failed with status %d\n", i,
2299b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                child_thread.GetStatus());
2300b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      result = false;
2301b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2302b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    errorcount_ += child_thread.GetErrorCount();
2303b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(9, "Log: Slave Thread %d found %lld miscompares\n", i,
2304b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              child_thread.GetErrorCount());
2305b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    pages_copied_ += child_thread.GetPageCount();
2306b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2307b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2308b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return result;
2309b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2310b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2311b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Network listener IO work loop. Execute until marked done.
2312b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return false on fatal software error.
2313b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkListenThread::Work() {
2314b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting network listen thread %d\n",
2315b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_);
2316b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2317b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Make a socket.
2318b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sock_ = 0;
2319b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!CreateSocket(&sock_)) {
2320b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
2321b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2322b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2323b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Listen thread created sock\n");
2324b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2325b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Allows incoming connections to be queued up by socket library.
2326b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int newsock = 0;
2327b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  Listen();
2328b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(12, "Log: Listen thread waiting for incoming connections\n");
2329b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2330b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Wait on incoming connections, and spawn worker threads for them.
2331b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int threadcount = 0;
2332b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (IsReadyToRun()) {
2333b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Poll for connections that we can accept().
2334b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (Wait()) {
2335b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Accept those connections.
2336b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(12, "Log: Listen thread found incoming connection\n");
2337b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (GetConnection(&newsock)) {
2338b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        SpawnSlave(newsock, threadcount);
2339b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        threadcount++;
2340b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
2341b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2342b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2343b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2344b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Gather status and join spawned threads.
2345b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  ReapSlaves();
2346b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2347b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Delete the child workers.
2348b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  for (ChildVector::iterator it = child_workers_.begin();
2349b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson       it != child_workers_.end(); ++it) {
2350b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    (*it)->status.Destroy();
2351b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    delete *it;
2352b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2353b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  child_workers_.clear();
2354b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2355b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  CloseSocket(sock_);
2356b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2357b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = true;
2358b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9,
2359b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            "Log: Completed %d: network listen thread status %d, "
2360b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            "%d pages copied\n",
2361b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, status_, pages_copied_);
2362b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2363b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2364b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2365b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Set network reflector socket struct.
2366b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid NetworkSlaveThread::SetSock(int sock) {
2367b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sock_ = sock;
2368b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2369b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2370b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Network reflector IO work loop. Execute until marked done.
2371b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return false on fatal software error.
2372b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool NetworkSlaveThread::Work() {
2373b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting network slave thread %d\n",
2374b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_);
2375b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2376b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Verify that we have a socket.
2377b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int sock = sock_;
2378b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!sock) {
2379b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
2380b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2381b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2382b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2383b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Loop until done.
2384b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 loops = 0;
2385b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Init a local buffer for storing data.
2386b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  void *local_page = NULL;
23878f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_POSIX_MEMALIGN
2388b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int result = posix_memalign(&local_page, 512, sat_->page_length());
23898f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#else
23908f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson  local_page = memalign(512, sat_->page_length());
23918f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson  int result = (local_page == 0);
23928f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
2393b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (result) {
2394b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: net slave posix_memalign "
2395b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                 "returned %d (fail)\n",
2396b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              result);
2397b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
2398b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2399b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2400b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2401b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct page_entry page;
2402b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  page.addr = local_page;
2403b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2404b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // This thread will continue to run as long as the thread on the other end of
2405b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // the socket is still sending and receiving data.
2406b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (1) {
2407b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Do the network read.
2408b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!ReceivePage(sock, &page))
2409b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
2410b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2411b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Do the network write.
2412b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!SendPage(sock, &page))
2413b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
2414b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2415b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    loops++;
2416b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2417b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2418b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_copied_ = loops;
2419b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // No results provided from this type of thread.
2420b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = true;
2421b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2422b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Clean up.
2423b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  CloseSocket(sock);
2424b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2425b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9,
2426b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            "Log: Completed %d: network slave thread status %d, "
2427b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            "%d pages copied\n",
2428b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, status_, pages_copied_);
2429b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2430b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2431b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2432b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Thread work loop. Execute until marked finished.
2433b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool ErrorPollThread::Work() {
2434b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting system error poll thread %d\n", thread_num_);
2435b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2436b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // This calls a generic error polling function in the Os abstraction layer.
2437b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  do {
2438b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    errorcount_ += os_->ErrorPoll();
2439b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    os_->ErrorWait();
2440b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } while (IsReadyToRun());
2441b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2442b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Finished system error poll thread %d: %d errors\n",
2443b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, errorcount_);
2444b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = true;
2445b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2446b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2447b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2448b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Worker thread to heat up CPU.
2449b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// This thread does not evaluate pass/fail or software error.
2450b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool CpuStressThread::Work() {
2451b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting CPU stress thread %d\n", thread_num_);
2452b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2453b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  do {
2454b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Run ludloff's platform/CPU-specific assembly workload.
2455b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    os_->CpuStressWorkload();
2456b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    YieldSelf();
2457b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } while (IsReadyToRun());
2458b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2459b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Finished CPU stress thread %d:\n",
2460b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_);
2461b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = true;
2462b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2463b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2464b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2465b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonCpuCacheCoherencyThread::CpuCacheCoherencyThread(cc_cacheline_data *data,
2466b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                                 int cacheline_count,
2467b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                                 int thread_num,
2468b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                                 int inc_count) {
2469b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  cc_cacheline_data_ = data;
2470b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  cc_cacheline_count_ = cacheline_count;
2471b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  cc_thread_num_ = thread_num;
2472b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  cc_inc_count_ = inc_count;
2473b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2474b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2475b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Worked thread to test the cache coherency of the CPUs
2476b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return false on fatal sw error.
2477b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool CpuCacheCoherencyThread::Work() {
2478b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting the Cache Coherency thread %d\n",
2479b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            cc_thread_num_);
2480b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 time_start, time_end;
2481b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct timeval tv;
2482b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2483b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  unsigned int seed = static_cast<unsigned int>(gettid());
2484b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  gettimeofday(&tv, NULL);  // Get the timestamp before increments.
2485b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  time_start = tv.tv_sec * 1000000ULL + tv.tv_usec;
2486b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2487b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 total_inc = 0;  // Total increments done by the thread.
2488b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (IsReadyToRun()) {
2489b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int i = 0; i < cc_inc_count_; i++) {
2490b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Choose a datastructure in random and increment the appropriate
2491b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // member in that according to the offset (which is the same as the
2492b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // thread number.
24938f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_RAND_R
2494b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      int r = rand_r(&seed);
24958f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#else
24968f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson      int r = rand();
24978f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
2498b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      r = cc_cacheline_count_ * (r / (RAND_MAX + 1.0));
2499b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Increment the member of the randomely selected structure.
2500b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      (cc_cacheline_data_[r].num[cc_thread_num_])++;
2501b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2502b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2503b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    total_inc += cc_inc_count_;
2504b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2505b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Calculate if the local counter matches with the global value
2506b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // in all the cache line structures for this particular thread.
2507b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int cc_global_num = 0;
2508b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int cline_num = 0; cline_num < cc_cacheline_count_; cline_num++) {
2509b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      cc_global_num += cc_cacheline_data_[cline_num].num[cc_thread_num_];
2510b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Reset the cachline member's value for the next run.
2511b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      cc_cacheline_data_[cline_num].num[cc_thread_num_] = 0;
2512b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2513b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (sat_->error_injection())
2514b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      cc_global_num = -1;
2515b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2516b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (cc_global_num != cc_inc_count_) {
2517b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      errorcount_++;
2518b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Hardware Error: global(%d) and local(%d) do not match\n",
2519b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                cc_global_num, cc_inc_count_);
2520b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2521b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2522b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  gettimeofday(&tv, NULL);  // Get the timestamp at the end.
2523b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  time_end = tv.tv_sec * 1000000ULL + tv.tv_usec;
2524b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2525b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 us_elapsed = time_end - time_start;
2526b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // inc_rate is the no. of increments per second.
2527b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  double inc_rate = total_inc * 1e6 / us_elapsed;
2528b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2529b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(4, "Stats: CC Thread(%d): Time=%llu us,"
2530b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            " Increments=%llu, Increments/sec = %.6lf\n",
2531b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            cc_thread_num_, us_elapsed, total_inc, inc_rate);
2532b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Finished CPU Cache Coherency thread %d:\n",
2533b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            cc_thread_num_);
2534b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = true;
2535b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2536b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2537b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2538b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonDiskThread::DiskThread(DiskBlockTable *block_table) {
2539b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  read_block_size_ = kSectorSize;   // default 1 sector (512 bytes)
2540b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  write_block_size_ = kSectorSize;  // this assumes read and write block size
2541b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                    // are the same
2542b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  segment_size_ = -1;               // use the entire disk as one segment
2543b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  cache_size_ = 16 * 1024 * 1024;   // assume 16MiB cache by default
2544b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Use a queue such that 3/2 times as much data as the cache can hold
2545b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // is written before it is read so that there is little chance the read
2546b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // data is in the cache.
2547b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  queue_size_ = ((cache_size_ / write_block_size_) * 3) / 2;
2548b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  blocks_per_segment_ = 32;
2549b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2550b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  read_threshold_ = 100000;         // 100ms is a reasonable limit for
2551b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  write_threshold_ = 100000;        // reading/writing a sector
2552b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2553b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  read_timeout_ = 5000000;          // 5 seconds should be long enough for a
2554b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  write_timeout_ = 5000000;         // timout for reading/writing
2555b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2556b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  device_sectors_ = 0;
2557b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  non_destructive_ = 0;
2558b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
25598f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_LIBAIO_H
2560b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  aio_ctx_ = 0;
25618f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
2562b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  block_table_ = block_table;
2563b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  update_block_table_ = 1;
2564b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2565b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  block_buffer_ = NULL;
2566b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2567b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  blocks_written_ = 0;
2568b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  blocks_read_ = 0;
2569b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2570b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2571b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonDiskThread::~DiskThread() {
2572b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (block_buffer_)
2573b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    free(block_buffer_);
2574b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2575b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2576b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Set filename for device file (in /dev).
2577b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid DiskThread::SetDevice(const char *device_name) {
2578b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  device_name_ = device_name;
2579b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2580b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2581b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Set various parameters that control the behaviour of the test.
2582b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// -1 is used as a sentinel value on each parameter (except non_destructive)
2583b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// to indicate that the parameter not be set.
2584b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool DiskThread::SetParameters(int read_block_size,
2585b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                               int write_block_size,
2586b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                               int64 segment_size,
2587b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                               int64 cache_size,
2588b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                               int blocks_per_segment,
2589b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                               int64 read_threshold,
2590b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                               int64 write_threshold,
2591b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                               int non_destructive) {
2592b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (read_block_size != -1) {
2593b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Blocks must be aligned to the disk's sector size.
2594b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (read_block_size % kSectorSize != 0) {
2595b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: Block size must be a multiple of %d "
2596b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "(thread %d).\n", kSectorSize, thread_num_);
2597b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
2598b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2599b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2600b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    read_block_size_ = read_block_size;
2601b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2602b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2603b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (write_block_size != -1) {
2604b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Write blocks must be aligned to the disk's sector size and to the
2605b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // block size.
2606b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (write_block_size % kSectorSize != 0) {
2607b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: Write block size must be a multiple "
2608b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "of %d (thread %d).\n", kSectorSize, thread_num_);
2609b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
2610b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2611b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (write_block_size % read_block_size_ != 0) {
2612b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: Write block size must be a multiple "
2613b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "of the read block size, which is %d (thread %d).\n",
2614b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                read_block_size_, thread_num_);
2615b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
2616b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2617b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2618b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    write_block_size_ = write_block_size;
2619b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2620b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else {
2621b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Make sure write_block_size_ is still valid.
2622b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (read_block_size_ > write_block_size_) {
2623b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(5, "Log: Assuming write block size equal to read block size, "
2624b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "which is %d (thread %d).\n", read_block_size_,
2625b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                thread_num_);
2626b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      write_block_size_ = read_block_size_;
2627b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else {
2628b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (write_block_size_ % read_block_size_ != 0) {
2629b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        logprintf(0, "Process Error: Write block size (defined as %d) must "
2630b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  "be a multiple of the read block size, which is %d "
2631b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  "(thread %d).\n", write_block_size_, read_block_size_,
2632b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  thread_num_);
2633b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        return false;
2634b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
2635b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2636b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2637b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2638b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (cache_size != -1) {
2639b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    cache_size_ = cache_size;
2640b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2641b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2642b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (blocks_per_segment != -1) {
2643b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (blocks_per_segment <= 0) {
2644b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: Blocks per segment must be greater than "
2645b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                   "zero.\n (thread %d)", thread_num_);
2646b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
2647b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2648b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2649b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    blocks_per_segment_ = blocks_per_segment;
2650b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2651b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2652b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (read_threshold != -1) {
2653b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (read_threshold <= 0) {
2654b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: Read threshold must be greater than "
2655b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                   "zero (thread %d).\n", thread_num_);
2656b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
2657b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2658b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2659b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    read_threshold_ = read_threshold;
2660b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2661b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2662b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (write_threshold != -1) {
2663b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (write_threshold <= 0) {
2664b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: Write threshold must be greater than "
2665b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                   "zero (thread %d).\n", thread_num_);
2666b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
2667b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2668b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2669b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    write_threshold_ = write_threshold;
2670b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2671b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2672b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (segment_size != -1) {
2673b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Segments must be aligned to the disk's sector size.
2674b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (segment_size % kSectorSize != 0) {
2675b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: Segment size must be a multiple of %d"
2676b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                " (thread %d).\n", kSectorSize, thread_num_);
2677b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
2678b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2679b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2680b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    segment_size_ = segment_size / kSectorSize;
2681b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2682b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2683b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  non_destructive_ = non_destructive;
2684b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2685b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Having a queue of 150% of blocks that will fit in the disk's cache
2686b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // should be enough to force out the oldest block before it is read and hence,
2687b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // making sure the data comes form the disk and not the cache.
2688b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  queue_size_ = ((cache_size_ / write_block_size_) * 3) / 2;
2689b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Updating DiskBlockTable parameters
2690b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (update_block_table_) {
2691b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    block_table_->SetParameters(kSectorSize, write_block_size_,
2692b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                device_sectors_, segment_size_,
2693b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                device_name_);
2694b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2695b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2696b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2697b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2698b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Open a device, return false on failure.
2699b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool DiskThread::OpenDevice(int *pfile) {
2700613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  bool no_O_DIRECT = false;
2701613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  int flags = O_RDWR | O_SYNC | O_LARGEFILE;
2702613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  int fd = open(device_name_.c_str(), flags | O_DIRECT, 0);
2703613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  if (O_DIRECT != 0 && fd < 0 && errno == EINVAL) {
2704613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson    no_O_DIRECT = true;
2705613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson    fd = open(device_name_.c_str(), flags, 0); // Try without O_DIRECT
2706613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  }
2707b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (fd < 0) {
2708b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Failed to open device %s (thread %d)!!\n",
2709b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              device_name_.c_str(), thread_num_);
2710b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2711b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2712613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson  if (no_O_DIRECT)
2713613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson    os_->ActivateFlushPageCache();
2714b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  *pfile = fd;
2715b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2716b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return GetDiskSize(fd);
2717b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2718b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2719b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Retrieves the size (in bytes) of the disk/file.
2720b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return false on failure.
2721b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool DiskThread::GetDiskSize(int fd) {
2722b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct stat device_stat;
2723b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (fstat(fd, &device_stat) == -1) {
2724b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Unable to fstat disk %s (thread %d).\n",
2725b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              device_name_.c_str(), thread_num_);
2726b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2727b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2728b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2729b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // For a block device, an ioctl is needed to get the size since the size
2730b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // of the device file (i.e. /dev/sdb) is 0.
2731b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (S_ISBLK(device_stat.st_mode)) {
2732b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    uint64 block_size = 0;
2733b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2734b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (ioctl(fd, BLKGETSIZE64, &block_size) == -1) {
2735b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: Unable to ioctl disk %s (thread %d).\n",
2736b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                device_name_.c_str(), thread_num_);
2737b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
2738b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2739b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2740b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Zero size indicates nonworking device..
2741b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (block_size == 0) {
2742b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      os_->ErrorReport(device_name_.c_str(), "device-size-zero", 1);
2743b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      ++errorcount_;
2744b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      status_ = true;  // Avoid a procedural error.
2745b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
2746b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2747b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2748b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    device_sectors_ = block_size / kSectorSize;
2749b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2750b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else if (S_ISREG(device_stat.st_mode)) {
2751b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    device_sectors_ = device_stat.st_size / kSectorSize;
2752b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2753b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else {
2754b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: %s is not a regular file or block "
2755b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "device (thread %d).\n", device_name_.c_str(),
2756b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              thread_num_);
2757b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2758b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2759b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2760b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(12, "Log: Device sectors: %lld on disk %s (thread %d).\n",
2761b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            device_sectors_, device_name_.c_str(), thread_num_);
2762b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2763b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (update_block_table_) {
2764b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    block_table_->SetParameters(kSectorSize, write_block_size_,
2765b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                device_sectors_, segment_size_,
2766b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                device_name_);
2767b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2768b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2769b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2770b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2771b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2772b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool DiskThread::CloseDevice(int fd) {
2773b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  close(fd);
2774b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2775b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2776b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2777b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return the time in microseconds.
2778b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonint64 DiskThread::GetTime() {
2779b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct timeval tv;
2780b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  gettimeofday(&tv, NULL);
2781b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return tv.tv_sec * 1000000 + tv.tv_usec;
2782b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2783b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2784b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Do randomized reads and (possibly) writes on a device.
2785b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return false on fatal SW error, true on SW success,
2786b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// regardless of whether HW failed.
2787b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool DiskThread::DoWork(int fd) {
2788b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 block_num = 0;
2789b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 num_segments;
2790b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2791b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (segment_size_ == -1) {
2792b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    num_segments = 1;
2793b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else {
2794b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    num_segments = device_sectors_ / segment_size_;
2795b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (device_sectors_ % segment_size_ != 0)
2796b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      num_segments++;
2797b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2798b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2799b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Disk size should be at least 3x cache size.  See comment later for
2800b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // details.
2801b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  sat_assert(device_sectors_ * kSectorSize > 3 * cache_size_);
2802b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2803b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // This disk test works by writing blocks with a certain pattern to
2804b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // disk, then reading them back and verifying it against the pattern
2805b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // at a later time.  A failure happens when either the block cannot
2806b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // be written/read or when the read block is different than what was
2807b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // written.  If a block takes too long to write/read, then a warning
2808b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // is given instead of an error since taking too long is not
2809b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // necessarily an error.
2810b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  //
2811b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // To prevent the read blocks from coming from the disk cache,
2812b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // enough blocks are written before read such that a block would
2813b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // be ejected from the disk cache by the time it is read.
2814b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  //
2815b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // TODO(amistry): Implement some sort of read/write throttling.  The
2816b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  //                flood of asynchronous I/O requests when a drive is
2817b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  //                unplugged is causing the application and kernel to
2818b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  //                become unresponsive.
2819b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2820b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (IsReadyToRun()) {
2821b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Write blocks to disk.
2822b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(16, "Log: Write phase %sfor disk %s (thread %d).\n",
2823b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              non_destructive_ ? "(disabled) " : "",
2824b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              device_name_.c_str(), thread_num_);
2825b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    while (IsReadyToRunNoPause() &&
2826b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson           in_flight_sectors_.size() <
2827b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson               static_cast<size_t>(queue_size_ + 1)) {
2828b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Confine testing to a particular segment of the disk.
2829b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      int64 segment = (block_num / blocks_per_segment_) % num_segments;
2830b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (!non_destructive_ &&
2831b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          (block_num % blocks_per_segment_ == 0)) {
2832b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        logprintf(20, "Log: Starting to write segment %lld out of "
2833b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  "%lld on disk %s (thread %d).\n",
2834b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  segment, num_segments, device_name_.c_str(),
2835b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  thread_num_);
2836b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
2837b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      block_num++;
2838b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2839b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      BlockData *block = block_table_->GetUnusedBlock(segment);
2840b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2841b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // If an unused sequence of sectors could not be found, skip to the
2842b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // next block to process.  Soon, a new segment will come and new
2843b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // sectors will be able to be allocated.  This effectively puts a
2844b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // minumim on the disk size at 3x the stated cache size, or 48MiB
2845b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // if a cache size is not given (since the cache is set as 16MiB
2846b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // by default).  Given that todays caches are at the low MiB range
2847b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // and drive sizes at the mid GB, this shouldn't pose a problem.
2848b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // The 3x minimum comes from the following:
2849b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      //   1. In order to allocate 'y' blocks from a segment, the
2850b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      //      segment must contain at least 2y blocks or else an
2851b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      //      allocation may not succeed.
2852b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      //   2. Assume the entire disk is one segment.
2853b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      //   3. A full write phase consists of writing blocks corresponding to
2854b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      //      3/2 cache size.
2855b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      //   4. Therefore, the one segment must have 2 * 3/2 * cache
2856b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      //      size worth of blocks = 3 * cache size worth of blocks
2857b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      //      to complete.
2858b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // In non-destructive mode, don't write anything to disk.
2859b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (!non_destructive_) {
2860b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        if (!WriteBlockToDisk(fd, block)) {
2861b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          block_table_->RemoveBlock(block);
2862b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          return true;
2863b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        }
2864b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        blocks_written_++;
2865b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
2866b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2867b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // Block is either initialized by writing, or in nondestructive case,
2868b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      // initialized by being added into the datastructure for later reading.
2869b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      block->SetBlockAsInitialized();
2870b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2871b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      in_flight_sectors_.push(block);
2872b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2873613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson    if (!os_->FlushPageCache()) // If O_DIRECT worked, this will be a NOP.
2874613ee1f783d25f83aeb9b5ad25c3ceb3da49b163Scott Anderson      return false;
2875b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2876b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Verify blocks on disk.
2877b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(20, "Log: Read phase for disk %s (thread %d).\n",
2878b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              device_name_.c_str(), thread_num_);
2879b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    while (IsReadyToRunNoPause() && !in_flight_sectors_.empty()) {
2880b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      BlockData *block = in_flight_sectors_.front();
2881b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      in_flight_sectors_.pop();
2882b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (!ValidateBlockOnDisk(fd, block))
2883b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        return true;
2884b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      block_table_->RemoveBlock(block);
2885b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      blocks_read_++;
2886b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2887b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2888b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2889b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_copied_ = blocks_written_ + blocks_read_;
2890b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
2891b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
2892b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2893b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Do an asynchronous disk I/O operation.
2894b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return false if the IO is not set up.
2895b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool DiskThread::AsyncDiskIO(IoOp op, int fd, void *buf, int64 size,
2896b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                            int64 offset, int64 timeout) {
28978f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_LIBAIO_H
2898b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Use the Linux native asynchronous I/O interface for reading/writing.
2899b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // A read/write consists of three basic steps:
2900b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  //    1. create an io context.
2901b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  //    2. prepare and submit an io request to the context
2902b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  //    3. wait for an event on the context.
2903b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2904b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct {
2905b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    const int opcode;
2906b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    const char *op_str;
2907b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    const char *error_str;
2908b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } operations[2] = {
2909b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    { IO_CMD_PREAD, "read", "disk-read-error" },
2910b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    { IO_CMD_PWRITE, "write", "disk-write-error" }
2911b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  };
2912b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2913b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct iocb cb;
2914b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  memset(&cb, 0, sizeof(cb));
2915b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2916b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  cb.aio_fildes = fd;
2917b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  cb.aio_lio_opcode = operations[op].opcode;
2918b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  cb.u.c.buf = buf;
2919b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  cb.u.c.nbytes = size;
2920b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  cb.u.c.offset = offset;
2921b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2922b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct iocb *cbs[] = { &cb };
2923b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (io_submit(aio_ctx_, 1, cbs) != 1) {
2924b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int error = errno;
2925b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    char buf[256];
2926b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    sat_strerror(error, buf, sizeof(buf));
2927b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Unable to submit async %s "
2928b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                 "on disk %s (thread %d). Error %d, %s\n",
2929b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              operations[op].op_str, device_name_.c_str(),
2930b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              thread_num_, error, buf);
2931b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2932b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2933b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2934b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct io_event event;
2935b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  memset(&event, 0, sizeof(event));
2936b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct timespec tv;
2937b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  tv.tv_sec = timeout / 1000000;
2938b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  tv.tv_nsec = (timeout % 1000000) * 1000;
2939b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (io_getevents(aio_ctx_, 1, 1, &event, &tv) != 1) {
2940b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // A ctrl-c from the keyboard will cause io_getevents to fail with an
2941b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // EINTR error code.  This is not an error and so don't treat it as such,
2942b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // but still log it.
2943b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int error = errno;
2944b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (error == EINTR) {
2945b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(5, "Log: %s interrupted on disk %s (thread %d).\n",
2946b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                operations[op].op_str, device_name_.c_str(),
2947b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                thread_num_);
2948b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else {
2949b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      os_->ErrorReport(device_name_.c_str(), operations[op].error_str, 1);
2950b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      errorcount_ += 1;
2951b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Hardware Error: Timeout doing async %s to sectors "
2952b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                   "starting at %lld on disk %s (thread %d).\n",
2953b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                operations[op].op_str, offset / kSectorSize,
2954b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                device_name_.c_str(), thread_num_);
2955b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2956b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2957b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Don't bother checking return codes since io_cancel seems to always fail.
2958b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Since io_cancel is always failing, destroying and recreating an I/O
2959b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // context is a workaround for canceling an in-progress I/O operation.
2960b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // TODO(amistry): Find out why io_cancel isn't working and make it work.
2961b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    io_cancel(aio_ctx_, &cb, &event);
2962b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    io_destroy(aio_ctx_);
2963b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    aio_ctx_ = 0;
2964b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (io_setup(5, &aio_ctx_)) {
2965b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      int error = errno;
2966b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      char buf[256];
2967b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      sat_strerror(error, buf, sizeof(buf));
2968b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: Unable to create aio context on disk %s"
2969b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                " (thread %d) Error %d, %s\n",
2970b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                device_name_.c_str(), thread_num_, error, buf);
2971b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
2972b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2973b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
2974b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
2975b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2976b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // event.res contains the number of bytes written/read or
2977b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // error if < 0, I think.
2978b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (event.res != static_cast<uint64>(size)) {
2979b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    errorcount_++;
2980b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    os_->ErrorReport(device_name_.c_str(), operations[op].error_str, 1);
2981b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
2982b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (event.res < 0) {
2983b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      switch (event.res) {
2984b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        case -EIO:
2985b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          logprintf(0, "Hardware Error: Low-level I/O error while doing %s to "
2986b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                       "sectors starting at %lld on disk %s (thread %d).\n",
2987b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                    operations[op].op_str, offset / kSectorSize,
2988b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                    device_name_.c_str(), thread_num_);
2989b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          break;
2990b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        default:
2991b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson          logprintf(0, "Hardware Error: Unknown error while doing %s to "
2992b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                       "sectors starting at %lld on disk %s (thread %d).\n",
2993b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                    operations[op].op_str, offset / kSectorSize,
2994b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                    device_name_.c_str(), thread_num_);
2995b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
2996b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else {
2997b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Hardware Error: Unable to %s to sectors starting at "
2998b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                   "%lld on disk %s (thread %d).\n",
2999b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                operations[op].op_str, offset / kSectorSize,
3000b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                device_name_.c_str(), thread_num_);
3001b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3002b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
3003b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3004b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3005b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
30068f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#else // !HAVE_LIBAIO_H
30078f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson  return false;
30088f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
3009b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3010b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3011b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Write a block to disk.
3012b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return false if the block is not written.
3013b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool DiskThread::WriteBlockToDisk(int fd, BlockData *block) {
3014b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  memset(block_buffer_, 0, block->GetSize());
3015b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3016b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Fill block buffer with a pattern
3017b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct page_entry pe;
3018b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!sat_->GetValid(&pe)) {
3019b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Even though a valid page could not be obatined, it is not an error
3020b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // since we can always fill in a pattern directly, albeit slower.
3021b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    unsigned int *memblock = static_cast<unsigned int *>(block_buffer_);
3022b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    block->SetPattern(patternlist_->GetRandomPattern());
3023b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3024b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(11, "Log: Warning, using pattern fill fallback in "
3025b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  "DiskThread::WriteBlockToDisk on disk %s (thread %d).\n",
3026b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              device_name_.c_str(), thread_num_);
3027b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3028b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int i = 0; i < block->GetSize()/wordsize_; i++) {
3029b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      memblock[i] = block->GetPattern()->pattern(i);
3030b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3031b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else {
3032b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    memcpy(block_buffer_, pe.addr, block->GetSize());
3033b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    block->SetPattern(pe.pattern);
3034b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    sat_->PutValid(&pe);
3035b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3036b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3037b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(12, "Log: Writing %lld sectors starting at %lld on disk %s"
3038b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            " (thread %d).\n",
3039b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            block->GetSize()/kSectorSize, block->GetAddress(),
3040b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            device_name_.c_str(), thread_num_);
3041b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3042b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 start_time = GetTime();
3043b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3044b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!AsyncDiskIO(ASYNC_IO_WRITE, fd, block_buffer_, block->GetSize(),
3045b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                   block->GetAddress() * kSectorSize, write_timeout_)) {
3046b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
3047b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3048b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3049b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 end_time = GetTime();
3050b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(12, "Log: Writing time: %lld us (thread %d).\n",
3051b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            end_time - start_time, thread_num_);
3052b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (end_time - start_time > write_threshold_) {
3053b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(5, "Log: Write took %lld us which is longer than threshold "
3054b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                 "%lld us on disk %s (thread %d).\n",
3055b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              end_time - start_time, write_threshold_, device_name_.c_str(),
3056b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              thread_num_);
3057b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3058b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3059b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
3060b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3061b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3062b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Verify a block on disk.
3063b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return true if the block was read, also increment errorcount
3064b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// if the block had data errors or performance problems.
3065b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool DiskThread::ValidateBlockOnDisk(int fd, BlockData *block) {
3066b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 blocks = block->GetSize() / read_block_size_;
3067b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 bytes_read = 0;
3068b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 current_blocks;
3069b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 current_bytes;
3070b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint64 address = block->GetAddress();
3071b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3072b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(20, "Log: Reading sectors starting at %lld on disk %s "
3073b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            "(thread %d).\n",
3074b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            address, device_name_.c_str(), thread_num_);
3075b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3076b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Read block from disk and time the read.  If it takes longer than the
3077b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // threshold, complain.
3078b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (lseek64(fd, address * kSectorSize, SEEK_SET) == -1) {
3079b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Unable to seek to sector %lld in "
3080b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "DiskThread::ValidateSectorsOnDisk on disk %s "
3081b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "(thread %d).\n", address, device_name_.c_str(), thread_num_);
3082b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
3083b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3084b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 start_time = GetTime();
3085b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3086b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Split a large write-sized block into small read-sized blocks and
3087b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // read them in groups of randomly-sized multiples of read block size.
3088b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // This assures all data written on disk by this particular block
3089b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // will be tested using a random reading pattern.
3090b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (blocks != 0) {
3091b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Test all read blocks in a written block.
3092b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    current_blocks = (random() % blocks) + 1;
3093b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    current_bytes = current_blocks * read_block_size_;
3094b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3095b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    memset(block_buffer_, 0, current_bytes);
3096b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3097b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(20, "Log: Reading %lld sectors starting at sector %lld on "
3098b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "disk %s (thread %d)\n",
3099b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              current_bytes / kSectorSize,
3100b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              (address * kSectorSize + bytes_read) / kSectorSize,
3101b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              device_name_.c_str(), thread_num_);
3102b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3103b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!AsyncDiskIO(ASYNC_IO_READ, fd, block_buffer_, current_bytes,
3104b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                     address * kSectorSize + bytes_read,
3105b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                     write_timeout_)) {
3106b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      return false;
3107b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3108b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3109b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    int64 end_time = GetTime();
3110b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(20, "Log: Reading time: %lld us (thread %d).\n",
3111b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              end_time - start_time, thread_num_);
3112b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (end_time - start_time > read_threshold_) {
3113b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(5, "Log: Read took %lld us which is longer than threshold "
3114b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "%lld us on disk %s (thread %d).\n",
3115b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                end_time - start_time, read_threshold_,
3116b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                device_name_.c_str(), thread_num_);
3117b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3118b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3119b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // In non-destructive mode, don't compare the block to the pattern since
3120b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // the block was never written to disk in the first place.
3121b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!non_destructive_) {
3122b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (CheckRegion(block_buffer_, block->GetPattern(), current_bytes,
3123b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                      0, bytes_read)) {
3124b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        os_->ErrorReport(device_name_.c_str(), "disk-pattern-error", 1);
3125b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        errorcount_ += 1;
3126b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        logprintf(0, "Hardware Error: Pattern mismatch in block starting at "
3127b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  "sector %lld in DiskThread::ValidateSectorsOnDisk on "
3128b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  "disk %s (thread %d).\n",
3129b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                  address, device_name_.c_str(), thread_num_);
3130b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      }
3131b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3132b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3133b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    bytes_read += current_blocks * read_block_size_;
3134b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    blocks -= current_blocks;
3135b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3136b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3137b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
3138b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3139b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3140b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Direct device access thread.
3141b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return false on software error.
3142b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool DiskThread::Work() {
3143b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int fd;
3144b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3145b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting disk thread %d, disk %s\n",
3146b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, device_name_.c_str());
3147b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3148b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  srandom(time(NULL));
3149b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3150b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (!OpenDevice(&fd)) {
3151b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
3152b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
3153b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3154b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3155b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // Allocate a block buffer aligned to 512 bytes since the kernel requires it
31568f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson  // when using direct IO.
31578f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_POSIX_MEMALIGN
3158b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int memalign_result = posix_memalign(&block_buffer_, kBufferAlignment,
3159b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                              sat_->page_length());
31608f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#else
31618f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson  block_buffer_ = memalign(kBufferAlignment, sat_->page_length());
31628f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson  int memalign_result = (block_buffer_ == 0);
31638f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
3164b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (memalign_result) {
3165b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    CloseDevice(fd);
3166b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Unable to allocate memory for buffers "
3167b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                 "for disk %s (thread %d) posix memalign returned %d.\n",
3168b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              device_name_.c_str(), thread_num_, memalign_result);
3169b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
3170b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
3171b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3172b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
31738f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_LIBAIO_H
3174b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (io_setup(5, &aio_ctx_)) {
3175b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    CloseDevice(fd);
3176b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: Unable to create aio context for disk %s"
3177b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              " (thread %d).\n",
3178b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              device_name_.c_str(), thread_num_);
3179b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    status_ = false;
3180b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
3181b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
31828f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
3183b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3184b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool result = DoWork(fd);
3185b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3186b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = result;
3187b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
31888f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#ifdef HAVE_LIBAIO_H
3189b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  io_destroy(aio_ctx_);
31908f1c60d605d31447b4f9ccf86029790bed3fb3f3Scott Anderson#endif
3191b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  CloseDevice(fd);
3192b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3193b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Completed %d (disk %s): disk thread status %d, "
3194b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson               "%d pages copied\n",
3195b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            thread_num_, device_name_.c_str(), status_, pages_copied_);
3196b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return result;
3197b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3198b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3199b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonRandomDiskThread::RandomDiskThread(DiskBlockTable *block_table)
3200b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    : DiskThread(block_table) {
3201b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  update_block_table_ = 0;
3202b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3203b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3204b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonRandomDiskThread::~RandomDiskThread() {
3205b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3206b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3207b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Workload for random disk thread.
3208b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool RandomDiskThread::DoWork(int fd) {
3209b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(11, "Log: Random phase for disk %s (thread %d).\n",
3210b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            device_name_.c_str(), thread_num_);
3211b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (IsReadyToRun()) {
3212b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    BlockData *block = block_table_->GetRandomBlock();
3213b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (block == NULL) {
3214b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(12, "Log: No block available for device %s (thread %d).\n",
3215b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                device_name_.c_str(), thread_num_);
3216b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    } else {
3217b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      ValidateBlockOnDisk(fd, block);
3218b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      block_table_->ReleaseBlock(block);
3219b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      blocks_read_++;
3220b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3221b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3222b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_copied_ = blocks_read_;
3223b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return true;
3224b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3225b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3226b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonMemoryRegionThread::MemoryRegionThread() {
3227b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  error_injection_ = false;
3228b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_ = NULL;
3229b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3230b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3231b0114cb9f332db144f65291211ae65f7f0e814e6Scott AndersonMemoryRegionThread::~MemoryRegionThread() {
3232b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (pages_ != NULL)
3233b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    delete pages_;
3234b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3235b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3236b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Set a region of memory or MMIO to be tested.
3237b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return false if region could not be mapped.
3238b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool MemoryRegionThread::SetRegion(void *region, int64 size) {
3239b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int plength = sat_->page_length();
3240b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int npages = size / plength;
3241b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (size % plength) {
3242b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: region size is not a multiple of SAT "
3243b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "page length\n");
3244b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return false;
3245b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else {
3246b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (pages_ != NULL)
3247b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      delete pages_;
3248b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    pages_ = new PageEntryQueue(npages);
3249b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    char *base_addr = reinterpret_cast<char*>(region);
3250b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    region_ = base_addr;
3251b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (int i = 0; i < npages; i++) {
3252b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      struct page_entry pe;
3253b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      init_pe(&pe);
3254b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      pe.addr = reinterpret_cast<void*>(base_addr + i * plength);
3255b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      pe.offset = i * plength;
3256b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3257b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      pages_->Push(&pe);
3258b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3259b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    return true;
3260b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3261b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3262b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3263b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// More detailed error printout for hardware errors in memory or MMIO
3264b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// regions.
3265b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonvoid MemoryRegionThread::ProcessError(struct ErrorRecord *error,
3266b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                      int priority,
3267b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                                      const char *message) {
3268b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  uint32 buffer_offset;
3269b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  if (phase_ == kPhaseCopy) {
3270b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // If the error occurred on the Copy Phase, it means that
3271b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // the source data (i.e., the main memory) is wrong. so
3272b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // just pass it to the original ProcessError to call a
3273b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // bad-dimm error
3274b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    WorkerThread::ProcessError(error, priority, message);
3275b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else if (phase_ == kPhaseCheck) {
3276b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // A error on the Check Phase means that the memory region tested
3277b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // has an error. Gathering more information and then reporting
3278b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // the error.
3279b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Determine if this is a write or read error.
3280b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    os_->Flush(error->vaddr);
3281b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    error->reread = *(error->vaddr);
3282b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    char *good = reinterpret_cast<char*>(&(error->expected));
3283b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    char *bad = reinterpret_cast<char*>(&(error->actual));
3284b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    sat_assert(error->expected != error->actual);
3285b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    unsigned int offset = 0;
3286b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    for (offset = 0; offset < (sizeof(error->expected) - 1); offset++) {
3287b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      if (good[offset] != bad[offset])
3288b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        break;
3289b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3290b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3291b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    error->vbyteaddr = reinterpret_cast<char*>(error->vaddr) + offset;
3292b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3293b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    buffer_offset = error->vbyteaddr - region_;
3294b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3295b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Find physical address if possible.
3296b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    error->paddr = os_->VirtualToPhysical(error->vbyteaddr);
3297b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(priority,
3298b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "%s: miscompare on %s, CRC check at %p(0x%llx), "
3299b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "offset %llx: read:0x%016llx, reread:0x%016llx "
3300b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "expected:0x%016llx\n",
3301b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              message,
3302b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              identifier_.c_str(),
3303b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->vaddr,
3304b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->paddr,
3305b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              buffer_offset,
3306b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->actual,
3307b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->reread,
3308b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              error->expected);
3309b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  } else {
3310b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    logprintf(0, "Process Error: memory region thread raised an "
3311b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson              "unexpected error.");
3312b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3313b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3314b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3315b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Workload for testion memory or MMIO regions.
3316b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Return false on software error.
3317b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonbool MemoryRegionThread::Work() {
3318b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct page_entry source_pe;
3319b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  struct page_entry memregion_pe;
3320b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  bool result = true;
3321b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 loops = 0;
3322b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  const uint64 error_constant = 0x00ba00000000ba00LL;
3323b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3324b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  // For error injection.
3325b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 *addr = 0x0;
3326b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int offset = 0;
3327b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  int64 data = 0;
3328b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3329b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Starting Memory Region thread %d\n", thread_num_);
3330b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3331b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  while (IsReadyToRun()) {
3332b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Getting pages from SAT and queue.
3333b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    phase_ = kPhaseNoPhase;
3334b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->GetValid(&source_pe);
3335b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
3336b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: memory region thread failed to pop "
3337b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "pages from SAT, bailing\n");
3338b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
3339b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3340b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3341b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && pages_->PopRandom(&memregion_pe);
3342b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
3343b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: memory region thread failed to pop "
3344b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "pages from queue, bailing\n");
3345b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
3346b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3347b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3348b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Error injection for CRC copy.
3349b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if ((sat_->error_injection() || error_injection_) && loops == 1) {
3350b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      addr = reinterpret_cast<int64*>(source_pe.addr);
3351b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      offset = random() % (sat_->page_length() / wordsize_);
3352b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data = addr[offset];
3353b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      addr[offset] = error_constant;
3354b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3355b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3356b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Copying SAT page into memory region.
3357b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    phase_ = kPhaseCopy;
3358b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    CrcCopyPage(&memregion_pe, &source_pe);
3359b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    memregion_pe.pattern = source_pe.pattern;
3360b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3361b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Error injection for CRC Check.
3362b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if ((sat_->error_injection() || error_injection_) && loops == 2) {
3363b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      addr = reinterpret_cast<int64*>(memregion_pe.addr);
3364b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      offset = random() % (sat_->page_length() / wordsize_);
3365b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      data = addr[offset];
3366b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      addr[offset] = error_constant;
3367b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3368b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3369b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Checking page content in memory region.
3370b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    phase_ = kPhaseCheck;
3371b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    CrcCheckPage(&memregion_pe);
3372b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3373b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    phase_ = kPhaseNoPhase;
3374b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    // Storing pages on their proper queues.
3375b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && sat_->PutValid(&source_pe);
3376b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
3377b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: memory region thread failed to push "
3378b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "pages into SAT, bailing\n");
3379b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
3380b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3381b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    result = result && pages_->Push(&memregion_pe);
3382b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if (!result) {
3383b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      logprintf(0, "Process Error: memory region thread failed to push "
3384b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson                "pages into queue, bailing\n");
3385b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      break;
3386b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3387b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3388b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    if ((sat_->error_injection() || error_injection_) &&
3389b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson        loops >= 1 && loops <= 2) {
3390b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson      addr[offset] = data;
3391b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    }
3392b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3393b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    loops++;
3394b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson    YieldSelf();
3395b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  }
3396b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson
3397b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  pages_copied_ = loops;
3398b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  status_ = result;
3399b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  logprintf(9, "Log: Completed %d: Memory Region thread. Status %d, %d "
3400b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson            "pages checked\n", thread_num_, status_, pages_copied_);
3401b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson  return result;
3402b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}
3403