00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <iostream>
00039
00040 #include "common/wave_ex.h"
00041 #include "perf/perf.h"
00042 #include "threadsafe/smart_ptr.h"
00043 #include "threadsafe/threadsafe.h"
00044 #include "threadsafe/threadsafe_counter.h"
00045 #include "threadsafe/threadsafe_map.h"
00046 #include "threadsafe/threadsafe_multimap.h"
00047 #include "threadsafe/threadsafe_queue.h"
00048
00049 typedef threadsafe_multimap<std::string, std::string> multi_string_t;
00050 typedef threadsafe_queue<std::string> tqueue_string_t;
00051
00052
00053 class ATest {
00054 public:
00055 ATest(void) throw() { }
00056 virtual ~ATest(void) throw() { }
00057
00058 private:
00059 long m_l;
00060 };
00061
00062
00063 class BTest : public ATest {
00064 public:
00065 ~BTest(void) throw() { }
00066
00067 private:
00068 long m_l2;
00069 };
00070
00071
00072 typedef smart_ptr<ATest> ptr_t;
00073
00074 typedef void * (*get_context_fn)(void);
00075 typedef void (*test_routine_t)(void *);
00076 typedef void (*valid_fn)(void *);
00077
00078 struct context_t {
00079 context_t(void) throw() {
00080 ctr = NULL;
00081 fn = NULL;
00082 ctx = NULL;
00083 }
00084
00085
00086 threadsafe_counter * ctr;
00087 test_routine_t fn;
00088 void * ctx;
00089 };
00090
00091
00092
00093
00094
00095
00096
00097
00098 static float
00099 getRandom
00100 (
00101 void
00102 )
00103 throw()
00104 {
00105 return (1.0 * rand()) / RAND_MAX;
00106 }
00107
00108
00109
00110 static void *
00111 getContext1
00112 (
00113 void
00114 )
00115 {
00116 tqueue_string_t * tqs = new tqueue_string_t;
00117 ASSERT(tqs, "out of memory");
00118
00119 return tqs;
00120 }
00121
00122
00123
00124 static void *
00125 getSPtrContext
00126 (
00127 void
00128 )
00129 {
00130 ptr_t * p = new ptr_t;
00131 ASSERT(p, "out of memory");
00132 *p = new BTest;
00133 ASSERT(*p, "out of memory");
00134 ASSERT(1 == p->get_ref_count(), "Bad ref count? %ld",
00135 p->get_ref_count());
00136
00137 return (void *) p;
00138 }
00139
00140
00141
00142 static void *
00143 getMMctx
00144 (
00145 void
00146 )
00147 {
00148 multi_string_t * ps = new multi_string_t;
00149 ASSERT(ps, "out of memory");
00150 return ps;
00151 }
00152
00153
00154
00155 static void
00156 doTest1
00157 (
00158 IN void * pv
00159 )
00160 {
00161
00162 tqueue_string_t * tqs = (tqueue_string_t *) pv;
00163 ASSERT(tqs, "null context");
00164
00165 std::string val;
00166 float x = getRandom();
00167 if (x < 0.3) {
00168
00169 val = "test";
00170 tqs->push_back(val);
00171 } else if (x < 0.7) {
00172
00173 tqs->pop_front(val);
00174 } else {
00175
00176 tqueue_string_t::iterator_t i;
00177 tqs->getIterator(i);
00178 while (tqs->getNextElement(i, val)) {
00179 }
00180 }
00181 }
00182
00183
00184
00185 static void
00186 doSPtrTest
00187 (
00188 IN void * pv
00189 )
00190 {
00191 ptr_t * p = (ptr_t *) pv;
00192 ASSERT(p, "null context");
00193 ASSERT(p->get_ref_count() > 0, "Bad ref count!");
00194
00195 ptr_t newP(*p);
00196 ASSERT(newP, "should be non-null!");
00197 ASSERT(newP.get_ref_count() > 1, "should be at least 2! %ld",
00198 newP.get_ref_count());
00199 }
00200
00201
00202
00203 static void
00204 doMultiTest
00205 (
00206 IN void * pv
00207 )
00208 {
00209 multi_string_t * ps = (multi_string_t *) pv;
00210 ASSERT(ps, "null context");
00211
00212
00213 multi_string_t::iterator_t i;
00214 ps->getIterator(i);
00215 std::string key;
00216 std::string value;
00217 while (ps->getNextElement(i, key, value)) {
00218
00219 }
00220
00221
00222
00223 ps->getIterator("a", i);
00224 while (ps->getNextElement(i, key, value)) {
00225
00226 }
00227
00228
00229 int nAdd = rand() % 10;
00230 char buffer[2];
00231 buffer[1] = 0;
00232 for (int j = 0; j < nAdd; ++j) {
00233 buffer[0] = 'a' + (rand() % 26);
00234 ps->insert(buffer, buffer);
00235 }
00236
00237
00238 buffer[0] = 'a' + (rand() % 26);
00239 ps->remove(buffer);
00240 }
00241
00242
00243
00244 static void
00245 validateSPtr
00246 (
00247 IN void * pv
00248 )
00249 {
00250 ptr_t * p = (ptr_t *) pv;
00251 ASSERT(p, "null context?");
00252
00253 if (1 != p->get_ref_count()) {
00254 WAVE_EX(wex);
00255 wex << "smart pointer test failed ref count!\n";
00256 wex << "Expected exactly 1 ref count, but found ";
00257 wex << p->get_ref_count();
00258 }
00259 delete p;
00260 }
00261
00262
00263
00264 static void *
00265 threadStartWrapper
00266 (
00267 IN void * pv
00268 )
00269 {
00270 context_t * ctx = (context_t *) pv;
00271 ASSERT(ctx, "null context");
00272 ASSERT(ctx->ctr, "null counter");
00273 ASSERT(ctx->fn, "null test function");
00274
00275
00276 counter_ref cref(ctx->ctr);
00277
00278
00279 for (int i = 0; i < 100 * 1000; ++i) {
00280 sleep(0);
00281 ctx->fn(ctx->ctx);
00282 }
00283
00284
00285 return NULL;
00286 }
00287
00288
00289
00290
00291 void
00292 threadLoop
00293 (
00294 IN int nThreads,
00295 IN get_context_fn getContext,
00296 IN test_routine_t fn,
00297 IN valid_fn valid = NULL
00298 )
00299 {
00300 ASSERT(nThreads > 0, "Bad thread count: %d", nThreads);
00301 ASSERT(fn, "null thread start function");
00302
00303
00304 threadsafe_counter c;
00305
00306 context_t ctx;
00307 ctx.ctx = getContext();
00308 ctx.ctr = &c;
00309 ctx.fn = fn;
00310
00311 for (int i = 0; i < nThreads; ++i) {
00312 thread_id_t id;
00313 createThread(threadStartWrapper, &ctx, id);
00314 }
00315
00316
00317 sleep(1);
00318 while (c.getCount()) {
00319 sleep(1);
00320 }
00321 DPRINTF("Done waiting for threads!");
00322
00323 if (valid) {
00324 valid(ctx.ctx);
00325 }
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 int
00337 main
00338 (
00339 IN int argc,
00340 IN const char * argv[]
00341 )
00342 {
00343 int retval = 0;
00344
00345 int nThreads = 10;
00346 if (argc > 1) {
00347 nThreads = atoi(argv[1]);
00348 }
00349 DPRINTF("Using %d threads.", nThreads);
00350 ASSERT(nThreads > 0, "Bad thread count: %d", nThreads);
00351
00352 try {
00353 perf::Timer timer("threadsafe test1 -- overall timer");
00354
00355 DPRINTF("Testing smart_ptr<T>...");
00356 threadLoop(nThreads, getSPtrContext, doSPtrTest, validateSPtr);
00357
00358 DPRINTF("Testing queues...");
00359 threadLoop(nThreads, getContext1, doTest1);
00360
00361 DPRINTF("Testing multimap (this takes ~30 seconds)...");
00362 threadLoop(nThreads, getMMctx, doMultiTest);
00363
00364 } catch (std::exception& e) {
00365 DPRINTF("Exception: %s", e.what());
00366 retval = 1;
00367 }
00368
00369 perf::dumpTimingSummary(std::cerr);
00370
00371
00372 return retval;
00373 }
00374