w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

TileCache.cc
Go to the documentation of this file.
1 //========================================================================
2 //
3 // TileCache.cc
4 //
5 // Copyright 2014 Glyph & Cog, LLC
6 //
7 //========================================================================
8 
9 #include <aconf.h>
10 
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14 
15 #include "gmem.h"
16 #include "gmempp.h"
17 #include "GList.h"
18 #include "GMutex.h"
19 #ifdef _WIN32
20 # include <windows.h>
21 #else
22 # include <pthread.h>
23 # include <unistd.h>
24 #endif
25 #include "Object.h"
26 #include "PDFDoc.h"
27 #include "SplashBitmap.h"
28 #include "SplashOutputDev.h"
29 #include "DisplayState.h"
30 #include "GfxState.h"
31 #include "TileMap.h"
32 #include "TileCache.h"
33 
34 //------------------------------------------------------------------------
35 // CachedTileDesc
36 //------------------------------------------------------------------------
37 
39  cachedTileUnstarted, // worker thread hasn't started
40  // rasterization yet
41  cachedTileStarted, // worker thread is rasterizing the tile
42  cachedTileFinished, // rasterization is done
43  cachedTileCanceled // worker thread should stop rasterizing
44  // and remove this tile from the cache
45 };
46 
47 class CachedTileDesc: public TileDesc {
48 public:
49 
52  tile->tx, tile->ty, tile->tw, tile->th),
56 
61 };
62 
64  if (freeBitmap) {
65  delete bitmap;
66  }
67 }
68 
69 //------------------------------------------------------------------------
70 // OS-dependent threading support code
71 //
72 // NB: This wrapper code is not meant to be general purpose. Pthreads
73 // condition objects are not equivalent to Windows event objects, in
74 // general.
75 //------------------------------------------------------------------------
76 
77 //-------------------- Windows --------------------
78 #ifdef _WIN32
79 
80 typedef HANDLE GThreadID;
81 typedef DWORD (WINAPI *GThreadFunc)(void *);
82 #define GThreadReturn DWORD WINAPI
83 
84 static void gCreateThread(GThreadID *thr, GThreadFunc threadFunc,
85  void *data) {
86  *thr = CreateThread(NULL, 0, threadFunc, data, 0, NULL);
87 }
88 
89 static void gJoinThread(GThreadID thr) {
90  WaitForSingleObject(thr, INFINITE);
91  CloseHandle(thr);
92 }
93 
94 typedef HANDLE GCondition;
95 
96 static void gInitCondition(GCondition *c) {
97  *c = CreateEvent(NULL, TRUE, FALSE, NULL);
98 }
99 
100 static void gDestroyCondition(GCondition *c) {
101  CloseHandle(*c);
102 }
103 
104 static void gSignalCondition(GCondition *c) {
105  SetEvent(*c);
106 }
107 
108 static void gClearCondition(GCondition *c) {
109  ResetEvent(*c);
110 }
111 
112 static void gWaitCondition(GCondition *c, GMutex *m) {
113  LeaveCriticalSection(m);
114  WaitForSingleObject(*c, INFINITE);
115  EnterCriticalSection(m);
116 }
117 
118 //-------------------- pthreads --------------------
119 #else
120 
121 typedef pthread_t GThreadID;
122 typedef void *(*GThreadFunc)(void *);
123 #define GThreadReturn void*
124 
125 static void gCreateThread(GThreadID *thr, GThreadFunc threadFunc,
126  void *data) {
127  pthread_create(thr, NULL, threadFunc, data);
128 }
129 
130 static void gJoinThread(GThreadID thr) {
131  pthread_join(thr, NULL);
132 }
133 
134 typedef pthread_cond_t GCondition;
135 
136 static void gInitCondition(GCondition *c) {
137  pthread_cond_init(c, NULL);
138 }
139 
141  pthread_cond_destroy(c);
142 }
143 
145  pthread_cond_broadcast(c);
146 }
147 
148 static void gClearCondition(GCondition *c) {
149 }
150 
151 static void gWaitCondition(GCondition *c, GMutex *m) {
152  pthread_cond_wait(c, m);
153 }
154 
155 #endif
156 
157 //------------------------------------------------------------------------
158 // TileCacheThreadPool
159 //------------------------------------------------------------------------
160 
162 public:
163 
164  TileCacheThreadPool(TileCache *tileCacheA, int nThreadsA);
166 
167  // Called by the client when one or more jobs have been added to the
168  // queue. This must be called with the mutex unlocked.
169  void jobAdded();
170 
171  // Wait for at least one job to be finished. This must be called
172  // with the mutex locked.
173  void waitForFinishedJob();
174 
175  // The client should use the mutex to protect the queue data
176  // structure.
177  void lockMutex() { gLockMutex(&mutex); }
179 
180 private:
181 
182  static GThreadReturn threadFunc(void *arg);
183  void worker();
184 
186  int nThreads;
190  GCondition cond; // signalled when a job is added to the
191  // queue and when the quit flag is set
192  GCondition finishCond; // signalled whenever a worker thread
193  // finishes rasterizing a tile
194 };
195 
197  int nThreadsA) {
198  int i;
199 
200  tileCache = tileCacheA;
201  nThreads = nThreadsA;
202  quit = gFalse;
203  gInitMutex(&mutex);
207  for (i = 0; i < nThreads; ++i) {
208  gCreateThread(&threads[i], &threadFunc, this);
209  }
210 }
211 
213  int i;
214 
215  gLockMutex(&mutex);
216  quit = true;
219  for (i = 0; i < nThreads; ++i) {
221  }
225  gfree(threads);
226 }
227 
229  gLockMutex(&mutex);
232 }
233 
235  ((TileCacheThreadPool *)arg)->worker();
236  return 0;
237 }
238 
240  CachedTileDesc *ct;
241 
242  while (1) {
243  gLockMutex(&mutex);
244  while (!quit && !(ct = tileCache->getUnstartedTile())) {
246  }
247  if (quit) {
249  break;
250  }
251  if (!tileCache->hasUnstartedTiles()) {
253  }
257  }
258 }
259 
262 }
263 
264 //------------------------------------------------------------------------
265 // TileCache
266 //------------------------------------------------------------------------
267 
269  state = stateA;
270  state->setTileCache(this);
271  cache = new GList();
272  threadPool = new TileCacheThreadPool(this, state->getNWorkerThreads());
273  tileDoneCbk = NULL;
275 }
276 
279  delete threadPool;
280  delete cache;
281 }
282 
284  TileDesc *tile;
285  CachedTileDesc *ct;
286  int tileIdx, cacheIdx;
287  GBool newTiles;
288 
290 
291  // remove any unstarted tiles not on the new active list;
292  // cancel any started tiles not on the new active list;
293  // mark all other tiles as inactive (active tiles will be marked later)
294  cacheIdx = 0;
295  while (cacheIdx < cache->getLength()) {
296  ct = (CachedTileDesc *)cache->get(cacheIdx);
297  if (ct->state == cachedTileUnstarted && findTile(ct, tiles) < 0) {
298  delete (CachedTileDesc *)cache->del(cacheIdx);
299  } else if (ct->state == cachedTileStarted && findTile(ct, tiles) < 0) {
301  ++cacheIdx;
302  } else {
303  ct->active = gFalse;
304  ++cacheIdx;
305  }
306  }
307 
308  // mark cached tiles as active; add any new tiles to the cache
309  newTiles = gFalse;
310  for (tileIdx = 0; tileIdx < tiles->getLength(); ++tileIdx) {
311  tile = (TileDesc *)tiles->get(tileIdx);
312  cacheIdx = findTile(tile, cache);
313  if (cacheIdx >= 0) {
314  ct = (CachedTileDesc *)cache->del(cacheIdx);
315  } else {
316  ct = new CachedTileDesc(tile);
317  newTiles = gTrue;
318  }
319  ct->active = gTrue;
320  cache->insert(0, ct);
321  }
322 
323  cleanCache();
324 
326 
327  if (newTiles) {
328  threadPool->jobAdded();
329  }
330 }
331 
333  CachedTileDesc *ct;
335  int cacheIdx;
336 
338  cacheIdx = findTile(tile, cache);
339  if (cacheIdx < 0) {
341  return NULL;
342  }
343  ct = (CachedTileDesc *)cache->get(cacheIdx);
344  if (ct->state != cachedTileCanceled) {
345  bitmap = ct->bitmap;
346  } else {
347  bitmap = NULL;
348  }
349  if (finished) {
350  *finished = ct->state == cachedTileFinished;
351  }
353  return bitmap;
354 }
355 
358 }
359 
362 }
363 
366 }
367 
369  flushCache(gTrue);
370 }
371 
372 
375 }
376 
377 // Search for <tile> on <tileList>, and return its index if found, or
378 // -1 if not found. If <tile> is part of the cache, or if <tileList>
379 // is the cache, the caller must have locked the ThreadPool mutex.
381  TileDesc *t;
382  int i;
383 
384  for (i = 0; i < tileList->getLength(); ++i) {
385  t = (TileDesc *)tileList->get(i);
386  if (t->matches(tile)) {
387  return i;
388  }
389  }
390  return -1;
391 }
392 
393 // If there are too many tiles in the cache, remove the least recently
394 // used tiles. Never removes active tiles. The caller must have
395 // locked the ThreadPool mutex.
397  CachedTileDesc *ct;
398  int n, i;
399 
400  // count the number of non-canceled tiles
401  n = 0;
402  for (i = 0; i < cache->getLength(); ++i) {
403  ct = (CachedTileDesc *)cache->get(i);
404  if (ct->state != cachedTileCanceled) {
405  ++n;
406  }
407  }
408 
409  // if there are too many non-canceled tiles, remove tiles
410  i = cache->getLength() - 1;
411  while (n > state->getTileCacheSize() && i >= 0) {
412  ct = (CachedTileDesc *)cache->get(i);
413  if (ct->active) {
414  break;
415  }
416  // any non-active tiles with state == cachedTileUnstarted should
417  // already have been removed by setActiveTileList()
418  if (ct->state == cachedTileFinished) {
419  delete (CachedTileDesc *)cache->del(i);
420  --n;
421  --i;
422  } else {
423  --i;
424  }
425  }
426 }
427 
428 // Remove all cached tiles. For tiles that are being rasterized, sets
429 // state to canceled. If <wait> is true, this function won't return
430 // until the cache is empty, i.e., until all possible users of the
431 // PDFDoc are done.
433  CachedTileDesc *ct;
434  int i;
435 
437  i = 0;
438  while (i < cache->getLength()) {
439  ct = (CachedTileDesc *)cache->get(i);
440  switch (ct->state) {
441  case cachedTileUnstarted:
442  case cachedTileFinished:
443  delete (CachedTileDesc *)cache->del(i);
444  break;
445  case cachedTileStarted:
447  ++i;
448  break;
449  case cachedTileCanceled:
450  default:
451  ++i;
452  break;
453  }
454  }
455  if (wait) {
456  while (cache->getLength() > 0) {
458  }
459  }
461 }
462 
463 // Remove a tile from the cache and delete it. This will be called
464 // with the TileCacheThreadPool mutex locked.
466  int i;
467 
468  for (i = 0; i < cache->getLength(); ++i) {
469  if (cache->get(i) == ct) {
470  delete (CachedTileDesc *)cache->del(i);
471  break;
472  }
473  }
474 }
475 
476 // Return true if there are one or more unstarted tiles. This will be
477 // called with the TileCacheThreadPool mutex locked.
479  CachedTileDesc *ct;
480  int i;
481 
482  for (i = 0; i < cache->getLength(); ++i) {
483  ct = (CachedTileDesc *)cache->get(i);
484  if (ct->state == cachedTileUnstarted) {
485  return gTrue;
486  }
487  }
488  return gFalse;
489 }
490 
491 // Return the next unstarted tile, changing its state to
492 // cachedTileStarted. If there are no unstarted tiles, return NULL.
493 // This will be called with the TileCacheThreadPool mutex locked.
495  CachedTileDesc *ct;
496  int i;
497 
498  for (i = 0; i < cache->getLength(); ++i) {
499  ct = (CachedTileDesc *)cache->get(i);
500  if (ct->state == cachedTileUnstarted) {
501  ct->state = cachedTileStarted;
502  return ct;
503  }
504  }
505  return NULL;
506 }
507 
512 };
513 
516 
517  info->tileCache->threadPool->lockMutex();
518  info->ct->bitmap = info->out->getBitmap();
519  info->ct->freeBitmap = gFalse;
520  info->tileCache->threadPool->unlockMutex();
521 }
522 
523 // Rasterize <tile>. The state has already been set to
524 // cachedTileStarted.
528 
529 
530  out = new SplashOutputDev(state->getColorMode(), 1, state->getReverseVideo(),
531  state->getPaperColor());
532  info.tileCache = this;
533  info.ct = ct;
534  info.out = out;
535  out->setStartPageCallback(&TileCache::startPageCbk, &info);
536  out->startDoc(state->getDoc()->getXRef());
537  state->getDoc()->displayPageSlice(out, ct->page, ct->dpi, ct->dpi, ct->rotate,
538  gFalse, gTrue, gFalse,
539  ct->tx, ct->ty, ct->tw, ct->th,
540  &abortCheckCbk, ct);
541  if (ct->state == cachedTileCanceled) {
543  removeTile(ct);
545  } else {
547  ct->bitmap = out->takeBitmap();
548  ct->freeBitmap = gTrue;
551  if (tileDoneCbk) {
552  (*tileDoneCbk)(tileDoneCbkData);
553  }
554  }
555  delete out;
556 }
557 
558 
561  return ct->state == cachedTileCanceled;
562 }
#define gUnlockMutex(m)
Definition: GMutex.h:54
pthread_mutex_t GMutex
Definition: GMutex.h:49
#define gDestroyMutex(m)
Definition: GMutex.h:52
#define gInitMutex(m)
Definition: GMutex.h:51
#define gLockMutex(m)
Definition: GMutex.h:53
#define WINAPI
void *(* GThreadFunc)(void *)
Definition: TileCache.cc:122
#define GThreadReturn
Definition: TileCache.cc:123
CachedTileState
Definition: TileCache.cc:38
@ cachedTileStarted
Definition: TileCache.cc:41
@ cachedTileCanceled
Definition: TileCache.cc:43
@ cachedTileFinished
Definition: TileCache.cc:42
@ cachedTileUnstarted
Definition: TileCache.cc:39
static void gDestroyCondition(GCondition *c)
Definition: TileCache.cc:140
static void gSignalCondition(GCondition *c)
Definition: TileCache.cc:144
pthread_t GThreadID
Definition: TileCache.cc:121
static void gJoinThread(GThreadID thr)
Definition: TileCache.cc:130
pthread_cond_t GCondition
Definition: TileCache.cc:134
static void gCreateThread(GThreadID *thr, GThreadFunc threadFunc, void *data)
Definition: TileCache.cc:125
static void gClearCondition(GCondition *c)
Definition: TileCache.cc:148
static void gWaitCondition(GCondition *c, GMutex *m)
Definition: TileCache.cc:151
static void gInitCondition(GCondition *c)
Definition: TileCache.cc:136
CachedTileDesc(TileDesc *tile)
Definition: TileCache.cc:50
CachedTileState state
Definition: TileCache.cc:57
SplashBitmap * bitmap
Definition: TileCache.cc:59
GBool freeBitmap
Definition: TileCache.cc:60
Definition: GList.h:24
int getLength()
Definition: GList.h:39
void * del(int i)
Definition: GList.cc:85
void insert(int i, void *p)
Definition: GList.cc:71
void * get(int i)
Definition: GList.h:48
GCondition finishCond
Definition: TileCache.cc:192
TileCacheThreadPool(TileCache *tileCacheA, int nThreadsA)
Definition: TileCache.cc:196
static void * threadFunc(void *arg)
Definition: TileCache.cc:234
void waitForFinishedJob()
Definition: TileCache.cc:260
TileCache * tileCache
Definition: TileCache.cc:185
GThreadID * threads
Definition: TileCache.cc:187
SplashBitmap * getTileBitmap(TileDesc *tile, GBool *finished)
Definition: TileCache.cc:332
void * tileDoneCbkData
Definition: TileCache.h:73
void flushCache(GBool wait)
Definition: TileCache.cc:432
void reverseVideoChanged()
Definition: TileCache.cc:360
void optionalContentChanged()
Definition: TileCache.cc:364
int findTile(TileDesc *tile, GList *tileList)
Definition: TileCache.cc:380
void setActiveTileList(GList *tiles)
Definition: TileCache.cc:283
void paperColorChanged()
Definition: TileCache.cc:356
TileCache(DisplayState *stateA)
Definition: TileCache.cc:268
GBool hasUnstartedTiles()
Definition: TileCache.cc:478
void forceRedraw()
Definition: TileCache.cc:373
GList * cache
Definition: TileCache.h:70
static void startPageCbk(void *data)
Definition: TileCache.cc:514
CachedTileDesc * getUnstartedTile()
Definition: TileCache.cc:494
void(* tileDoneCbk)(void *data)
Definition: TileCache.h:72
friend class TileCacheThreadPool
Definition: TileCache.h:75
void cleanCache()
Definition: TileCache.cc:396
void rasterizeTile(CachedTileDesc *tile)
Definition: TileCache.cc:525
void docChanged()
Definition: TileCache.cc:368
void removeTile(CachedTileDesc *ct)
Definition: TileCache.cc:465
static GBool abortCheckCbk(void *data)
Definition: TileCache.cc:559
TileCacheThreadPool * threadPool
Definition: TileCache.h:71
int tw
Definition: TileMap.h:47
int ty
Definition: TileMap.h:45
int rotate
Definition: TileMap.h:43
int tx
Definition: TileMap.h:45
int page
Definition: TileMap.h:42
int th
Definition: TileMap.h:47
double dpi
Definition: TileMap.h:44
#define n
Definition: t4ht.c:1290
@ FALSE
Definition: dd.h:101
@ TRUE
Definition: dd.h:102
#define gfree(p)
Definition: dt2dv.c:326
#define info
Definition: dviinfo.c:42
struct rect data
Definition: dvipdfm.c:64
#define t
Definition: afcover.h:96
void * gmallocn(int nObjs, int objSize)
Definition: gmem.cc:204
#define c(n)
Definition: gpos-common.c:150
#define gFalse
Definition: gtypes.h:18
int GBool
Definition: gtypes.h:16
#define gTrue
Definition: gtypes.h:17
FILE * out
Definition: hbf2gf.c:286
int wait()
#define NULL
Definition: ftobjs.h:61
small capitals from c petite p scientific i
Definition: afcover.h:80
int getLength(char *s)
Definition: lengths.c:99
unsigned int DWORD
Definition: mktexlib.h:49
char * bitmap
Definition: pbmpage.c:35
CachedTileDesc * ct
Definition: TileCache.cc:510
SplashOutputDev * out
Definition: TileCache.cc:511
TileCache * tileCache
Definition: TileCache.cc:509
Definition: gf2pbm.c:137
Definition: mendex.h:14
Definition: dvips.h:235
Definition: sd.h:107
m
Definition: tex4ht.c:3990