HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_Interrupt.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_Interrupt.h (C++)
7  *
8  * COMMENTS:
9  *
10  */
11 
12 #ifndef __UT_Interrupt__
13 #define __UT_Interrupt__
14 
15 #include "UT_API.h"
16 
17 #include "UT_Array.h"
18 #include "UT_Lock.h"
19 #include "UT_Signal.h"
20 #include "UT_String.h"
21 #include "UT_StringArray.h"
22 #include "UT_StringHolder.h"
23 #include "UT_SysClone.h"
24 #include "UT_ThreadSpecificValue.h"
25 #include "UT_TimeGate.h"
26 #include "UT_ValArray.h"
27 
28 #ifndef GAMEOS
29  #include "UT_SharedMem.h"
30 #endif
31 
32 #include <sys/types.h>
33 
34 class ut_IserverInterface;
35 class ut_Iclient;
36 class UT_Interrupt;
38 
39 typedef void (*UT_InterruptCB)(UT_Interrupt *me, int state, const char *op);
40 typedef void (*OPUI_UpdateModeCB)();
41 typedef bool (*UI_CheckForEscapeCB)();
42 
44 
45 /// An intentionally light weight class to hold interrupt messages
46 /// The idea is people can format them with their callback methods.
47 /// This isn't virtual as we want to build an array of them by value
48 /// at this level.
49 /// You should harden any info you need. Do not rely on your callback
50 /// being invoked in your thread or during your scope!
52 {
53 public:
54  UT_InterruptMessage() { myBuildMessageCallback = 0; }
55  UT_InterruptMessage(UT_InterruptMessageCB cb) { myBuildMessageCallback = cb; }
56  UT_InterruptMessage(UT_InterruptMessageCB cb, const UT_StringHolder &str) { myBuildMessageCallback = cb; myText = str; }
57 
59  {
60  if (myCachedText.isstring()) return myCachedText;
61  if (!myBuildMessageCallback) return myCachedText;
62  myCachedText = myBuildMessageCallback(this);
63  return myCachedText;
64  }
65 
66 private:
67  mutable UT_StringHolder myCachedText;
68  UT_InterruptMessageCB myBuildMessageCallback;
69 
70  // These are public so the callbacks can use them.
71 public:
73 
74  // We have our values. Intentionally *not* including
75  // pointers since there is no destructor and no scope.
76  // The point of this is to be *fast*.
77  union {
78  int i;
79  float d;
80  } value1;
81  union {
82  int i;
83  float d;
84  } value2;
85  union {
86  int i;
87  float d;
88  } value3;
89  union {
90  int i;
91  float d;
92  } value4;
93 };
94 
96 {
97 public:
98  virtual ~UT_InterruptHandler() {}
99  virtual void start(UT_Interrupt *intr,
100  const UT_InterruptMessage &msg,
101  const UT_StringRef &main_optext,
102  int priority) =0;
103  virtual void push(UT_Interrupt *intr,
104  const UT_InterruptMessage &msg,
105  const UT_StringRef &main_optext,
106  int priority) =0;
107  virtual void busyCheck(bool interrupted,
108  float percent,
109  float longpercent) = 0;
110  virtual void pop() =0;
111  virtual void stop() =0;
112 
113  virtual void interruptAllowed(bool allowed, bool allow_ui) =0;
114 };
115 
116 //
117 // These state values are passed to the active callback:
118 //
119 enum
120 {
121  ACTIVE_STOP, // Final opEnd
122  ACTIVE_START, // First opStart
123  ACTIVE_PUSH, // opStart
124  ACTIVE_POP, // opEnd
125  ACTIVE_BUSY, // opInterrupt
126  ACTIVE_ALLOW_CHANGE // myInterruptable has changed state
127 };
128 
129 
130 #ifdef GAMEOS
131 class UT_API UT_Interrupt
132 #else
134 #endif
135 {
136 public:
137  /// When interrupts nest, it is not always useful to display the
138  /// entire stack of interrupts. Priority is used to control if
139  /// the interrupt should be shown.
140  /// 1) All PERMANENT messages are shown.
141  /// 2) Only the topmost NODE is shown, provided it isn't shadowed
142  /// by a PERMANENT.
143  /// 3) Only the topmost TRANSIENT is shown, provided it isn't shadowed
144  /// by a PERMANENT or NODE.
145  /// Node cooking in Houdini uses the NODE level, so for most ad-hoc
146  /// interrupt messages the TRANSIENT level is best.
147  enum Priority
148  {
149  PRIORITY_TRANSIENT = 0,
150  PRIORITY_NODE = 1,
151  PRIORITY_PERMANENT = 2,
152  };
153  explicit UT_Interrupt(const char *app_title = 0);
154  virtual ~UT_Interrupt();
155 
156  // The interrupt object must be enabled for interrupts to be
157  // allowed. The initial state is disabled.
158  // If print_longtext is 1, then each time the "long" text is changed
159  // with setLongOpText(), the text will be printed onto stdout.
160  void setEnabled(int state, int print_longtext = 0);
161  bool isEnabled() const { return (bool) myEnableFlag; }
162 
163  // If this class is being used in a single-threaded app then call
164  // setUseLocks(0); Default is 1.
165  void setUseLocks(int state) { myUseLockFlag = (state != 0); }
166 
167  // If this flag is set to false, the idialog is started in uninterruptable
168  // mode. This makes idialog basically a status display. Also, on threaded
169  // UI, hitting ESC will do nothing.
170  //
171  // setInterruptable(true) returns false if UT_Interrupt was already
172  // interrupted, and hence will fail to turn off the interruptable flag. If
173  // prev_enabled is non-NULL, then it is set to the previous flag state,
174  // regardless of the return value.
175  // NB: setInterruptable() will perform locking using myInterruptableLock.
176  bool setInterruptable(bool allow, bool *prev_enabled = NULL,
177  bool allow_ui = false);
178  bool getInterruptable() const { return myInterruptable; }
179  UT_Lock & getInterruptableLock() { return myInterruptableLock; }
180  bool getAllowUI() const { return myAllowUI; }
181 
182  // Normally the myInterruptedFlag is reset as soon as the outermost
183  // opStart/opEnd pair is closed. This does not work very well
184  // if we need to track the interrupt flag across returning into
185  // the event loop. Similarly, we may wish to leave the interrupt
186  // in a sticky state until someone manually re-enables cooking.
187  // clearStickyInterrupts() will both clear the sticky interrupt
188  // flag *AND* clear the interrupt flag.
189  void clearStickyInterrupts();
190  bool stickyInterrupts() const { return myInterruptSticky; }
191  void setStickyInterrupts();
192 
193  int getOpDepth() const { return myOpDepth; }
194 
195  /// To use the long operation mechanism invoke "opStart" once,
196  /// giving the name of the operation and (if possible) an estimate
197  /// of the number of calls which are planned to be made to the
198  /// opInterrupt method. The start method will return zero if the
199  /// operation has already been terminated (possibly from a containing long
200  /// operation) and should not even start. In that case, you *must* still
201  /// call opEnd(). It will return one if the operation can proceed normally.
202  ///
203  /// During the long operation, invoke the "opInterrupt" method
204  /// (if possible, giving a value between 0 and 100 indicating the
205  /// percentage of the operation that is complete). This method will
206  /// return zero if the operation should continue and one if a request
207  /// was made to terminate. When the operation is complete, invoke the
208  /// "opEnd" method. This should be called even if the operation was
209  /// interrupted.
210  ///
211  /// The 'immediate_dialog' flag causes the idialog program to be started
212  /// immediately instead of waiting for a timeout. This is the only way to
213  /// start the idialog progress monitor, and should only be used for very
214  /// long operations where the user would minimize Houdini (like rendering)
215  ///
216  /// The opid can be used to verify nesting of interrupts. It can be
217  /// passed to opEnd to verify that the nesting is proper...
218  ///
219  /// These methods are now thread safe. Only the main thread will start
220  /// the interrupt server.
221  // @{
222  int opStart(const char *opname = 0, int npoll = 0,
223  int immediate_dialog=0, int *opid=0);
224  int opStartPriority(int priority, const char *opname = 0, int npoll = 0,
225  int immediate_dialog=0, int *opid=0);
226  int opStartMessage(int priority, const UT_InterruptMessage &msg, int immediate_dialog = 0, int *opid = 0);
227 
228  int opInterrupt(int percent = -1);
229 
230  void opEnd(int opid=-1);
231  // @}
232 
233  /// Call this before a new set of opStart()s are called. It will also
234  /// cause idialog to configure the user interface with two text boxes
235  /// instead of the usual single line. After that, you can call
236  /// setLongOpText() to modify the second line message.
237  // @{
238  void setLongOpText(const UT_StringHolder &longoptext);
239  void setLongPercent(float percent);
240  // @}
241 
242  // The application title string will be placed in the percent
243  // completion dialog.
244  void setAppTitle(const char *title);
245  UT_StringHolder getAppTitle() const { return myAppTitle; }
246 
247  // The active callback is invoked whenever opStart and opEnd are called.
248  // This lets someone else keep track of when we're inside an interruptible
249  // loop. The Interrupt Handler is similar but C++ based.
251  { myActiveCallback = function; }
252 
254  {
255  myUIHandler = hand;
256  if(hand)
257  hand->interruptAllowed(myInterruptable, myAllowUI);
258  }
259  UT_InterruptHandler *getInterruptHandler() { return myUIHandler; }
260 
261  // Set the 'ourMemoryThresholdCallback' ptr to 'function'. See the
262  // declaration of ourMemoryThresholdCallback for more details.
264  { ourMemoryThresholdCallback = function; }
265 
266  // Set the 'ourEscapeCheckCallback' ptr to 'function'. See the
267  // declaration of ourEscapeCheckCallback for more details
269  { ourEscapeCheckCallback = function; }
271  { return ourEscapeCheckCallback; }
272 
273  // The interrupt callbacks are called when the user interrupts Houdini.
274  // Add an interrupt callback when the operation being called needs to
275  // do extra work to interrupt the main thread. For example, to stop
276  // python execution, an interrupt callback is needed to raise a python
277  // exception.
278  //
279  // Only the callback that was pushed last will be called.
280  void pushInterruptCallback(void (*callback)());
281  void popInterruptCallback();
282 
283  // You can manually interrupt an active loop by calling this method.
284  // If calling from a thread other than the looping thread then set
285  // the use_semaphore flag.
286  void interrupt(int use_semaphore = 0);
287 
288  void pause(bool dopause);
289 
290  bool isPaused() const;
291 
292  // This is the signal handler that gets used when we're not in an
293  // interruptable state.
294  void setSignalCallback(UTsigHandler function);
295 
296  // test if we're within the memory threshold, and if not, return true.
298  {
299  return ourMemoryThresholdCallback
300  ? doTestMemoryThreshold() : false;
301  }
302 protected:
303  // These methods are used by the interrupt server to get access
304  // to the shared memory segment.
305  const char *getSharedKey() const;
306 
307  virtual int detach();
308 
309 #ifdef GAMEOS
310  void *getMemory(int reuse=1) { return 0; }
311  void destroy() {}
312  int setKey(const char *, int id=0) { return -1; }
313  int setKey(key_t key) { return -1; }
314  int setSize(int size) { return size; }
316 #endif
317 
318 private:
319  bool doTestMemoryThreshold();
320  void testIdialogInterrupt();
321  void testEscCallbackInterrupt();
322 
323  void updateTitle(const char *title);
324  void operationComplete();
325  void startServer();
326  void stopServer();
327  UT_StringHolder getOpName() const;
328  void callInterruptCB();
329 
330 
331  UT_Array<UT_InterruptMessage> myOpNameStack;
332 
333  UT_Array<void(*)()> myInterruptCBStack;
334 
335  UT_StringHolder myAppTitle;
336  UT_StringHolder myLongOpText;
337  UT_InterruptCB myActiveCallback;
338  UT_InterruptHandler *myUIHandler;
339  char *myServerPath;
340  char myPidString[16];
341  const char *myArgv[16];
342  int myOpDepth;
343  UT_Interrupt *myPreviousInterrupt;
344  UT_Signal *mySignal;
345  UT_Signal *mySignalSubstitute;
346  UTsigHandler mySignalCallback;
347  pid_t myServerPID;
348 
349  int myStartTime;
350 
351  short myEnableFlag;
352  short myStartedFlag;
353  short myInterruptedFlag;
354  char myPrintLongTextFlag;
355  char myUseLockFlag;
356  bool myInterruptable;
357  bool myAllowUI;
358  bool myInterruptSticky;
359  float myPercent;
360  float myLongPercent;
361  volatile bool myPaused;
362 
363  UT_ThreadSpecificValue<int> myTLSDepth;
364 
365  // This is how we let OPUI_App know we'd like to change the update mode
366  // to OPUI_UPDATE_ON_DEMAND when we're running out of virtual addresses
367  static OPUI_UpdateModeCB ourMemoryThresholdCallback;
368 
369  // This is how we ask the UI layer to check whether an escape key has
370  // been pressed in the case where we do not have threaded UI.
371  static UI_CheckForEscapeCB ourEscapeCheckCallback;
372 
373  UT_Lock myLock;
374  UT_Lock myInterruptableLock;
375 
376  UT_TimeGate<100> myTimeGate;
377 
378  static void ut_interruptHandler(UTsignalHandlerArg);
379 };
380 
381 /// Obtain global UT_Interrupt singleton.
383 UT_API extern void UTsetInterrupt(UT_Interrupt *);
384 
385 // a template for the comm layout for the shared memory link between
386 // UT_Interrupt and idialog.
388 {
389  // I/O is relative to UT_Interrupt.
390  volatile int myCommand; // In: 0 none, 1 interrupt, 2 pause
391  volatile float myPercent; // Out: current task % complete
392  volatile float myLongPercent; // Out: primary task % complete
393  volatile int myNumMessages; // Out: # of messages in message area
394  volatile char myMessage[128]; // Out: message
395  volatile char myLongMessage[128]; // Out: message for long ops
396 };
397 
398 // A simple client which can be used in processes spawned by Houdini (such
399 // as mantra). It allows these processes to report the completion percentage,
400 // and read the interrupt/pause state.
401 #ifdef GAMEOS
403 #else
405 #endif
406 {
407 public:
408  UT_InterruptClient(pid_t server_id);
410 
411  bool isInterrupted();
412 
413  void setPercent(float p);
414  void setLongPercent(float p);
415 
416  void setMessage(const char *title);
417 
418 #ifdef GAMEOS
419  void *getMemory(int reuse=1) { return 0; }
420  void destroy() {}
421  int setKey(const char *, int id=0) { return -1; }
422  int setKey(key_t key) { return -1; }
423  int setSize(int size) { return size; }
425 #endif
426 
427 };
428 
429 /// Helper class to ensure that opEnd() is always called, even if you
430 /// return early from a function. It's similar to UT_AutoUndoBlock.
432 {
433 public:
434  UT_AutoInterrupt(const char* operation_name,
436  : myInterrupt(boss)
437  {
438  myRunOk = myInterrupt
439  ? (bool)myInterrupt->opStart(operation_name, 0, 0, &myId)
440  : true;
441  }
442 
444  {
445  if (myInterrupt)
446  myInterrupt->opEnd(myId);
447  }
448 
450  {
451  if (myRunOk && myInterrupt && myInterrupt->opInterrupt())
452  myRunOk = false;
453  return !myRunOk;
454  }
455 
456  bool wasInterrupted(int percent)
457  {
458  if (myRunOk && myInterrupt && myInterrupt->opInterrupt(percent))
459  myRunOk = false;
460  return !myRunOk;
461  }
462 
463  UT_Interrupt *getInterrupt() const { return myInterrupt; }
464 
465 private:
466  UT_Interrupt *myInterrupt;
467  bool myRunOk;
468  int myId;
469 };
470 
471 #endif /* __UT_Interrupt__ */
UT_StringHolder myText
Definition: UT_Interrupt.h:72
UT_Interrupt * getInterrupt() const
Definition: UT_Interrupt.h:463
virtual int destroy()
bool getAllowUI() const
Definition: UT_Interrupt.h:180
volatile char myLongMessage[128]
Definition: UT_Interrupt.h:395
GLuint start
Definition: glcorearb.h:474
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
static bool getIsEscapeCheckCallbackSet()
Definition: UT_Interrupt.h:270
int getOpDepth() const
Definition: UT_Interrupt.h:193
virtual int detach()
void(* OPUI_UpdateModeCB)()
Definition: UT_Interrupt.h:40
#define UT_API
Definition: UT_API.h:13
void setUseLocks(int state)
Definition: UT_Interrupt.h:165
void setActiveCallback(UT_InterruptCB function)
Definition: UT_Interrupt.h:250
png_uint_32 i
Definition: png.h:2877
GLsizeiptr size
Definition: glcorearb.h:663
bool(* UI_CheckForEscapeCB)()
Definition: UT_Interrupt.h:41
void setInterruptHandler(UT_InterruptHandler *hand)
Definition: UT_Interrupt.h:253
UT_InterruptMessage(UT_InterruptMessageCB cb, const UT_StringHolder &str)
Definition: UT_Interrupt.h:56
const UT_StringHolder & buildMessage() const
Definition: UT_Interrupt.h:58
UT_AutoInterrupt(const char *operation_name, UT_Interrupt *boss=UTgetInterrupt())
Definition: UT_Interrupt.h:434
void(* UT_InterruptCB)(UT_Interrupt *me, int state, const char *op)
Definition: UT_Interrupt.h:39
UT_InterruptMessage(UT_InterruptMessageCB cb)
Definition: UT_Interrupt.h:55
virtual void * getMemory(int reuse=1)
int setKey(const char *path, int id=0)
volatile float myLongPercent
Definition: UT_Interrupt.h:392
bool stickyInterrupts() const
Definition: UT_Interrupt.h:190
virtual void interruptAllowed(bool allowed, bool allow_ui)=0
static void setUpdateModeCallback(OPUI_UpdateModeCB function)
Definition: UT_Interrupt.h:263
static void setEscapeCheckCallback(UI_CheckForEscapeCB function)
Definition: UT_Interrupt.h:268
bool getInterruptable() const
Definition: UT_Interrupt.h:178
bool isEnabled() const
Definition: UT_Interrupt.h:161
UT_String ourKeyPath
Definition: UT_SharedMem.h:105
UT_API UT_Interrupt * UTgetInterrupt()
Obtain global UT_Interrupt singleton.
volatile char myMessage[128]
Definition: UT_Interrupt.h:394
UT_API void UTsetInterrupt(UT_Interrupt *)
int setSize(int size)
virtual ~UT_InterruptHandler()
Definition: UT_Interrupt.h:98
UT_Lock & getInterruptableLock()
Definition: UT_Interrupt.h:179
void(* UTsigHandler)(UTsignalHandlerArg)
Definition: UT_Signal.h:169
UT_InterruptHandler * getInterruptHandler()
Definition: UT_Interrupt.h:259
bool wasInterrupted(int percent)
Definition: UT_Interrupt.h:456
UT_StringHolder getAppTitle() const
Definition: UT_Interrupt.h:245
bool testMemoryThreshold()
Definition: UT_Interrupt.h:297
UT_StringHolder(* UT_InterruptMessageCB)(const UT_InterruptMessage *me)
Definition: UT_Interrupt.h:43