/* * Copyright (C) 2008-2010 Philippe Gerum . * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * Watchdog support. * * Not shareable (we can't tell whether the handler would always be * available in all processes). */ #include #include #include #include #include #include #include "wdLib.h" #include "tickLib.h" #define wd_magic 0x3a4b5c6d static struct wind_wd *get_wd(WDOG_ID wdog_id) { struct wind_wd *wd = (struct wind_wd *)wdog_id; if (wd == NULL || ((intptr_t)wd & (sizeof(intptr_t)-1)) != 0) return NULL; if (wd->magic != wd_magic) return NULL; if (timerobj_lock(&wd->tmobj)) return NULL; return wd->magic != wd_magic ? NULL : wd; } static inline void put_wd(struct wind_wd *wd) { timerobj_unlock(&wd->tmobj); } static void watchdog_handler(struct timerobj *tmobj) { struct wind_wd *wd = container_of(tmobj, struct wind_wd, tmobj); wd->handler(wd->arg); } WDOG_ID wdCreate(void) { struct wind_wd *wd; struct service svc; int ret; CANCEL_DEFER(svc); wd = pvmalloc(sizeof(*wd)); if (wd == NULL) goto fail; ret = timerobj_init(&wd->tmobj); if (ret) { pvfree(wd); fail: errno = S_memLib_NOT_ENOUGH_MEMORY; wd = NULL; goto out; } wd->magic = wd_magic; out: CANCEL_RESTORE(svc); return (WDOG_ID)wd; } STATUS wdDelete(WDOG_ID wdog_id) { struct wind_wd *wd; struct service svc; int ret = OK; CANCEL_DEFER(svc); wd = get_wd(wdog_id); if (wd == NULL) { errno = S_objLib_OBJ_ID_ERROR; ret = ERROR; goto out; } timerobj_destroy(&wd->tmobj); wd->magic = ~wd_magic; pvfree(wd); out: CANCEL_RESTORE(svc); return ret; } STATUS wdStart(WDOG_ID wdog_id, int delay, void (*handler)(long), long arg) { struct itimerspec it; struct service svc; struct wind_wd *wd; int ret; CANCEL_DEFER(svc); wd = get_wd(wdog_id); if (wd == NULL) goto objid_error; wd->handler = handler; wd->arg = arg; clockobj_ticks_to_timeout(&wind_clock, delay, &it.it_value); it.it_interval.tv_sec = 0; it.it_interval.tv_nsec = 0; ret = timerobj_start(&wd->tmobj, watchdog_handler, &it); if (ret) { objid_error: CANCEL_RESTORE(svc); errno = S_objLib_OBJ_ID_ERROR; return ERROR; } CANCEL_RESTORE(svc); return OK; } STATUS wdCancel(WDOG_ID wdog_id) { struct wind_wd *wd; struct service svc; int ret; CANCEL_DEFER(svc); wd = get_wd(wdog_id); if (wd == NULL) goto objid_error; ret = timerobj_stop(&wd->tmobj); if (ret) { objid_error: CANCEL_RESTORE(svc); errno = S_objLib_OBJ_ID_ERROR; return ERROR; } CANCEL_RESTORE(svc); return OK; }