Files
QNX/lib/c/iofunc/iofunc_notify.c
2025-08-20 19:02:58 +08:00

180 lines
4.3 KiB
C

/*
* $QNXLicenseC:
* Copyright 2007, QNX Software Systems. All Rights Reserved.
*
* You must obtain a written license from and pay applicable license fees to QNX
* Software Systems before you may reproduce, modify or distribute this software,
* or any work that includes all or part of this software. Free development
* licenses are available for evaluation and non-commercial purposes. For more
* information visit http://licensing.qnx.com or email licensing@qnx.com.
*
* This file may contain contributions from others. Please review this entire
* file for other proprietary rights or license notices, as well as the QNX
* Development Suite License Guide at http://licensing.qnx.com/license-guide/
* for other information.
* $
*/
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/iomsg.h>
#include <sys/iofunc.h>
#include "iofunc.h"
static iofunc_notify_event_t *
notify_lookup(int rcvid, iofunc_notify_t *nop) {
iofunc_notify_event_t *nep;
// A quick match and return will be the normal steady state case.
for(nep = nop->list ; nep ; nep = nep->next) {
if(nep->rcvid == rcvid) {
return nep;
}
}
if((nep = malloc(sizeof(*nep))) == NULL) {
return NULL;
}
nep->next = nop->list;
nop->list = nep;
return nep;
}
int iofunc_notify(resmgr_context_t *ctp, io_notify_t *msg, iofunc_notify_t *nop, int trig, const int *notifycnts, int *armed) {
iofunc_notify_event_t *nep;
unsigned msgflags;
int i, action, dummy, lim, ext;
static const int ones[_NOTIFY_MAXCOND] = {
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1
};
if(notifycnts == NULL) {
notifycnts = ones;
}
lim = 3;
if(armed == NULL) {
armed = &dummy;
}
else if(trig & _NOTIFY_COND_EXTEN) {
lim = min(_NOTIFY_MAXCOND, *armed);
}
*armed = 0;
/*
* Set corresponding _NOTIFY_COND / _NOTIFY_CONDE bits
* to catch clients that set either set in a single test.
*/
trig |= (unsigned)trig << 28;
trig &= ~_NOTIFY_COND_EXTEN;
trig |= (unsigned)trig >> 28;
// Calculate trigger conditions and disarm each source.
action = msg->i.action;
msgflags = msg->i.flags;
ext = msgflags & _NOTIFY_COND_EXTEN;
msgflags &= ~_NOTIFY_COND_EXTEN;
if(action != _NOTIFY_ACTION_TRANARM) {
trig &= msgflags;
} else {
//
// POSIX message queues only allow one transition arm (mq_notify)
// at a time. We apply the rule for all resource managers.
//
for(nep = nop[IOFUNC_NOTIFY_INPUT].list ; nep ; nep = nep->next) {
if(nep->event.sigev_notify != SIGEV_NONE) {
if(nep->scoid != ctp->info.scoid ||
msg->i.event.sigev_notify != SIGEV_NONE) {
return EBUSY;
}
}
}
trig = 0;
}
/*
* trig now contains satisfied events as asked for
* by the client (_NOTIFY_COND* or _NOTIFY_CONDE*).
* We don't change this so that the flags the client
* gets in the reply are the same as it sent. However,
* we'll convert msgflags to the extended set
* (_NOTIFY_CONDE) to facilitate an early out of the loop
* as clients will only ever be looking past the first
* 3 events for poll().
*/
msgflags |= msgflags >> 28;
msgflags &= ((1 << _NOTIFY_MAXCOND) - 1);
/* Lookup a notify entry for each src. */
for(i = 0 ; i < lim && msgflags; i++, msgflags >>= 1, nop++) {
/* Only affect sources specified */
if((msgflags & 1) == 0) {
continue;
}
/* Lookup and create a notify entry if needed. */
if((nep = notify_lookup(ctp->rcvid, nop)) == NULL)
return ENOMEM;
nep->rcvid = ctp->rcvid;
nep->scoid = ctp->info.scoid;
nep->coid = ctp->info.coid;
nep->flags = ext;
/*
* Arm each source if no triggers and not a straight poll,
* otherwise ensured disarmed.
*/
if(trig == 0 && action != _NOTIFY_ACTION_POLL) {
nep->event = msg->i.event;
if(action == _NOTIFY_ACTION_TRANARM) {
nep->cnt = 0;
} else {
nep->cnt = notifycnts[i];
*armed = 1;
}
if(nep->cnt < nop->cnt) {
nop->cnt = nep->cnt;
}
}
else {
SIGEV_NONE_INIT(&nep->event);
nep->cnt = INT_MAX;
}
}
if ((msg->o.flags = trig))
msg->o.flags |= ext;
// A poll tries to return status bits.
if(action & _NOTIFY_ACTION_POLL) { // *_POLL or *_POLLARM
return _RESMGR_PTR(ctp, &msg->o, sizeof(msg->o));
}
if(trig || action != _NOTIFY_ACTION_CONDARM) {
return _RESMGR_PTR(ctp, &msg->o, sizeof(msg->o));
}
return EAGAIN;
}
__SRCVERSION("iofunc_notify.c $Rev: 153052 $");