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