NEURON
ivoc.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 #include <vector>
4 #include <ocnotify.h>
5 #include <stdio.h>
6 #include <stdlib.h>
8 #include <nrnmutdec.h>
9 #include "oc2iv.h"
10 #include "ocfunc.h"
11 #include "ocnotify.h"
12 #include "oc_ansi.h"
13 #include "ocjump.h"
14 
15 #if HAVE_IV
16 #include "utility.h"
17 #include "ivoc.h"
18 #endif
19 
20 #include "bimap.hpp"
21 
22 #if NRN_ENABLE_THREADS
23 static MUTDEC;
24 #endif
25 
26 using PF = void (*)(void*, int);
27 using FList = std::vector<PF>;
28 
29 static FList* f_list;
30 
36 
37 // fast insert, find, and remove of (double*, Observer*) using either as
38 // a key. Use pair of multimap since there can be many observers of the
39 // same double. And perhaps one Observer is watching several double*. Also
40 // the double* being watched is removed when the array (pd*, size) it is
41 // a part of is freed. So the upper_bound property is needed
42 
44 
45 void nrn_notify_freed(PF pf) {
46  if (!f_list) {
47  f_list = new FList;
48  }
49  f_list->push_back(pf);
50 }
51 
53  MUTLOCK
54  if (!pvob) {
56  }
57  pvob->insert(p, ob);
58  MUTUNLOCK
59 }
60 
62  MUTLOCK
63  if (!pdob) {
65  }
66  pdob->insert(p, ob);
67  MUTUNLOCK
68 }
69 
71  MUTLOCK
72  if (pvob) {
73  pvob->obremove(ob);
74  }
75  if (pdob) {
76  pdob->obremove(ob);
77  }
78  if (phob) {
79  phob->obremove(ob);
80  }
81  MUTUNLOCK
82 }
83 
84 namespace neuron::container {
85 /**
86  * @brief Register that `obs` should be notified when `dh` dies.
87  *
88  * In general this should happen less often than before, as data_handle<double> can remain valid
89  * even when the pointed-to value changes address.
90  */
93  assert(dh); // strange to set up notification-on-death for something that's already dead
94  MUTLOCK
95  if (!phob) {
97  }
98  phob->insert(dh.identifier(), obs);
99  MUTUNLOCK
100  } else {
101  // The handle is wrapping a raw pointer, fall back to the old code
102  nrn_notify_when_double_freed(static_cast<double*>(dh), obs);
103  }
104 }
105 namespace detail {
106 /**
107  * @brief Respond to the news that data_handles relying on `p` are now dead.
108  *
109  * The data_handle<T> and generic_data_handle wrappers ultimately hold something like `vector_ptr`
110  * and `p`, where `p` is basically `std::size_t*`, and yield vector_ptr->at(*p). When the relevant
111  * value gets deleted, `*p` is set to a sentinel value, then this method is called, and then `p`
112  * is transferred to a garbage heap.
113  */
115  // call Observer::update on everything that was observing `p`, and remove those entries from the
116  // table
117  if (!phob) {
118  return;
119  }
120  MUTLOCK
122  Observer* ob;
123  while (phob->find(p, pv, ob)) {
124  ob->update(nullptr);
125  phob->remove(pv, ob);
126  }
127  MUTUNLOCK
128 }
129 } // namespace detail
130 } // namespace neuron::container
131 
132 void notify_pointer_freed(void* pt) {
133  if (pvob) {
134  MUTLOCK
135  void* pv;
136  Observer* ob;
137  while (pvob->find(pt, pv, ob)) {
138  ob->update(nullptr);
139  pvob->remove(pv, ob);
140  }
141  MUTUNLOCK
142  }
143 }
144 void notify_freed(void* p) {
145  if (f_list) {
146  for (PF f: *f_list) {
147  f(p, 1);
148  }
149  }
151 }
152 void notify_freed_val_array(double* p, size_t size) {
153  if (f_list) {
154  for (PF f: *f_list) {
155  f((void*) p, size);
156  }
157  }
158  if (pdob) {
159  double* pp;
160  Observer* ob;
161  while (pdob->find(p, size, pp, ob)) {
162  // printf("notify_freed_val_array %d %ld\n", size, j);
163  ob->update(NULL);
164  pdob->remove(pp, ob);
165  }
166  }
167 }
168 
169 char* cxx_char_alloc(size_t sz) {
170  char* cp = new char[sz];
171  return cp;
172 }
173 
174 
175 #ifndef MINGW // actual implementation in ivocwin.cpp
177  hoc_pushx(1.);
178  hoc_ret();
179 }
180 #endif
181 
182 void nrn_err_dialog(const char* mes) {
183 #if HAVE_IV
184  if (hoc_usegui) {
185  if (nrn_err_dialog_active_ && !Session::instance()->done()) {
186  char m[1024];
187  Sprintf(m, "%s (See terminal window)", mes);
188  continue_dialog(m);
189  }
190  }
191 #endif
192 }
193 
194 #if HAVE_IV // to end of file
195 
196 #include <InterViews/event.h>
197 #include <InterViews/reqerr.h>
198 #include <InterViews/style.h>
199 #include <IV-look/kit.h>
200 
201 #include "xmenu.h"
202 
203 /*
204  * Interface between oc and interviews.
205  *
206  * The normal command driven oc can be simultaneously event driven if
207  * instead of blocking on a terminal read, run_til_stdin() is called.
208  * This runs the interviews event loop until something is typed in the
209  * window from which oc was run.
210  */
211 
212 extern void hoc_main1_init(const char* pname, const char** env);
213 extern int hoc_interviews;
214 extern Symbol* hoc_parse_expr(const char*, Symlist**);
215 extern double hoc_run_expr(Symbol*);
216 extern int hoc_execerror_messages;
217 extern void hoc_ret();
218 extern void hoc_pushx(double);
219 extern FILE* hoc_fin;
220 extern void ivoc_cleanup();
221 extern "C" void nrn_shape_update();
222 extern int bbs_poll_;
223 extern void bbs_handle();
224 
225 int run_til_stdin();
226 void single_event_run();
227 void hoc_notify_iv();
228 
229 extern int hoc_print_first_instance;
230 void ivoc_style();
231 
232 // because NEURON can no longer maintain its own copy of dialogs.cpp
233 // we communicate with the InterViews version through a callback.
234 extern bool (*IVDialog_setAcceptInput)(bool);
235 bool setAcceptInputCallback(bool b) {
236  Oc oc;
237  return oc.setAcceptInput(b);
238 }
239 
240 void ivoc_style() {
241  TRY_GUI_REDIRECT_DOUBLE("ivoc_style", NULL);
242  if (hoc_usegui) {
243  if (Session::instance()) {
244  Style* s = Session::instance()->style();
245  s->remove_attribute(gargstr(1));
246  s->attribute(gargstr(1), gargstr(2), -5);
247  }
248 #if 0
249 String s;
250 if (WidgetKit::instance()->style()->find_attribute(gargstr(1)+1, s)) {
251  printf("ivoc_style %s: %s\n", gargstr(1), s.string());
252 }else{
253  printf("couldn't find %s\n", gargstr(1));
254 }
255 #endif
256  }
257  hoc_ret();
258  hoc_pushx(1.);
259 }
260 
261 #if !defined(MINGW)
262 /*static*/ class ReqErr1: public ReqErr {
263  public:
264  ReqErr1();
265  virtual void Error();
266  virtual int count() {
267  return count_;
268  }
269 
270  private:
271  int count_;
272  int r_;
273 };
274 
275 ReqErr1::ReqErr1() {
276  count_ = 0;
277  r_ = 0;
278 }
279 
280 void ReqErr1::Error() {
281  if (!count_ || code != r_) {
282  if (!r_) {
283  r_ = code;
284  }
285  fprintf(stderr, "X Error of failed request: %s\n", message);
286  if (r_ == code) {
287  fprintf(stderr, "Further messages for error code %d will not be shown\n", r_);
288  }
289  }
290  ++count_;
291 }
292 
293 static ReqErr1* reqerr1;
294 #endif
295 
296 #ifdef MINGW
297 static HandleStdin* hsd_;
298 void winio_key_press() {
299  hsd_->inputReady(1);
300 }
301 
302 #endif
303 
304 Oc::Oc() {
305  MUTLOCK
306  ++refcnt_;
307  MUTUNLOCK
308 }
309 
310 bool Oc::helpmode_;
311 
312 Oc::Oc(Session* s, const char* pname, const char** env) {
313  if (session_)
314  return;
315  refcnt_++;
316  session_ = s;
317  IVDialog_setAcceptInput = setAcceptInputCallback;
318  notify_change_ = new Observable();
319  if (s) {
320  helpmode_ = false;
321 #if !defined(WIN32)
322  reqerr1 = new ReqErr1;
323  reqerr1->Install();
324 #endif
325 #if defined(MINGW)
326  hsd_ = handleStdin_ = new HandleStdin;
327 #else
329  Dispatcher::instance().link(0, Dispatcher::ReadMask, handleStdin_);
330  Dispatcher::instance().link(0, Dispatcher::ExceptMask, handleStdin_);
331 #endif
332  hoc_interviews = 1;
333  String str;
334  if (session_->style()->find_attribute("first_instance_message", str)) {
335  if (str == "on") {
337  } else {
339  }
340  }
341  }
342  MUTCONSTRUCT(1)
344 }
345 
346 Oc::~Oc() {
347  MUTLOCK
348  if (--refcnt_ == 0) {
349 #if !defined(MINGW)
350  if (reqerr1 && reqerr1->count()) {
351  fprintf(stderr, "total X Errors: %d\n", reqerr1->count());
352  }
353 #endif
354  }
355  MUTUNLOCK
356 }
357 
358 
360  return session_;
361 }
362 
363 int Oc::run(int argc, const char** argv) {
364  return hoc_main1(argc, argv, 0);
365 }
366 
367 int Oc::run(const std::string& buf, bool show_err_mes) {
368  return run(buf.c_str(), show_err_mes);
369 }
370 
371 int Oc::run(const char* buf, bool show_err_mes) {
372  int hem = hoc_execerror_messages;
373  hoc_execerror_messages = show_err_mes;
374  int err{};
375  try_catch_depth_increment tell_children_we_will_catch{};
376  try {
377  err = hoc_oc(buf);
378  } catch (std::exception const& e) {
379  if (show_err_mes) {
380  Fprintf(stderr, "Oc::run: caught exception");
381  std::string_view what{e.what()};
382  if (!what.empty()) {
383  Fprintf(stderr, fmt::format(": {}", what).c_str());
384  }
385  Fprintf(stderr, "\n");
386  }
387  err = 1;
388  }
390  return err;
391 }
392 
393 Symbol* Oc::parseExpr(const char* expr, Symlist** ps) {
394  return hoc_parse_expr(expr, ps);
395 }
396 
397 double Oc::runExpr(Symbol* sym) {
398  return hoc_run_expr(sym);
399 }
400 
401 const char* Oc::name(Symbol* sym) {
402  return sym->name;
403 }
404 
405 bool Oc::setAcceptInput(bool b) {
406  bool old = handleStdin_->acceptInput_;
408  return old;
409 }
410 
411 void Oc::notify_freed(PF pf) {
412  nrn_notify_freed(pf);
413 }
414 
415 void Oc::notify_when_freed(void* p, Observer* ob) {
417 }
418 
421 }
422 
424  stdinSeen_ = false;
425  acceptInput_ = true;
426 }
427 
428 int HandleStdin::inputReady(int fd) {
429  stdinSeen_ = 1;
430  if (fd) {
431  ;
432  }
433  if (acceptInput_) {
434  Oc::getSession()->quit();
435  }
436  return 0;
437 }
438 
439 int HandleStdin::exceptionRaised(int fd) {
440  hoc_interviews = 0;
441  if (fd) {
442  ;
443  }
444  stdinSeen_ = 1;
445  Oc::getSession()->quit();
446  return 0;
447 }
448 
449 void ivoc_cleanup() {}
450 
451 int run_til_stdin() {
452  Session* session = Oc::getSession();
453 #if defined(WIN32)
454  Oc oc;
455  oc.notify();
456 #endif
457 #ifndef WIN32
458  Oc::setStdinSeen(false);
459 #endif
460  session->run();
461  WinDismiss::dismiss_defer(); // in case window was dismissed
462 #ifdef WIN32
463  return 0;
464 #else
465  return Oc::getStdinSeen();
466 #endif
467 }
468 
469 void single_event_run() {
470  Resource::flush();
471  Session* session = Oc::getSession();
472  Event e;
473  // actually run till no more events
474  Oc::setAcceptInput(false);
475  bool dsav = session->done();
476  session->unquit();
477  while (session->pending() && !session->done()) {
478  session->read(e);
479  e.handle();
480  }
481  if (dsav) {
482  session->quit();
483  }
484  Oc::setAcceptInput(true);
486  WinDismiss::dismiss_defer(); // in case window was dismissed
487 }
488 
489 #ifdef MINGW
490 extern void nrniv_bind_call(void);
491 #endif
492 
493 void hoc_notify_iv() {
494  if (hoc_usegui) {
495 #ifdef MINGW
496  if (!nrn_is_gui_thread()) {
497  // allow gui thread to run
498  nrnpy_pass();
499  hoc_pushx(0.);
500  hoc_ret();
501  return;
502  }
503  nrniv_bind_call();
504 #endif
505  Resource::flush();
506  Oc oc;
507  oc.notify();
509  }
510  hoc_pushx(1.);
511  hoc_ret();
512 }
513 
515 
516 void Oc::notify() { // merely a possible change
518  notifyHocValue();
520  if (bbs_poll_ > 0)
521  bbs_handle();
522  WinDismiss::dismiss_defer(); // in case window was dismissed
523 }
524 void Oc::notify_attach(Observer* o) {
526 }
527 void Oc::notify_detach(Observer* o) {
529 }
530 #endif
#define ReqErr
Definition: _defines.h:220
#define Observable
Definition: _defines.h:188
#define Style
Definition: _defines.h:278
#define Event
Definition: _defines.h:105
bool acceptInput_
Definition: ivoc.h:30
virtual int exceptionRaised(int fd)
virtual int inputReady(int fd)
static void keep_updated()
virtual void notify()
Definition: observe.cpp:53
virtual void attach(Observer *)
Definition: observe.cpp:45
virtual void detach(Observer *)
Definition: observe.cpp:49
virtual void update(Observable *)
Definition: observe.h:56
Definition: ivoc.h:36
double runExpr(Symbol *)
static void setStdinSeen(bool i)
Definition: ivoc.h:66
void notify_detach(Observer *)
void notify()
int run(int argc, const char **argv)
Oc()
static Observable * notify_change_
Definition: ivoc.h:87
void notify_attach(Observer *)
void notify_freed(void(*pf)(void *, int))
static Session * session_
Definition: ivoc.h:82
static int refcnt_
Definition: ivoc.h:81
void notify_when_freed(void *p, Observer *)
const char * name(Symbol *)
static bool helpmode_
Definition: ivoc.h:84
void notifyHocValue()
static bool setAcceptInput(bool)
Symbol * parseExpr(const char *, Symlist **=NULL)
void notify_pointer_disconnect(Observer *)
static int getStdinSeen()
Definition: ivoc.h:63
static HandleStdin * handleStdin_
Definition: ivoc.h:83
static Session * getSession()
static void flush()
Definition: resource.cpp:102
static void dismiss_defer()
char * gargstr(int narg)
Definition: code2.cpp:227
int bbs_poll_
Definition: code.cpp:32
void bbs_handle()
Definition: bbssrvmpi.cpp:210
char buf[512]
Definition: init.cpp:13
void hoc_ret()
void notify_pointer_freed(void *pt)
Definition: ivoc.cpp:132
Symbol * hoc_parse_expr(const char *str, Symlist **psymlist)
Definition: code2.cpp:646
int hoc_oc(const char *buf)
Definition: hoc.cpp:1314
double hoc_run_expr(Symbol *sym)
Definition: code2.cpp:638
void nrnpy_pass()
Definition: fileio.cpp:819
void notify_freed(void *p)
Definition: ivoc.cpp:144
#define TRY_GUI_REDIRECT_DOUBLE(name, obj)
Definition: gui-redirect.h:47
int hoc_interviews
Definition: hoc.cpp:1476
int hoc_usegui
Definition: hoc.cpp:121
#define assert(ex)
Definition: hocassrt.h:24
static char * env[]
Definition: inithoc.cpp:259
static int argc
Definition: inithoc.cpp:45
static char ** argv
Definition: inithoc.cpp:46
void notify_freed_val_array(double *p, size_t size)
Definition: ivoc.cpp:152
char * cxx_char_alloc(size_t sz)
Definition: ivoc.cpp:169
void nrn_err_dialog(const char *mes)
Definition: ivoc.cpp:182
static nrn::tool::bimap< double *, Observer * > * pdob
Definition: ivoc.cpp:32
void nrniv_bind_thread()
Definition: ivoc.cpp:176
void nrn_notify_freed(PF pf)
Definition: ivoc.cpp:45
static nrn::tool::bimap< void *, Observer * > * pvob
Definition: ivoc.cpp:31
static identifier_observer_bimap * phob
Definition: ivoc.cpp:35
int nrn_err_dialog_active_
Definition: ivoc.cpp:43
void nrn_notify_when_void_freed(void *p, Observer *ob)
Definition: ivoc.cpp:52
void nrn_notify_when_double_freed(double *p, Observer *ob)
Definition: ivoc.cpp:61
std::vector< PF > FList
Definition: ivoc.cpp:27
static FList * f_list
Definition: ivoc.cpp:29
void nrn_notify_pointer_disconnect(Observer *ob)
Definition: ivoc.cpp:70
void(*)(void *, int) PF
Definition: ivoc.cpp:26
void ivoc_cleanup()
Definition: ocnoiv1.cpp:15
#define Session
Definition: ivocmain.cpp:9
int hoc_print_first_instance
Definition: hoc_oop.cpp:39
void hoc_main1_init(const char *, const char **)
Definition: hoc.cpp:783
int hoc_main1(int, const char **, const char **)
Definition: hoc.cpp:867
void hoc_pushx(double)
Definition: code.cpp:779
int run_til_stdin()
Definition: ivocmain.cpp:761
printf
Definition: extdef.h:5
void notify_handle_dying(non_owning_identifier_without_container p)
Respond to the news that data_handles relying on p are now dead.
Definition: ivoc.cpp:114
void notify_when_handle_dies(data_handle< double > dh, Observer *obs)
Register that obs should be notified when dh dies.
Definition: ivoc.cpp:91
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
Definition: wrap_sprintf.h:14
void single_event_run()
size_t p
s
Definition: multisend.cpp:521
#define MUTCONSTRUCT(mkmut)
Definition: nrnmutdec.h:33
#define MUTDEC
Definition: nrnmutdec.h:31
#define MUTLOCK
Definition: nrnmutdec.h:35
#define MUTUNLOCK
Definition: nrnmutdec.h:36
FILE * hoc_fin
Definition: hoc.cpp:152
HOC interpreter function declarations (included by hocdec.h)
static double done(void *v)
Definition: ocbbs.cpp:251
int hoc_execerror_messages
Definition: hoc.cpp:607
void hoc_notify_iv()
Definition: ocnoiv1.cpp:17
void ivoc_style()
Definition: ocnoiv1.cpp:124
void nrn_shape_update()
Definition: treeset.cpp:915
static const char ** pname(void *v)
Definition: ocpointer.cpp:64
#define NULL
Definition: spdefs.h:105
Definition: model.h:47
char * name
Definition: model.h:61
Definition: hocdec.h:75
non_owning_identifier_without_container identifier() const
Get the identifier used by this handle.
bool refers_to_a_modern_data_structure() const
Query whether this data handle is in "modern" mode.
A non-owning permutation-stable identifier for an entry in a container.
bool find(T const &p, size_t n, T &, O &)
Definition: bimap.hpp:68
void insert(T const &, O const &)
Definition: bimap.hpp:45
void obremove(O const &)
Definition: bimap.hpp:51
void remove(T const &, O const &)
Definition: bimap.hpp:62
Helper type for incrementing/decrementing nrn_try_catch_nest_depth.
Definition: ocjump.h:20
void continue_dialog(const char *label, Window *w=NULL, Coord x=400., Coord y=400.)
int Fprintf(FILE *stream, const char *fmt, Args... args)
Definition: logger.hpp:8