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