static void *handleMessages(void *parm) { /* Main loop for message reception and handling. */ ReceiverThreadParms *rtp = (ReceiverThreadParms *) parm; int segLength; char msgbuf[PMQLSA_MSGSIZE]; unsigned int mqp; /* Priority of rec'd msg. */ iblock(SIGTERM); while (rtp->running) { segLength = mq_receive(rtp->mq, msgbuf, sizeof msgbuf, &mqp); switch (segLength) { case 1: /* Normal stop. */ continue; case -1: putSysErrmsg("pmqlsi failed receiving msg", NULL); pthread_kill(rtp->mainThread, SIGTERM); rtp->running = 0; continue; } if (ltpHandleInboundSegment(msgbuf, segLength) < 0) { putErrmsg("Can't handle inbound segment.", NULL); pthread_kill(rtp->mainThread, SIGTERM); rtp->running = 0; continue; } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } writeErrmsgMemos(); writeMemo("[i] pmqlsi receiver thread has ended."); return NULL; }
static void *sendKeepalives(void *parm) { KeepaliveThreadParms *parms = (KeepaliveThreadParms *) parm; int count = KEEPALIVE_PERIOD; int bytesSent; iblock(SIGTERM); while (*(parms->cloRunning)) { snooze(1); count++; if (count < KEEPALIVE_PERIOD) { continue; } /* Time to send a keepalive. Note that the * interval between keepalive attempts will be * KEEPALIVE_PERIOD plus (if the remote induct * is not reachable) the length of time taken * by TCP to determine that the connection * attempt will not succeed (e.g., 3 seconds). */ count = 0; pthread_mutex_lock(parms->mutex); bytesSent = sendBundleByTCP(parms->socketName, parms->ductSocket, 0, 0, NULL); pthread_mutex_unlock(parms->mutex); if (bytesSent < 0) { shutDownClo(); break; } } return NULL; }
static void *sendKeepalives(void *parm) { KeepaliveThreadParms *parms = (KeepaliveThreadParms *) parm; int keepaliveTimer = 0; int bytesSent; int backoffTimer = BACKOFF_TIMER_START; int backoffTimerCount = 0; unsigned char *buffer; buffer = MTAKE(TCPCLA_BUFSZ); //To send keepalive bundle if (buffer == NULL) { putErrmsg("No memory for TCP buffer in tcpclo.", NULL); return NULL; } iblock(SIGTERM); while (*(parms->cloRunning)) { snooze(1); keepaliveTimer++; if (keepaliveTimer < *(parms->keepalivePeriod)) { continue; } // If the negotiated keep alive interval is 0, then // keep alives will not be sent. if(*(parms->keepalivePeriod) == 0) { continue; } /* Time to send a keepalive. Note that the * interval between keepalive attempts will be * KEEPALIVE_PERIOD plus (if the remote induct * is not reachable) the length of time taken * by TCP to determine that the connection * attempt will not succeed (e.g., 3 seconds). */ keepaliveTimer = 0; pthread_mutex_lock(parms->mutex); bytesSent = sendBundleByTCPCL(parms->socketName, parms->ductSocket, 0, 0, buffer, parms->keepalivePeriod); pthread_mutex_unlock(parms->mutex); /* if the node is unable to establish a TCP connection, * the connection should be tried only after some delay. * */ if(bytesSent == 0) { while((backoffTimerCount < backoffTimer) && (*(parms->ductSocket) < 0)) { snooze(1); backoffTimerCount++; if(!(*(parms->cloRunning))) { break; } } backoffTimerCount = 0; /* keepaliveTimer keeps track of when the keepalive needs * to be sent. This value is set to keepalive period. * That way at the end of backoff period a * keepalive is sent * */ keepaliveTimer = *(parms->keepalivePeriod); if(backoffTimer < BACKOFF_TIMER_LIMIT) { backoffTimer *= 2; } continue; } backoffTimer = BACKOFF_TIMER_START; if (bytesSent < 0) { shutDownClo(); break; } } MRELEASE(buffer); return NULL; }
static void *receiveBundles(void *parm) { /* Main loop for bundle reception thread */ ReceiveThreadParms *parms = (ReceiveThreadParms *) parm; int threadRunning = 1; AcqWorkArea *work; char *buffer; buffer = MTAKE(TCPCLA_BUFSZ); if (buffer == NULL) { putErrmsg("tcpclo receiver can't get TCP buffer", NULL); return NULL; } work = bpGetAcqArea(parms->vduct); if (work == NULL) { putErrmsg("tcpclo receiver can't get acquisition work area", NULL); MRELEASE(buffer); return NULL; } iblock(SIGTERM); while (threadRunning && *(parms->cloRunning)) { if(*(parms->bundleSocket) < 0) { snooze(1); /*Retry later*/ continue; } if (bpBeginAcq(work, 0, NULL) < 0) { putErrmsg("Can't begin acquisition of bundle.", NULL); threadRunning = 0; continue; } switch (receiveBundleByTcpCL(*(parms->bundleSocket), work, buffer)) { case -1: putErrmsg("Can't acquire bundle.", NULL); pthread_mutex_lock(parms->mutex); closesocket(*(parms->bundleSocket)); *(parms->bundleSocket) = -1; pthread_mutex_unlock(parms->mutex); continue; case 0: /* Shutdown message */ /* Go back to the start of the while loop */ pthread_mutex_lock(parms->mutex); closesocket(*(parms->bundleSocket)); *(parms->bundleSocket) = -1; pthread_mutex_unlock(parms->mutex); continue; default: break; /* Out of switch. */ } if (bpEndAcq(work) < 0) { putErrmsg("Can't end acquisition of bundle.", NULL); threadRunning = 0; } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } /* End of receiver thread; release resources. */ bpReleaseAcqArea(work); MRELEASE(buffer); return NULL; }
static int iblock(struct inodesc *idesc, long ilevel, u_int64_t isize) { ufs_daddr_t *ap, *aplim; struct ubuf *bp; int i, n, (*func) (struct inodesc *), nif; u_int64_t sizepb; char pathbuf[MAXPATHLEN + 1], buf[BUFSIZ]; struct uvnode *devvp, *vp; int diddirty = 0; if (idesc->id_type == ADDR) { func = idesc->id_func; n = (*func) (idesc); if ((n & KEEPON) == 0) return (n); } else func = dirscan; if (chkrange(idesc->id_blkno, fragstofsb(fs, idesc->id_numfrags))) return (SKIP); devvp = fs->lfs_devvp; bread(devvp, fsbtodb(fs, idesc->id_blkno), fs->lfs_bsize, NOCRED, 0, &bp); ilevel--; for (sizepb = fs->lfs_bsize, i = 0; i < ilevel; i++) sizepb *= NINDIR(fs); if (isize > sizepb * NINDIR(fs)) nif = NINDIR(fs); else nif = howmany(isize, sizepb); if (idesc->id_func == pass1check && nif < NINDIR(fs)) { aplim = ((ufs_daddr_t *) bp->b_data) + NINDIR(fs); for (ap = ((ufs_daddr_t *) bp->b_data) + nif; ap < aplim; ap++) { if (*ap == 0) continue; (void) sprintf(buf, "PARTIALLY TRUNCATED INODE I=%llu", (unsigned long long)idesc->id_number); if (dofix(idesc, buf)) { *ap = 0; ++diddirty; } } } aplim = ((ufs_daddr_t *) bp->b_data) + nif; for (ap = ((ufs_daddr_t *) bp->b_data); ap < aplim; ap++) { if (*ap) { idesc->id_blkno = *ap; if (ilevel == 0) { /* * dirscan needs lblkno. */ idesc->id_lblkno++; n = (*func) (idesc); } else { n = iblock(idesc, ilevel, isize); } if (n & STOP) { if (diddirty) VOP_BWRITE(bp); else brelse(bp, 0); return (n); } } else { if (idesc->id_type == DATA && isize > 0) { /* An empty block in a directory XXX */ getpathname(pathbuf, sizeof(pathbuf), idesc->id_number, idesc->id_number); pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [3]", pathbuf, (long long)idesc->id_number); if (reply("ADJUST LENGTH") == 1) { vp = vget(fs, idesc->id_number); VTOI(vp)->i_ffs1_size -= isize; isize = 0; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); rerun = 1; inodirty(VTOI(vp)); if (diddirty) VOP_BWRITE(bp); else brelse(bp, 0); return (STOP); } } } isize -= sizepb; } if (diddirty) VOP_BWRITE(bp); else brelse(bp, 0); return (KEEPON); }
/* * Check validity of held blocks in an inode, recursing through all blocks. */ int ckinode(struct ufs1_dinode *dp, struct inodesc *idesc) { ufs_daddr_t *ap, lbn; long ret, n, ndb, offset; struct ufs1_dinode dino; u_int64_t remsize, sizepb; mode_t mode; char pathbuf[MAXPATHLEN + 1]; struct uvnode *vp, *thisvp; if (idesc->id_fix != IGNORE) idesc->id_fix = DONTKNOW; idesc->id_entryno = 0; idesc->id_filesize = dp->di_size; mode = dp->di_mode & IFMT; if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && (dp->di_size < fs->lfs_maxsymlinklen || (fs->lfs_maxsymlinklen == 0 && dp->di_blocks == 0)))) return (KEEPON); dino = *dp; ndb = howmany(dino.di_size, fs->lfs_bsize); thisvp = vget(fs, idesc->id_number); for (lbn = 0; lbn < NDADDR; lbn++) { ap = dino.di_db + lbn; if (thisvp) idesc->id_numfrags = numfrags(fs, VTOI(thisvp)->i_lfs_fragsize[lbn]); else { if (--ndb == 0 && (offset = blkoff(fs, dino.di_size)) != 0) { idesc->id_numfrags = numfrags(fs, fragroundup(fs, offset)); } else idesc->id_numfrags = fs->lfs_frag; } if (*ap == 0) { if (idesc->id_type == DATA && ndb >= 0) { /* An empty block in a directory XXX */ getpathname(pathbuf, sizeof(pathbuf), idesc->id_number, idesc->id_number); pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [1]", pathbuf, (long long)idesc->id_number); if (reply("ADJUST LENGTH") == 1) { vp = vget(fs, idesc->id_number); dp = VTOD(vp); dp->di_size = (ap - &dino.di_db[0]) * fs->lfs_bsize; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); rerun = 1; inodirty(VTOI(vp)); } else break; } continue; } idesc->id_blkno = *ap; idesc->id_lblkno = ap - &dino.di_db[0]; if (idesc->id_type == ADDR) { ret = (*idesc->id_func) (idesc); } else ret = dirscan(idesc); if (ret & STOP) return (ret); } idesc->id_numfrags = fs->lfs_frag; remsize = dino.di_size - fs->lfs_bsize * NDADDR; sizepb = fs->lfs_bsize; for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { if (*ap) { idesc->id_blkno = *ap; ret = iblock(idesc, n, remsize); if (ret & STOP) return (ret); } else { if (idesc->id_type == DATA && remsize > 0) { /* An empty block in a directory XXX */ getpathname(pathbuf, sizeof(pathbuf), idesc->id_number, idesc->id_number); pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [2]", pathbuf, (long long)idesc->id_number); if (reply("ADJUST LENGTH") == 1) { vp = vget(fs, idesc->id_number); dp = VTOD(vp); dp->di_size -= remsize; remsize = 0; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); rerun = 1; inodirty(VTOI(vp)); break; } else break; } } sizepb *= NINDIR(fs); remsize -= sizepb; } return (KEEPON); }
int ckinode(struct ufs1_dinode *dp, struct inodesc *idesc) { ufs_daddr_t *ap; int ret; long n, ndb, offset; struct ufs1_dinode dino; quad_t remsize, sizepb; mode_t mode; char pathbuf[MAXPATHLEN + 1]; if (idesc->id_fix != IGNORE) idesc->id_fix = DONTKNOW; idesc->id_entryno = 0; idesc->id_filesize = dp->di_size; mode = dp->di_mode & IFMT; if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && dp->di_size < (unsigned)sblock.fs_maxsymlinklen)) return (KEEPON); dino = *dp; ndb = howmany(dino.di_size, sblock.fs_bsize); for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) idesc->id_numfrags = numfrags(&sblock, fragroundup(&sblock, offset)); else idesc->id_numfrags = sblock.fs_frag; if (*ap == 0) { if (idesc->id_type == DATA && ndb >= 0) { /* An empty block in a directory XXX */ getpathname(pathbuf, idesc->id_number, idesc->id_number); pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", pathbuf); if (reply("ADJUST LENGTH") == 1) { dp = ginode(idesc->id_number); dp->di_size = (ap - &dino.di_db[0]) * sblock.fs_bsize; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); rerun = 1; inodirty(); } } continue; } idesc->id_blkno = *ap; if (idesc->id_type == ADDR) ret = (*idesc->id_func)(idesc); else ret = dirscan(idesc); if (ret & STOP) return (ret); } idesc->id_numfrags = sblock.fs_frag; remsize = dino.di_size - sblock.fs_bsize * NDADDR; sizepb = sblock.fs_bsize; for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { if (*ap) { idesc->id_blkno = *ap; ret = iblock(idesc, n, remsize); if (ret & STOP) return (ret); } else { if (idesc->id_type == DATA && remsize > 0) { /* An empty block in a directory XXX */ getpathname(pathbuf, idesc->id_number, idesc->id_number); pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", pathbuf); if (reply("ADJUST LENGTH") == 1) { dp = ginode(idesc->id_number); dp->di_size -= remsize; remsize = 0; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); rerun = 1; inodirty(); break; } } } sizepb *= NINDIR(&sblock); remsize -= sizepb; } return (KEEPON); }
static int iblock(struct inodesc *idesc, long ilevel, quad_t isize) { ufs_daddr_t *ap; ufs_daddr_t *aplim; struct bufarea *bp; int i, n, (*func)(), nif; quad_t sizepb; char buf[BUFSIZ]; char pathbuf[MAXPATHLEN + 1]; struct ufs1_dinode *dp; if (idesc->id_type == ADDR) { func = idesc->id_func; if (((n = (*func)(idesc)) & KEEPON) == 0) return (n); } else func = dirscan; if (chkrange(idesc->id_blkno, idesc->id_numfrags)) return (SKIP); bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); ilevel--; for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) sizepb *= NINDIR(&sblock); nif = howmany(isize , sizepb); if (nif > NINDIR(&sblock)) nif = NINDIR(&sblock); if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { if (*ap == 0) continue; sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", (u_long)idesc->id_number); if (dofix(idesc, buf)) { *ap = 0; dirty(bp); } } flush(fswritefd, bp); } aplim = &bp->b_un.b_indir[nif]; for (ap = bp->b_un.b_indir; ap < aplim; ap++) { if (*ap) { idesc->id_blkno = *ap; if (ilevel == 0) n = (*func)(idesc); else n = iblock(idesc, ilevel, isize); if (n & STOP) { bp->b_flags &= ~B_INUSE; return (n); } } else { if (idesc->id_type == DATA && isize > 0) { /* An empty block in a directory XXX */ getpathname(pathbuf, idesc->id_number, idesc->id_number); pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", pathbuf); if (reply("ADJUST LENGTH") == 1) { dp = ginode(idesc->id_number); dp->di_size -= isize; isize = 0; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); rerun = 1; inodirty(); bp->b_flags &= ~B_INUSE; return(STOP); } } } isize -= sizepb; } bp->b_flags &= ~B_INUSE; return (KEEPON); }
int ckinode(union dinode *dp, struct inodesc *idesc) { off_t remsize, sizepb; int i, offset, ret; union dinode dino; ufs2_daddr_t ndb; mode_t mode; char pathbuf[MAXPATHLEN + 1]; if (idesc->id_fix != IGNORE) idesc->id_fix = DONTKNOW; idesc->id_lbn = -1; idesc->id_entryno = 0; idesc->id_filesize = DIP(dp, di_size); mode = DIP(dp, di_mode) & IFMT; if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && DIP(dp, di_size) < (unsigned)sblock.fs_maxsymlinklen)) return (KEEPON); if (sblock.fs_magic == FS_UFS1_MAGIC) dino.dp1 = dp->dp1; else dino.dp2 = dp->dp2; ndb = howmany(DIP(&dino, di_size), sblock.fs_bsize); for (i = 0; i < NDADDR; i++) { idesc->id_lbn++; if (--ndb == 0 && (offset = blkoff(&sblock, DIP(&dino, di_size))) != 0) idesc->id_numfrags = numfrags(&sblock, fragroundup(&sblock, offset)); else idesc->id_numfrags = sblock.fs_frag; if (DIP(&dino, di_db[i]) == 0) { if (idesc->id_type == DATA && ndb >= 0) { /* An empty block in a directory XXX */ getpathname(pathbuf, idesc->id_number, idesc->id_number); pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", pathbuf); if (reply("ADJUST LENGTH") == 1) { dp = ginode(idesc->id_number); DIP_SET(dp, di_size, i * sblock.fs_bsize); printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); rerun = 1; inodirty(); } } continue; } idesc->id_blkno = DIP(&dino, di_db[i]); if (idesc->id_type != DATA) ret = (*idesc->id_func)(idesc); else ret = dirscan(idesc); if (ret & STOP) return (ret); } idesc->id_numfrags = sblock.fs_frag; remsize = DIP(&dino, di_size) - sblock.fs_bsize * NDADDR; sizepb = sblock.fs_bsize; for (i = 0; i < NIADDR; i++) { sizepb *= NINDIR(&sblock); if (DIP(&dino, di_ib[i])) { idesc->id_blkno = DIP(&dino, di_ib[i]); ret = iblock(idesc, i + 1, remsize, BT_LEVEL1 + i); if (ret & STOP) return (ret); } else { idesc->id_lbn += sizepb / sblock.fs_bsize; if (idesc->id_type == DATA && remsize > 0) { /* An empty block in a directory XXX */ getpathname(pathbuf, idesc->id_number, idesc->id_number); pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", pathbuf); if (reply("ADJUST LENGTH") == 1) { dp = ginode(idesc->id_number); DIP_SET(dp, di_size, DIP(dp, di_size) - remsize); remsize = 0; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); rerun = 1; inodirty(); break; } } } remsize -= sizepb; } return (KEEPON); }
static int iblock(struct inodesc *idesc, long ilevel, off_t isize, int type) { struct bufarea *bp; int i, n, (*func)(struct inodesc *), nif; off_t sizepb; char buf[BUFSIZ]; char pathbuf[MAXPATHLEN + 1]; union dinode *dp; if (idesc->id_type != DATA) { func = idesc->id_func; if (((n = (*func)(idesc)) & KEEPON) == 0) return (n); } else func = dirscan; if (chkrange(idesc->id_blkno, idesc->id_numfrags)) return (SKIP); bp = getdatablk(idesc->id_blkno, sblock.fs_bsize, type); ilevel--; for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) sizepb *= NINDIR(&sblock); if (howmany(isize, sizepb) > NINDIR(&sblock)) nif = NINDIR(&sblock); else nif = howmany(isize, sizepb); if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { for (i = nif; i < NINDIR(&sblock); i++) { if (IBLK(bp, i) == 0) continue; (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", (u_long)idesc->id_number); if (preen) { pfatal("%s", buf); } else if (dofix(idesc, buf)) { IBLK_SET(bp, i, 0); dirty(bp); } } flush(fswritefd, bp); } for (i = 0; i < nif; i++) { if (ilevel == 0) idesc->id_lbn++; if (IBLK(bp, i)) { idesc->id_blkno = IBLK(bp, i); if (ilevel == 0) n = (*func)(idesc); else n = iblock(idesc, ilevel, isize, type); if (n & STOP) { bp->b_flags &= ~B_INUSE; return (n); } } else { if (idesc->id_type == DATA && isize > 0) { /* An empty block in a directory XXX */ getpathname(pathbuf, idesc->id_number, idesc->id_number); pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", pathbuf); if (reply("ADJUST LENGTH") == 1) { dp = ginode(idesc->id_number); DIP_SET(dp, di_size, DIP(dp, di_size) - isize); isize = 0; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); rerun = 1; inodirty(); bp->b_flags &= ~B_INUSE; return(STOP); } } } isize -= sizepb; } bp->b_flags &= ~B_INUSE; return (KEEPON); }
static void *sendBundles(void *parm) { /* Main loop for single bundle transmission thread * serving all BRS sockets. */ SenderThreadParms *parms = (SenderThreadParms *) parm; unsigned char *buffer; Outduct outduct; Sdr sdr; Outflow outflows[3]; int i; Object bundleZco; BpExtendedCOS extendedCOS; char destDuctName[MAX_CL_DUCT_NAME_LEN + 1]; unsigned int bundleLength; int ductNbr; int bytesSent; int failedTransmissions = 0; buffer = MTAKE(TCPCLA_BUFSZ); if (buffer == NULL) { putErrmsg("No memory for TCP buffer in brsscla.", NULL); return terminateSenderThread(parms); } sdr = getIonsdr(); sdr_read(sdr, (char *) &outduct, sdr_list_data(sdr, parms->vduct->outductElt), sizeof(Outduct)); memset((char *) outflows, 0, sizeof outflows); outflows[0].outboundBundles = outduct.bulkQueue; outflows[1].outboundBundles = outduct.stdQueue; outflows[2].outboundBundles = outduct.urgentQueue; for (i = 0; i < 3; i++) { outflows[i].svcFactor = 1 << i; } /* Can now begin transmitting to clients. */ iblock(SIGTERM); while (!(sm_SemEnded(parms->vduct->semaphore))) { if (bpDequeue(parms->vduct, outflows, &bundleZco, &extendedCOS, destDuctName) < 0) { break; } if (bundleZco == 0) /* Interrupted. */ { continue; } bundleLength = zco_length(sdr, bundleZco); ductNbr = atoi(destDuctName); if (ductNbr >= parms->baseDuctNbr && ductNbr <= parms->lastDuctNbr && parms->brsSockets[(i = ductNbr - parms->baseDuctNbr)] != -1) { bytesSent = sendBundleByTCP(NULL, parms->brsSockets + i, bundleLength, bundleZco, buffer); if (bytesSent < 0) { putErrmsg("Can't send bundle.", NULL); break; } if (bytesSent < bundleLength) { failedTransmissions++; } } else /* Can't send it; just discard it. */ { sdr_begin_xn(sdr); zco_destroy_reference(sdr, bundleZco); if (sdr_end_xn(sdr) < 0) { putErrmsg("Can't destroy ZCO reference.", NULL); break; } } /* Make sure other tasks have a chance to run. */ sm_TaskYield(); } pthread_kill(brssclaMainThread(0), SIGTERM); writeMemoNote("[i] brsscla outduct has ended", itoa(failedTransmissions)); MRELEASE(buffer); return terminateSenderThread(parms); }