/home/hillier_g/checkout/most4linux/libnetservices/src/linux/service.c

00001 /*
00002  *  Copyright(c) Siemens AG, Muenchen, Germany, 2005, 2006, 2007
00003  *                           Bernhard Walle <bernhard.walle@gmx.de>
00004  *                           Gernot Hillier <gernot.hillier@siemens.com>
00005  *                           All rights reserved.
00006  *
00007  * ----------------------------------------------------------------------------
00008  * The contents of this file are subject to the Mozilla Public License
00009  * Version 1.1 (the "License"); you may not use this file except in
00010  * compliance with the License. You may obtain a copy of the License at
00011  * http://www.mozilla.org/MPL/
00012  * 
00013  * Software distributed under the License is distributed on an "AS IS"
00014  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
00015  * License for the specific language governing rights and limitations
00016  * under the License.
00017  *
00018  * The Original Code is Siemens code.
00019  * 
00020  * The Initial Developer of the Original Code is Siemens AG.
00021  * Portions created by the Initial Developer are Copyright (C) 2005-06
00022  * the Initial Developer. All Rights Reserved.
00023  * ----------------------------------------------------------------------------
00024  */
00025 #include <errno.h>
00026 #include <sys/ioctl.h>
00027 #include <signal.h>
00028 #include <pthread.h>
00029 #include <semaphore.h>
00030 #include <time.h>
00031 #include <assert.h>
00032 
00033 #include <adjust.h>
00034 #include <mostdef1.h>
00035 #include <mostns1.h>
00036 #include <mostnetsdll.h>
00037 #include <par_cp.h>
00038 
00039 #include "global.h"
00040 #include "most-netservice.h"
00041 #include "service.h"
00042 
00043 static pthread_t    service_thread_descriptor;
00044 static sigset_t     old_sigset;
00045 static sem_t        startup_sem;
00046 static sem_t        thread_sem;
00047 
00048 /* inspired by ns_main.c (Coguar example) */
00049 static unsigned int events_mns                  = 0;
00050 
00051 /* -------------------------------------------------------------------------- */
00052 void MostStartUpFinished(void)
00053 {
00054     /* wakeup the main thread after MostStartUp has been called */
00055     sem_post(&startup_sem);
00056 }
00057 
00058 /* -------------------------------------------------------------------------- */
00059 void *service_thread_func(void *cookie)
00060 {
00061     int                 ret;
00062     sigset_t            sig;
00063     struct timespec     next_timeout         = { 0, 0 };
00064     siginfo_t           sinfo;
00065     long long           last_time, cur_time, time_diff;
00066     int                 tmp;
00067     int                 most_service         = 0;
00068 
00069     PRINT_TRACE();
00070 
00071     /* initialize the sigset_t value */
00072     sigemptyset(&sig);
00073     sigaddset(&sig, MOST_RT_SIGNAL);
00074     sigaddset(&sig, MOST_RT_SIGNAL_TIMER);
00075 
00076     /* signal the init function to continue */
00077     sem_post(&thread_sem);
00078 
00079     PRINT_TRACE("Waiting until MostStartUp has been called");
00080 
00081     /* wait until MostStartUp has been called or just continue */
00082     sem_wait(&startup_sem);
00083 
00084     TIME_IN_MS(last_time);
00085         
00086     for (;;) {
00087         PRINT_TRACE("Waiting for a signal, timeout = { %ld, %ld }", next_timeout.tv_sec,
00088                                                                     next_timeout.tv_nsec);
00089 
00090         /* wait for the next interrupt or request */
00091         ret = sigtimedwait(&sig, &sinfo, &next_timeout);
00092         if (ret == -1 && errno != EAGAIN) {
00093             PERR_DEBUG("sigtimedwait error");
00094             continue;
00095         }
00096 
00097         PRINT_TRACE("Signal received, ret = %d, value = %d", ret, sinfo.si_value.sival_int);
00098 
00099         /* now ret == -1 is timeout, all other values are signals */
00100 
00101         /* calculate the difference */
00102         TIME_IN_MS(cur_time);
00103         time_diff = cur_time - last_time;
00104         last_time = cur_time;
00105 
00106         PRINT_TRACE("time_diff = %lld", time_diff);
00107         assert(time_diff >= 0);
00108 
00109         MostTimerIntDiff( (word)time_diff );
00110 
00111         /* calculate the next timeout */
00112         tmp = MostGetMinTimeout();
00113         if (tmp == 0xffff) {
00114             /* wait one second, that should be ok for "infinite" */
00115             next_timeout.tv_sec     = 1;
00116             next_timeout.tv_nsec    = 0;
00117         } else {
00118             next_timeout.tv_sec  = tmp / 1000;
00119             tmp %= 1000;
00120             next_timeout.tv_nsec = tmp * 1000 * 1000;
00121         }
00122 
00123         /* maximum timeout is 1 s */
00124         if (next_timeout.tv_sec > 0) {
00125             next_timeout.tv_sec = 1;
00126             next_timeout.tv_nsec = 0;
00127         }
00128 
00129         /* only timeout, nothing to do, timers are updated */
00130         if (ret == -1 && !most_service) {
00131             continue;
00132         }
00133 
00134         /* clear the events from last time */
00135         events_mns = 0;
00136 
00137         /* now get the event that caued the process to continue */
00138         if (ret == MOST_RT_SIGNAL && sinfo.si_value.sival_int == MNS_INT) {
00139             events_mns |= MNS_E_INT | MNS_E_REQ;
00140         }
00141 
00142         /* timer events */
00143         if (ret == MOST_RT_SIGNAL_TIMER) {
00144             events_mns |= MNS_E_TIMER;
00145         }
00146     
00147         /* pending events */
00148         if (most_service > 0) {
00149             events_mns |= MNS_E_PEN;
00150         }
00151 
00152         /* workaround for recv msg before NET_ON, from MostNetsDll.cpp */
00153         if (MostGetState() != NET_ON) {
00154             events_mns |= MNS_E_TIMER;
00155         }
00156 
00157         /* now any layer I event */
00158         if (events_mns > 0) {
00159             /*
00160              * XXX
00161              * MostNetsDLL.cpp locks the access here, but since no other threads
00162              * are calling MostService, I don't think that is necessary here 
00163              */
00164             pthread_mutex_lock(&g_nets_mutex);
00165             most_service = MostService(0, events_mns);
00166             pthread_mutex_unlock(&g_nets_mutex);
00167         }
00168     }
00169 }
00170 
00171 /* -------------------------------------------------------------------------- */
00172 int service_thread_init(void)
00173 {
00174     int                         ret;
00175     sigset_t                    sig;
00176     struct interrupt_set_arg    interrupt_set = {MOST_RT_SIGNAL, MNS_INT};
00177 
00178     PRINT_TRACE();
00179 
00180     /* initialize the semaphore (in "locked" state) */
00181     sem_init(&startup_sem, 0, 0);
00182     sem_init(&thread_sem, 0, 0);
00183         
00184     /* modify the interrupt mask of the process */
00185     sigemptyset(&sig);
00186     sigaddset(&sig, MOST_RT_SIGNAL);
00187     sigaddset(&sig, MOST_RT_SIGNAL_TIMER);
00188     
00189     ret = sigprocmask(SIG_BLOCK, &sig, &old_sigset);
00190     if (ret != 0) {
00191         PERR_DEBUG("Setting procmask failed");
00192         return E_SIGNAL;
00193     }
00194 
00195     /* register the signal at the driver */
00196     ret = ioctl(g_control_fd, MOST_NETS_IRQ_SET, &interrupt_set);
00197     if (ret < 0) {
00198         PERR_DEBUG("Registering interrupts at the driver failed");
00199         ret = E_IOCTL;
00200         goto out_procmask;
00201     }
00202     
00203     /* start the service thread */
00204     ret = pthread_create(&service_thread_descriptor, NULL, service_thread_func, NULL);
00205     if (ret < 0) {
00206         PERR_DEBUG("Thread creation failed");
00207         ret = E_THREAD;
00208         goto out_ioctl;
00209     }
00210 
00211     /* wait until the service thread has finished his initialization */
00212     sem_wait(&thread_sem);
00213 
00214     return E_SUCCESS;
00215 
00216 out_procmask:
00217     sigprocmask(SIG_SETMASK, &old_sigset, NULL);
00218 out_ioctl:
00219     interrupt_set.sigmask   = 0;
00220     ioctl(g_control_fd, MOST_NETS_IRQ_SET, &interrupt_set);
00221     return ret;
00222 }
00223 
00224 /* -------------------------------------------------------------------------- */
00225 void service_thread_finish(void)
00226 {
00227     struct interrupt_set_arg    interrupt_set = {0, 0};
00228     int                         ret;
00229     
00230     /* deregister the signal of the driver */
00231     ret = ioctl(g_control_fd, MOST_NETS_IRQ_SET, &interrupt_set);
00232     if (ret < 0) {
00233         PERR_DEBUG("Deregistering interrupts at the driver failed");
00234     }
00235 
00236     /* stop the service thread */
00237     ret = pthread_cancel(service_thread_descriptor);
00238     if (ret != 0) {
00239         PERR_DEBUG("Cancelling service thread failed");
00240     }
00241 
00242     /* restore the interrupt mask of the process */ 
00243     ret = sigprocmask(SIG_SETMASK, &old_sigset, NULL);
00244     if (ret != 0) {
00245         PERR_DEBUG("Restoring procmask failed");
00246     }
00247 }
00248 
00249 /* vim: set ts=4 et sw=4: */

Generated on Fri Mar 9 14:48:59 2007 for MOST Adaption Layer for Netservices Library by  doxygen 1.5.0