#include "configd.h"
#include "configd_server.h"
#include "session.h"
#include "pattern.h"
#define N_QUICK 32
static void
_notifyWatchers()
{
CFIndex keyCnt;
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
keyCnt = CFSetGetCount(changedKeys);
if (keyCnt == 0)
return;
if (keyCnt > (CFIndex)(sizeof(keys_q) / sizeof(CFStringRef)))
keys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
CFSetGetValues(changedKeys, keys);
while (--keyCnt >= 0) {
CFStringRef changedKey = (CFStringRef)keys[keyCnt];
CFDictionaryRef dict;
CFArrayRef sessionsWatchingKey;
CFIndex watcherCnt;
const void * watchers_q[N_QUICK];
const void ** watchers = watchers_q;
dict = CFDictionaryGetValue(storeData, changedKey);
if ((dict == NULL) || !CFDictionaryContainsKey(dict, kSCDWatchers)) {
continue;
}
sessionsWatchingKey = CFDictionaryGetValue(dict, kSCDWatchers);
watcherCnt = CFArrayGetCount(sessionsWatchingKey);
if (watcherCnt == 0) {
continue;
}
if (watcherCnt > (CFIndex)(sizeof(watchers_q) / sizeof(CFNumberRef)))
watchers = CFAllocatorAllocate(NULL, watcherCnt * sizeof(CFNumberRef), 0);
CFArrayGetValues(sessionsWatchingKey, CFRangeMake(0, watcherCnt), watchers);
while (--watcherCnt >= 0) {
serverSessionRef session;
CFNumberRef watchedSession = watchers[watcherCnt];
session = getSessionNum(watchedSession);
if (session->changedKeys == NULL) {
session->changedKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
if (!CFArrayContainsValue(session->changedKeys,
CFRangeMake(0, CFArrayGetCount(session->changedKeys)),
changedKey)) {
CFArrayAppendValue(session->changedKeys, changedKey);
}
if (needsNotification == NULL)
needsNotification = CFSetCreateMutable(NULL,
0,
&kCFTypeSetCallBacks);
CFSetAddValue(needsNotification, watchedSession);
}
if (watchers != watchers_q) CFAllocatorDeallocate(NULL, watchers);
}
if (keys != keys_q) CFAllocatorDeallocate(NULL, keys);
CFSetRemoveAllValues(changedKeys);
}
static void
_processDeferredRemovals()
{
CFIndex keyCnt;
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
keyCnt = CFSetGetCount(deferredRemovals);
if (keyCnt == 0)
return;
if (keyCnt > (CFIndex)(sizeof(keys_q) / sizeof(CFStringRef)))
keys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
CFSetGetValues(deferredRemovals, keys);
while (--keyCnt >= 0) {
patternRemoveKey((CFStringRef)keys[keyCnt]);
}
if (keys != keys_q) CFAllocatorDeallocate(NULL, keys);
CFSetRemoveAllValues(deferredRemovals);
return;
}
static void
_cleanupRemovedSessionKeys(const void *value, void *context)
{
#pragma unused(context)
CFStringRef removedKey = (CFStringRef)value;
CFRange dRange;
serverSessionRef session;
CFStringRef sessionKey;
CFStringRef key;
CFIndex i;
dRange = CFStringFind(removedKey, CFSTR(":"), 0);
sessionKey = CFStringCreateWithSubstring(NULL,
removedKey,
CFRangeMake(0, dRange.location));
key = CFStringCreateWithSubstring(NULL,
removedKey,
CFRangeMake(dRange.location+dRange.length,
CFStringGetLength(removedKey)-dRange.location-dRange.length));
session = getSessionStr(sessionKey);
if (session == NULL) {
goto done;
}
i = CFArrayGetFirstIndexOfValue(session->sessionKeys,
CFRangeMake(0, CFArrayGetCount(session->sessionKeys)),
key);
if (i == kCFNotFound) {
goto done;
}
CFArrayRemoveValueAtIndex(session->sessionKeys, i);
if (CFArrayGetCount(session->sessionKeys) == 0) {
CFRelease(session->sessionKeys);
session->sessionKeys = NULL;
}
done:
CFRelease(sessionKey);
CFRelease(key);
return;
}
__private_extern__
int
__SCDynamicStorePush(void)
{
_notifyWatchers();
_processDeferredRemovals();
CFSetApplyFunction(removedSessionKeys, _cleanupRemovedSessionKeys, NULL);
CFSetRemoveAllValues(removedSessionKeys);
return kSCStatusOK;
}