xbee_err xbee_frameWait(struct xbee_frameBlock *fBlock, struct xbee_con *con, unsigned char *retVal, struct timespec *timeout) { xbee_err ret; struct xbee_frame *frame; int i, o; if (!fBlock || !con) return XBEE_EMISSINGPARAM; ret = XBEE_EINVAL; xbee_mutex_lock(&fBlock->mutex); frame = NULL; for (i = 0, o = fBlock->lastFrame; i < fBlock->numFrames; i++, o--) { if (o < 0) o = fBlock->numFrames - 1; if (fBlock->frame[o].id != con->frameId) continue; if (fBlock->frame[o].status == 0 || fBlock->frame[o].con != con) { ret = XBEE_ESTALE; } else { frame = &fBlock->frame[o]; frame->status |= XBEE_FRAME_STATUS_WAITING; } break; } xbee_mutex_unlock(&fBlock->mutex); if (!frame) return ret; ret = XBEE_ENONE; if (timeout) { if (xsys_sem_timedwait(&frame->sem, timeout)) { if (errno == ETIMEDOUT) { ret = XBEE_ETIMEOUT; } else { ret = XBEE_ESEMAPHORE; } } } else { if (xsys_sem_wait(&frame->sem)) { ret = XBEE_ESEMAPHORE; } } xbee_mutex_lock(&fBlock->mutex); con->frameId = 0; frame->con = NULL; if (frame->status & XBEE_FRAME_STATUS_COMPLETE && ret == XBEE_ENONE) { if (retVal) *retVal = frame->retVal; frame->status = 0; } else { frame->status &= ~XBEE_FRAME_STATUS_WAITING; } xbee_mutex_unlock(&fBlock->mutex); return ret; }
/* the thread monitoring thread... hmm */ void xbee_threadMonitor(struct xbee *xbee) { struct threadInfo *info; void *tRet; int ret; int count, joined, restarted; /* detach self, so that resources are free'd as soon as we return */ xsys_thread_detach_self(); while (xbee->running) { /* wait for 10 seconds, unless prodded */ xsys_sem_timedwait(&xbee->semMonitor, 10, 0); xbee_log(15,"Scanning for dead threads..."); /* keep track of some stats */ count = 0; joined = 0; restarted = 0; /* iterate through each monitored thread */ for (info = NULL; (info = ll_get_next(&xbee->threadList, info)) != NULL;) { /* if thread is supposed to be running */ if (info->running) { #warning TODO - find an alternative to pthread_tryjoin_np() /* try to join with the thread */ if ((ret = xsys_thread_tryjoin(*info->thread, &tRet)) == 0) { /* apparently it died! mark it dead, and report it */ info->running = 0; xbee_log(15,"Thread 0x%X died (%s), it returned 0x%X", info->thread, info->funcName, ret); joined++; } else { /* if the join failed, then find out why (to the best of our ability) and log the details */ if (ret == EBUSY) { xbee_log(10,"xsys_thread_tryjoin(): 0x%X (%s) EBUSY", info->thread, info->funcName); } else if (ret == ETIMEDOUT) { xbee_log(10,"xsys_thread_tryjoin(): 0x%X (%s) ETIMEDOUT", info->thread, info->funcName); } else if (ret == EINVAL) { xbee_log(10,"xsys_thread_tryjoin(): 0x%X (%s) EINVAL", info->thread, info->funcName); } else { xbee_log(10,"xsys_thread_tryjoin(): 0x%X (%s) unknown (%d)", info->thread, info->funcName, ret); } count++; } } /* we need to re-test info->running, because it may have just been marked dead */ if (!info->running) { /* try to restart the thread */ if (xsys_thread_create(info->thread, info->start_routine, info->arg) == 0) { /* success! keep the stats */ restarted++; info->restartCount++; info->running = 1; } else { /* otherwise log the info */ xbee_log(10,"Failed to restart thread (%s)...\n", info->funcName); } } } /* log the stats */ xbee_log(15,"Scan complete! joined/restarted/remain %d/%d/%d threads", joined, restarted, count); } }