// // Created by Дмитрий Бахвалов on 13.07.15. // Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved. // #ifndef __HIREDIS_MACOSX_H__ #define __HIREDIS_MACOSX_H__ #include #include "../hiredis.h" #include "../async.h" typedef struct { redisAsyncContext *context; CFSocketRef socketRef; CFRunLoopSourceRef sourceRef; } RedisRunLoop; static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) { if( redisRunLoop != NULL ) { if( redisRunLoop->sourceRef != NULL ) { CFRunLoopSourceInvalidate(redisRunLoop->sourceRef); CFRelease(redisRunLoop->sourceRef); } if( redisRunLoop->socketRef != NULL ) { CFSocketInvalidate(redisRunLoop->socketRef); CFRelease(redisRunLoop->socketRef); } hi_free(redisRunLoop); } return REDIS_ERR; } static void redisMacOSAddRead(void *privdata) { RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); } static void redisMacOSDelRead(void *privdata) { RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); } static void redisMacOSAddWrite(void *privdata) { RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); } static void redisMacOSDelWrite(void *privdata) { RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); } static void redisMacOSCleanup(void *privdata) { RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; freeRedisRunLoop(redisRunLoop); } static void redisMacOSAsyncCallback(CFSocketRef __unused s, CFSocketCallBackType callbackType, CFDataRef __unused address, const void __unused *data, void *info) { redisAsyncContext* context = (redisAsyncContext*) info; switch (callbackType) { case kCFSocketReadCallBack: redisAsyncHandleRead(context); break; case kCFSocketWriteCallBack: redisAsyncHandleWrite(context); break; default: break; } } static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLoop) { redisContext *redisCtx = &(redisAsyncCtx->c); /* Nothing should be attached when something is already attached */ if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR; RedisRunLoop* redisRunLoop = (RedisRunLoop*) hi_calloc(1, sizeof(RedisRunLoop)); if (redisRunLoop == NULL) return REDIS_ERR; /* Setup redis stuff */ redisRunLoop->context = redisAsyncCtx; redisAsyncCtx->ev.addRead = redisMacOSAddRead; redisAsyncCtx->ev.delRead = redisMacOSDelRead; redisAsyncCtx->ev.addWrite = redisMacOSAddWrite; redisAsyncCtx->ev.delWrite = redisMacOSDelWrite; redisAsyncCtx->ev.cleanup = redisMacOSCleanup; redisAsyncCtx->ev.data = redisRunLoop; /* Initialize and install read/write events */ CFSocketContext socketCtx = { 0, redisAsyncCtx, NULL, NULL, NULL }; redisRunLoop->socketRef = CFSocketCreateWithNative(NULL, redisCtx->fd, kCFSocketReadCallBack | kCFSocketWriteCallBack, redisMacOSAsyncCallback, &socketCtx); if( !redisRunLoop->socketRef ) return freeRedisRunLoop(redisRunLoop); redisRunLoop->sourceRef = CFSocketCreateRunLoopSource(NULL, redisRunLoop->socketRef, 0); if( !redisRunLoop->sourceRef ) return freeRedisRunLoop(redisRunLoop); CFRunLoopAddSource(runLoop, redisRunLoop->sourceRef, kCFRunLoopDefaultMode); return REDIS_OK; } #endif