pgarg Posted November 2, 2012 Report Posted November 2, 2012 I have a process that is asynchronous/external to SystemC Kernel. I want this process to generate an event to a systemC thread. I read on forums that there is mechanism - "async_request_update" - in system 2.3.0 to do so without corrupting systemC kernel data structures. Is there an example showing how to use this mechanism with OSCI simulator? Thanks Piyush Quote
Philipp A Hartmann Posted November 2, 2012 Report Posted November 2, 2012 There is no real tutorial example available, yet. But you can look at the SystemC regression tests [1], which have a small test included at tests/systemc/1666-2011-compliance/async_request_update/ Greetings from Oldenburg, Philipp [1] http://www.accellera..._2-3_2012-07-02 maehne 1 Quote
David Black Posted November 2, 2012 Report Posted November 2, 2012 struct thread_safe_event_if : sc_core::sc_interface { virtual void notify(sc_core::sc_time delay = SC_ZERO_TIME) = 0; virtual const sc_core::sc_event& default_event(void) const = 0; protected: virtual void update(void) = 0; }; struct thread_safe_event_channel : sc_core::sc_prim_channel, thread_safe_event_if { thread_safe_channel(const char* name); void notify(sc_core::sc_time delay = SC_ZERO_TIME); const sc_core::sc_event& default_event(void) const; protected: virtual void update(void); private: sc_core::sc_event m_event; sc_core::sc_time m_delay; }; // The following may be safely called from outside the SystemC OS thread void thread_safe_event_channel::notify(sc_core::sc_time delay) { m_delay = delay; async_request_update(); } const sc_core::sc_event& thread_safe_event_channel::default_event(void) { return m_event; } virtual void update(void) { m_event.notify(m_delay); } maehne and Philipp A Hartmann 2 Quote
pgarg Posted November 2, 2012 Author Report Posted November 2, 2012 There is no real tutorial example available, yet. But you can look at the SystemC regression tests [1], which have a small test included at tests/systemc/1666-2011-compliance/async_request_update/ Greetings from Oldenburg, Philipp [1] http://www.accellera..._2-3_2012-07-02 Hi Philipp There is no test directory at the path specified by you in systemc_regressions-2.3.0. There is async_reset and async_reset_port but no async_request_update? Regards Piyush Quote
Philipp A Hartmann Posted November 2, 2012 Report Posted November 2, 2012 Oh, sorry. My mistake. The mentioned test has not been part of the 2.3.0 release. There may be some similar test included in the next version of SystemC… For now, you should use David's example as a reference. As in any (host) parallel programming, make sure to properly protect any shared data used in both parts (SystemC and other OS threads). This is not automatically addressed by the async_request_update mechanism. Sorry for the noise, Philipp Quote
David Black Posted November 2, 2012 Report Posted November 2, 2012 I should probably note that using a non-default delay in my example probably does not make sense. Also this example could lose notifications in the sense that if SystemC has not yet serviced a notification, a subsequent notification will simply overwrite the previous one. I generally setup a handshake to ensure the external notifier knows it was received. You could also make a more elaborate notify method that sets/clears a "busy" flag. Be careful to properly protect shared data as Philipp points out. maehne 1 Quote
pgarg Posted November 3, 2012 Author Report Posted November 3, 2012 Hi David and Philipp, Thanks for the example. This example works for me. As David mention that newer notification will simply overwrite previous notification even though time delta for newer is larger than previous notification. This is fine in my case as in my case the time delta is always zero. As long as event can be delivered i am fine. To understand what is meant by shared data, let me elaborate my scenario. The shared data structure in my case is a queue<int>. My external thread looks as following grab pthread_mutex push a value in queue. thread_safe_event.notify(); // from David's example release pthread_mutex SystemC thread while(1) { wait( thread_safe_event.default_event() ); grab pthread_mutex pop all values from queue. release phtread_mutex; process values poped from queue. } Does this cover shared data structure protection for my case or do i need add mutexing within thread_safe_event as well? I am asking the question because in David's example m_delay variable essentially a shared variable between external thread and systemC kernel. external thread writes to variable and systemC kernel reads the variable? Thanks Piyush Quote
Philipp A Hartmann Posted November 5, 2012 Report Posted November 5, 2012 Your solution looks correct. You may want to consider wrapping all of this together in a single "thread-safe input queue" for better encapsulation (and to remove the pthread stuff from your SystemC model). In this case, you can duplicate the queues internally: At protected one for pushing from the outside and a SystemC-local one, where to store the tokens that you need to process within the SystemC part of the model. With a swap of these queues in the update step, you can keep the locking times minimal. Secondly, if you accept a slight extension beyond the plain 1666-2011 standard, you can use sc_scoped_lock and sc_host_mutex instead of the plain pthread_mutex_* API (untested): template< typename T> class async_fifo : public tlm::tlm_blocking_get_if<T> // whatever fits your needs best , public sc_core::sc_prim_channel { sc_core::sc_host_mutex mtx_; // host-locking (e.g. pthread_mutex) sc_core::sc_event written_; std::deque<T> pushq_, popq_; public: async_fifo( const char* nm ) : sc_core::sc_prim_channel(nm) {} /* implement SystemC side interface (e.g. tlm_blocking_get_if) based on pop-queue */ void write_async( T const & v ) { { sc_core::sc_scoped_lock lock( mtx_ ); // critical section pusq_.push_back( v ); // append new value to queue } async_request_update(); } private: void update() { sc_assert( ! popq_.size() ); // make sure, everything is consumed by now { sc_core::sc_scoped_lock lock( mtx_ ); // critical section popq_.swap( pushq_ ); // move all pending tokens to pop-queue } written_.notify( sc_core::SC_ZERO_TIME ); } }; // async_fifo In David's original example, m_delay is indeed not fully protected. But as he already pointed out, you may miss updates (and notifications) anyhow. On the lower level, the compiler should be able to update m_delay in a single instruction, which at least prevents broken values. (You may want to check the assembly for this.) Greetings from Oldenburg, Philipp maehne 1 Quote
katang Posted April 12, 2020 Report Posted April 12, 2020 I have found a complete code example (the location is shown at the bottom), that operates with wait(time); the method proposed by David Black, too. The source code argumentation seems to be reasonable, and the example works with the vast sleep times. It seems to me that for some reason the waiting does not work: the timing of the event makes the synchronization, rather than the event notification sent after the timing is over. The code below produces the output SC started External host thread started Done 1 Done 2 Done 3 Event 1 notified from an external host thread Event 2 notified from an external host thread Got event SC returned With these timings, the second event is not sent at all, and neither of the wait() operations works. It looks that I missed the point, why. #include <systemc> #include <pthread.h> #include <unistd.h> using namespace sc_core; class ThreadSafeEventIf : public sc_interface { virtual void notify(sc_time delay = SC_ZERO_TIME) = 0; virtual const sc_event &default_event(void) const = 0; protected: virtual void update(void) = 0; }; class ThreadSafeEvent : public sc_prim_channel, public ThreadSafeEventIf { public: ThreadSafeEvent(const char *name = ""): event(name) {} void notify(sc_time delay = SC_ZERO_TIME) { this->delay = delay; async_request_update(); } const sc_event &default_event(void) const { return event; } protected: virtual void update(void) { event.notify(delay); } sc_event event; sc_time delay; }; SC_MODULE(Foo) { public: SC_CTOR(Foo) { SC_THREAD(main); SC_METHOD(eventTriggered); sensitive << event; dont_initialize(); std::cout << "SC started\n"; } private: void main() { usleep(1000); // Just for the example, event is added to pending events during this sleep wait(SC_ZERO_TIME); // Schedule (event is evaluated here) std::cout << "Done 1" << std::endl; usleep(1000); // Just for the example // wait(SC_ZERO_TIME); // Schedule (event is evaluated here) wait(1,SC_MS); std::cout << "Done 2" << std::endl; usleep(1 * 1000 * 1000); // Just for the example, event is added to pending events during this sleep std::cout << "Done 3" << std::endl; usleep(2 * 1000 * 1000); // Just for the example, event is added to pending events during this sleep } void eventTriggered() { std::cout << "Got event" << std::endl; } public: ThreadSafeEvent event; }; void *externalHostThread(void *arg) { std::cout << "External host thread started" << std::endl; Foo* foo = (Foo*)(arg); usleep(1500 * 1000); // Just for the example std::cout << "Event 1 notified from an external host thread" << std::endl; foo->event.notify(); usleep(1 * 1000 * 1000); // Just for the example std::cout << "Event 2 notified from an external host thread" << std::endl; foo->event.notify(); } int sc_main(int argc, char *argv[]) { Foo foo("foo"); pthread_t thread; pthread_create(&thread, NULL, externalHostThread, &foo); sc_start(); std::cout << "SC returned" << std::endl; return 0; } //https://stackoverflow.com/questions/49814756/async-request-update-example-in-systemc Quote
katang Posted April 14, 2020 Report Posted April 14, 2020 It looks like I could not understand some essential points of async_request_update() In the sample program below (if the usleep in externalHostThread is commented out, the output is) SC first event notified ThreadSafeNotify called External host thread started Event 1 notified from an external host thread ThreadSafeNotify called Event 2 notified from an external host thread ThreadSafeNotify called ThreadSafeUpdate called Got event in triggered SC returned if it is uncommented, the output is SC started SC first event notified ThreadSafeNotify called External host thread started Event 1 notified from an external host thread ThreadSafeNotify called ThreadSafeUpdate called Got event in triggered SC returned 1/ That is, I do receive the event in the SC_METHOD, but not in the SC_THREAD 2./ If the delay (imitating some useful processing) is active, the 2nd event is not sent out, the thread returns early. Whay do I wrong? Quote
David Black Posted April 15, 2020 Report Posted April 15, 2020 Nothing in SC_THREAD main has any dependence on anything other than time in your example. The external event will have not effect. If you want to see an event, you must be waiting on it. usleep only consumes time. wait(SC_ZERO_TIME) means that the simulation for that portion will wait zero simulated seconds and resume. You should add wait(event) to see it. Quote
katang Posted April 16, 2020 Report Posted April 16, 2020 Sorry, I noticed that I did not insert the new source code So, the output again is SC started SC first event notified ThreadSafeNotify called External host thread started Event 1 notified from an external host thread ThreadSafeNotify called ThreadSafeUpdate called Got event in triggered SC returned I am missing 1/ why the "Event2 notified" line is missing (the thread should terminate only after printing it) As the output is prompt, I guess the thread terminates before reaching printing The update() is called after the second notify(); I expected it is called after the third notify() 2/ I expected a "Got event in main()" message, too #include <systemc> #include <pthread.h> #include <unistd.h> using namespace sc_core; class ThreadSafeEventIf : public sc_interface { virtual void notify(sc_time delay = SC_ZERO_TIME) = 0; virtual const sc_event &default_event(void) const = 0; protected: virtual void update(void) = 0; }; class ThreadSafeEvent : public sc_prim_channel, public ThreadSafeEventIf { public: ThreadSafeEvent(const char *name = ""): event(name) {} void notify(sc_time delay = SC_ZERO_TIME) { this->delay = delay; std::cout << "ThreadSafeNotify called\n"; async_request_update(); } const sc_event &default_event(void) const { return event; } protected: virtual void update(void) { event.notify(delay); std::cout << "ThreadSafeUpdate called\n"; } sc_event event; sc_time delay; }; SC_MODULE(Foo) { public: SC_CTOR(Foo) { SC_THREAD(main); sensitive << event; SC_METHOD(eventTriggered); sensitive << event; dont_initialize(); std::cout << "SC started\n"; std::cout << "SC first event notified\n"; event.notify(); } private: void main() { int i=0; while(i++<3) { wait(); std::cout << "Got event in main()" << std::endl; } } void eventTriggered() { std::cout << "Got event in triggered" << std::endl; } public: ThreadSafeEvent event; }; void *externalHostThread(void *arg) { std::cout << "External host thread started" << std::endl; Foo* foo = (Foo*)(arg); std::cout << "Event 1 notified from an external host thread" << std::endl; foo->event.notify(); usleep(1 * 1000 * 1000); // Just for the example std::cout << "Event 2 notified from an external host thread" << std::endl; foo->event.notify(); } int sc_main(int argc, char *argv[]) { Foo foo("foo"); pthread_t thread; pthread_create(&thread, NULL, externalHostThread, &foo); sc_start(); std::cout << "SC returned" << std::endl; return 0; } Quote
katang Posted April 16, 2020 Report Posted April 16, 2020 I am getting confused. My output is SC started External host thread started Before Event 1 notified from an external host thread ThreadSafeNotify called After Event 1 notified from an external host thread ThreadSafeUpdate called Got event in triggered Got event after next_trigger Got event in triggered again Initializing main() SC returned I expected 1/ main() is executed before anything starts 2/ also the "After usleep" and "Event 2" messages appear #include <systemc> #include <pthread.h> #include <unistd.h> using namespace sc_core; class ThreadSafeEventIf : public sc_interface { virtual void notify(sc_time delay = SC_ZERO_TIME) = 0; virtual const sc_event &default_event(void) const = 0; protected: virtual void update(void) = 0; }; class ThreadSafeEvent : public sc_prim_channel, public ThreadSafeEventIf { public: ThreadSafeEvent(const char *name = ""): event(name) {} void notify(sc_time delay = SC_ZERO_TIME) { this->delay = delay; std::cout << "ThreadSafeNotify called\n"; async_request_update(); } const sc_event &default_event(void) const { return event; } protected: virtual void update(void) { event.notify(delay); std::cout << "ThreadSafeUpdate called\n"; } sc_event event; sc_time delay; }; SC_MODULE(Foo) { public: SC_CTOR(Foo) { SC_THREAD(main); sensitive << event; SC_METHOD(eventTriggered); sensitive << event; dont_initialize(); std::cout << "SC started\n"; } private: void main() { std::cout << "Initializing main()" << std::endl; int i=0; while(i++<3) { wait(); std::cout << "Got event in main()" << std::endl; } } void eventTriggered() { std::cout << "Got event in triggered" << std::endl; next_trigger(10,SC_NS); std::cout << "Got event after next_trigger" << std::endl; next_trigger(); std::cout << "Got event in triggered again" << std::endl; } public: ThreadSafeEvent event; }; void *externalHostThread(void *arg) { std::cout << "External host thread started" << std::endl; Foo* foo = (Foo*)(arg); std::cout << "Before Event 1 notified from an external host thread" << std::endl; foo->event.notify(); std::cout << "After Event 1 notified from an external host thread" << std::endl; usleep(10 * 1000 * 1000); // Just for the example std::cout << "After usleep from an external host thread" << std::endl; std::cout << "Event 2 notified from an external host thread" << std::endl; foo->event.notify(); } int sc_main(int argc, char *argv[]) { Foo foo("foo"); pthread_t thread; pthread_create(&thread, NULL, externalHostThread, &foo); sc_start(); std::cout << "SC returned" << std::endl; return 0; } Quote
katang Posted April 17, 2020 Report Posted April 17, 2020 I wonder what is wrong with using usleep(). If I replace it with a dummy cycle, my output is as shown below Interestingly/importantly: 1/ Initializing main() appears where I expected, and correspondingly the event is received also in main(). However, this seems to be a random event; most of the outputs show that main() is intialized only !after! the events serviced, see the 2nd output. 2/ Event2 is sent and received as expected, but 'main()' persist hiding Maybe async_request_update() was not designed to be used right at the beginning of the simulation and something is not initalized? SC started External host thread initial processing Before Event 1 notified from an external host thread ThreadSafeNotify called Initializing main()After Event 1 notified from an external host thread Event 2 notified from an external host thread ThreadSafeNotify called ThreadSafeUpdate called Got event in triggered Got event after next_trigger(10,SC_NS) Got event in triggered again ThreadSafeUpdate called Got event in triggered Got event after next_trigger(10,SC_NS) Got event in triggered again Got event in main() SC returned SC started External host thread initial processing Before Event 1 notified from an external host thread ThreadSafeNotify called After Event 1 notified from an external host thread Event 2 notified from an external host thread ThreadSafeNotify called ThreadSafeUpdate called Got event in triggered Got event after next_trigger(10,SC_NS) Got event in triggered again Initializing main() SC returned Quote
David Black Posted April 20, 2020 Report Posted April 20, 2020 usleep() does not interact with the systemc kernel at all. SystemC time is different from real time. maehne 1 Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.