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