kinsamanka@3778: /**
kinsamanka@3778:  * Mac OSX specific code
kinsamanka@3778:  **/
kinsamanka@3778: 
kinsamanka@3778: #include <stdio.h>
kinsamanka@3778: #include <string.h>
kinsamanka@3778: #include <time.h>
kinsamanka@3778: #include <signal.h>
kinsamanka@3778: #include <stdlib.h>
kinsamanka@3778: #include <pthread.h>
kinsamanka@3778: #include <locale.h>
kinsamanka@3778: #include <semaphore.h>
kinsamanka@3778: #include <dispatch/dispatch.h>
kinsamanka@3778: 
kinsamanka@3781: static dispatch_semaphore_t Run_PLC;
kinsamanka@3778: 
kinsamanka@3778: long AtomicCompareExchange(long *atomicvar, long compared, long exchange)
kinsamanka@3778: {
kinsamanka@3778:     return __sync_val_compare_and_swap(atomicvar, compared, exchange);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: long long AtomicCompareExchange64(long long *atomicvar, long long compared,
kinsamanka@3778:                                   long long exchange)
kinsamanka@3778: {
kinsamanka@3778:     return __sync_val_compare_and_swap(atomicvar, compared, exchange);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: void PLC_GetTime(IEC_TIME * CURRENT_TIME)
kinsamanka@3778: {
kinsamanka@3778:     struct timespec tmp;
kinsamanka@3778:     clock_gettime(CLOCK_REALTIME, &tmp);
kinsamanka@3778:     CURRENT_TIME->tv_sec = tmp.tv_sec;
kinsamanka@3778:     CURRENT_TIME->tv_nsec = tmp.tv_nsec;
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: dispatch_queue_t queue;
kinsamanka@3778: dispatch_source_t PLC_timer;
kinsamanka@3778: 
kinsamanka@3778: static inline void PLC_timer_cancel(void *arg)
kinsamanka@3778: {
kinsamanka@3778:     dispatch_release(PLC_timer);
kinsamanka@3778:     dispatch_release(queue);
kinsamanka@3778:     exit(0);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: static inline void PLC_timer_notify(void *arg)
kinsamanka@3778: {
kinsamanka@3778:     PLC_GetTime(&__CURRENT_TIME);
kinsamanka@3781:     dispatch_semaphore_signal(Run_PLC);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: void PLC_SetTimer(unsigned long long next, unsigned long long period)
kinsamanka@3778: {
kinsamanka@3778:     if (next == period && next == 0) {
kinsamanka@3778:         dispatch_suspend(PLC_timer);
kinsamanka@3778:     } else {
kinsamanka@3778:         dispatch_time_t start;
kinsamanka@3782:         start = dispatch_walltime(NULL, next);
kinsamanka@3778:         dispatch_source_set_timer(PLC_timer, start, period, 0);
kinsamanka@3778:         dispatch_resume(PLC_timer);
kinsamanka@3778:     }
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: void catch_signal(int sig)
kinsamanka@3778: {
kinsamanka@3778:     signal(SIGINT, catch_signal);
kinsamanka@3778:     printf("Got Signal %d\n", sig);
kinsamanka@3778:     dispatch_source_cancel(PLC_timer);
kinsamanka@3778:     exit(0);
kinsamanka@3778: }
kinsamanka@3778: 
edouard@3947: static unsigned int __debug_tick;
kinsamanka@3778: 
kinsamanka@3778: pthread_t PLC_thread;
kinsamanka@3778: static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER;
kinsamanka@3778: static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER;
kinsamanka@3778: static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER;
kinsamanka@3778: static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
kinsamanka@3778: 
kinsamanka@3778: int PLC_shutdown = 0;
kinsamanka@3778: 
kinsamanka@3778: int ForceSaveRetainReq(void)
kinsamanka@3778: {
kinsamanka@3778:     return PLC_shutdown;
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: void PLC_thread_proc(void *arg)
kinsamanka@3778: {
kinsamanka@3778:     while (!PLC_shutdown) {
kinsamanka@3781:         dispatch_semaphore_wait(Run_PLC, DISPATCH_TIME_FOREVER);
kinsamanka@3778:         __run();
kinsamanka@3778:     }
kinsamanka@3778:     pthread_exit(0);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: #define maxval(a,b) ((a>b)?a:b)
kinsamanka@3778: int startPLC(int argc, char **argv)
kinsamanka@3778: {
kinsamanka@3778:     setlocale(LC_NUMERIC, "C");
kinsamanka@3778: 
kinsamanka@3778:     PLC_shutdown = 0;
kinsamanka@3778: 
kinsamanka@3781:     Run_PLC = dispatch_semaphore_create(0);
kinsamanka@3778: 
kinsamanka@3778:     pthread_create(&PLC_thread, NULL, (void *)&PLC_thread_proc, NULL);
kinsamanka@3778: 
kinsamanka@3778:     pthread_mutex_init(&debug_wait_mutex, NULL);
kinsamanka@3778:     pthread_mutex_init(&debug_mutex, NULL);
kinsamanka@3778:     pthread_mutex_init(&python_wait_mutex, NULL);
kinsamanka@3778:     pthread_mutex_init(&python_mutex, NULL);
kinsamanka@3778: 
kinsamanka@3778:     pthread_mutex_lock(&debug_wait_mutex);
kinsamanka@3778:     pthread_mutex_lock(&python_wait_mutex);
kinsamanka@3778: 
kinsamanka@3778:     queue = dispatch_queue_create("timerQueue", 0);
kinsamanka@3778:     PLC_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
kinsamanka@3778: 
kinsamanka@3778:     dispatch_set_context(PLC_timer, &PLC_timer);
kinsamanka@3778:     dispatch_source_set_event_handler_f(PLC_timer, PLC_timer_notify);
kinsamanka@3778:     dispatch_source_set_cancel_handler_f(PLC_timer, PLC_timer_cancel);
kinsamanka@3778: 
kinsamanka@3778:     if (__init(argc, argv) == 0) {
kinsamanka@3778:         PLC_SetTimer(common_ticktime__, common_ticktime__);
kinsamanka@3778: 
kinsamanka@3778:         /* install signal handler for manual break */
kinsamanka@3778:         signal(SIGINT, catch_signal);
kinsamanka@3778:     } else {
kinsamanka@3778:         return 1;
kinsamanka@3778:     }
kinsamanka@3778:     return 0;
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: int TryEnterDebugSection(void)
kinsamanka@3778: {
kinsamanka@3778:     if (pthread_mutex_trylock(&debug_mutex) == 0) {
kinsamanka@3778:         /* Only enter if debug active */
kinsamanka@3778:         if (__DEBUG) {
kinsamanka@3778:             return 1;
kinsamanka@3778:         }
kinsamanka@3778:         pthread_mutex_unlock(&debug_mutex);
kinsamanka@3778:     }
kinsamanka@3778:     return 0;
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: void LeaveDebugSection(void)
kinsamanka@3778: {
kinsamanka@3778:     pthread_mutex_unlock(&debug_mutex);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: int stopPLC()
kinsamanka@3778: {
kinsamanka@3778:     /* Stop the PLC */
kinsamanka@3778:     PLC_shutdown = 1;
kinsamanka@3781:     dispatch_semaphore_signal(Run_PLC);
kinsamanka@3778:     PLC_SetTimer(0, 0);
kinsamanka@3778:     pthread_join(PLC_thread, NULL);
kinsamanka@3781:     dispatch_release(Run_PLC);
kinsamanka@3781:     Run_PLC = NULL;
kinsamanka@3778:     dispatch_source_cancel(PLC_timer);
kinsamanka@3778:     __cleanup();
kinsamanka@3778:     pthread_mutex_destroy(&debug_wait_mutex);
kinsamanka@3778:     pthread_mutex_destroy(&debug_mutex);
kinsamanka@3778:     pthread_mutex_destroy(&python_wait_mutex);
kinsamanka@3778:     pthread_mutex_destroy(&python_mutex);
kinsamanka@3778:     return 0;
kinsamanka@3778: }
kinsamanka@3778: 
edouard@3947: extern unsigned int __tick;
edouard@3947: 
edouard@3947: int WaitDebugData(unsigned int *tick)
kinsamanka@3778: {
kinsamanka@3778:     int res;
kinsamanka@3778:     if (PLC_shutdown)
kinsamanka@3778:         return 1;
kinsamanka@3778:     /* Wait signal from PLC thread */
kinsamanka@3778:     res = pthread_mutex_lock(&debug_wait_mutex);
kinsamanka@3778:     *tick = __debug_tick;
kinsamanka@3778:     return res;
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: /* Called by PLC thread when debug_publish finished
kinsamanka@3778:  * This is supposed to unlock debugger thread in WaitDebugData*/
kinsamanka@3778: void InitiateDebugTransfer()
kinsamanka@3778: {
kinsamanka@3778:     /* remember tick */
kinsamanka@3778:     __debug_tick = __tick;
kinsamanka@3778:     /* signal debugger thread it can read data */
kinsamanka@3778:     pthread_mutex_unlock(&debug_wait_mutex);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: int suspendDebug(int disable)
kinsamanka@3778: {
kinsamanka@3778:     /* Prevent PLC to enter debug code */
kinsamanka@3778:     pthread_mutex_lock(&debug_mutex);
kinsamanka@3778:     /*__DEBUG is protected by this mutex */
kinsamanka@3778:     __DEBUG = !disable;
kinsamanka@3778:     if (disable)
kinsamanka@3778:         pthread_mutex_unlock(&debug_mutex);
kinsamanka@3778:     return 0;
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: void resumeDebug(void)
kinsamanka@3778: {
kinsamanka@3778:     __DEBUG = 1;
kinsamanka@3778:     /* Let PLC enter debug code */
kinsamanka@3778:     pthread_mutex_unlock(&debug_mutex);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: /* from plc_python.c */
kinsamanka@3778: int WaitPythonCommands(void)
kinsamanka@3778: {
kinsamanka@3778:     /* Wait signal from PLC thread */
kinsamanka@3778:     return pthread_mutex_lock(&python_wait_mutex);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: /* Called by PLC thread on each new python command*/
kinsamanka@3778: void UnBlockPythonCommands(void)
kinsamanka@3778: {
kinsamanka@3778:     /* signal python thread it can read data */
kinsamanka@3778:     pthread_mutex_unlock(&python_wait_mutex);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: int TryLockPython(void)
kinsamanka@3778: {
kinsamanka@3778:     return pthread_mutex_trylock(&python_mutex) == 0;
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: void UnLockPython(void)
kinsamanka@3778: {
kinsamanka@3778:     pthread_mutex_unlock(&python_mutex);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: void LockPython(void)
kinsamanka@3778: {
kinsamanka@3778:     pthread_mutex_lock(&python_mutex);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: struct RT_to_nRT_signal_s {
kinsamanka@3778:     pthread_cond_t WakeCond;
kinsamanka@3778:     pthread_mutex_t WakeCondLock;
kinsamanka@3778: };
kinsamanka@3778: 
kinsamanka@3778: typedef struct RT_to_nRT_signal_s RT_to_nRT_signal_t;
kinsamanka@3778: 
kinsamanka@3778: #define _LogAndReturnNull(text) \
kinsamanka@3778:     {\
kinsamanka@3778:     	char mstr[256] = text " for ";\
kinsamanka@3778:         strncat(mstr, name, 255);\
kinsamanka@3778:         LogMessage(LOG_CRITICAL, mstr, strlen(mstr));\
kinsamanka@3778:         return NULL;\
kinsamanka@3778:     }
kinsamanka@3778: 
kinsamanka@3778: void *create_RT_to_nRT_signal(char *name)
kinsamanka@3778: {
kinsamanka@3778:     RT_to_nRT_signal_t *sig =
kinsamanka@3778:         (RT_to_nRT_signal_t *) malloc(sizeof(RT_to_nRT_signal_t));
kinsamanka@3778: 
kinsamanka@3778:     if (!sig)
kinsamanka@3778:         _LogAndReturnNull("Failed allocating memory for RT_to_nRT signal");
kinsamanka@3778: 
kinsamanka@3778:     pthread_cond_init(&sig->WakeCond, NULL);
kinsamanka@3778:     pthread_mutex_init(&sig->WakeCondLock, NULL);
kinsamanka@3778: 
kinsamanka@3778:     return (void *)sig;
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: void delete_RT_to_nRT_signal(void *handle)
kinsamanka@3778: {
kinsamanka@3778:     RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t *) handle;
kinsamanka@3778: 
kinsamanka@3778:     pthread_cond_destroy(&sig->WakeCond);
kinsamanka@3778:     pthread_mutex_destroy(&sig->WakeCondLock);
kinsamanka@3778: 
kinsamanka@3778:     free(sig);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: int wait_RT_to_nRT_signal(void *handle)
kinsamanka@3778: {
kinsamanka@3778:     int ret;
kinsamanka@3778:     RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t *) handle;
kinsamanka@3778:     pthread_mutex_lock(&sig->WakeCondLock);
kinsamanka@3778:     ret = pthread_cond_wait(&sig->WakeCond, &sig->WakeCondLock);
kinsamanka@3778:     pthread_mutex_unlock(&sig->WakeCondLock);
kinsamanka@3778:     return ret;
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: int unblock_RT_to_nRT_signal(void *handle)
kinsamanka@3778: {
kinsamanka@3778:     RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t *) handle;
kinsamanka@3778:     return pthread_cond_signal(&sig->WakeCond);
kinsamanka@3778: }
kinsamanka@3778: 
kinsamanka@3778: void nRT_reschedule(void)
kinsamanka@3778: {
kinsamanka@3778:     sched_yield();
kinsamanka@3778: }