CFReadStreamHasBytesAvailable polling - best practices - iphone

I'm currently polling my CFReadStream for new data with CFReadStreamHasBytesAvailable.
(First, some background: I'm doing my own threading and I don't want/need to mess with runloop stuff, so the client callback stuff doesn't really apply here).
My question is: what are accepted practices for polling?
Apple's documentation on the subject doesn't seem too helpful.
They recommend to "do something else while you wait". I'm currently just doing something along the lines of:
while(!done)
{
if(CFReadStreamHasBytesAvailable(readStream))
{
CFReadStreamRead(...) ... bla bla bla
} else {
usleep(3600); // I made this up
sched_yield(); // also made this up
continue;
}
}
Is the usleep and the sched_yield "good enough"? In there a "good" number to sleep for in usleep?
(Also: yes, because this is running in my own thread, I could just block on CFReadStreamRead - which would be great but I'm also trying to snag upload progress as well as download progress, so blocking there wouldn't help...).
Any insight would be much appreciated - thanks!

I think this question is a bit of a paradox because you're asking what the best practices are for doing something that's intrinsically not a best practice ;)
When there's a perfectly good method for blocking on network I/O, any compromise that causes you to poll instead is by definition not the best practice.
That said, if you do poll I think it might be more appropriate to "run the runloop until date" on your thread, instead of using whatever posix sleep or yield method you're imagining. Remember that each thread gets its own runloop, so essentially by running the runloop you're allowing Apple to employ its concept of best practices for blocking until a future date.
As for the time delay, I don't know if you'll get a definitive answer for what a good time is. It's a tradeoff between peppering the CPU with polling cycles vs. being stuck in the runloop for a little while when I/O is ready to be read from the network.
Ideally I think I would refocus your efforts on making this work using I/O blocking calls, but if you stick with the poll & idle technique, don't fret too much about the specific delay time. Just pick something that works and doesn't seem to impact performance negatively in either direction.
(Also, I'd like to clarify that I'm not too religious about the polling vs. blocking thing, I'm only stressing its value because you're obviously in search of an elevated solution).

When doing manual CFStream based connections on a separate thread (for custom things like bandwidth monitoring and throttling), I use a combination of CFReadStreamScheduleWithRunLoop, CFRunLoopRunInMode and CFReadStreamSetClient. Basically I run for 0.25 seconds and then check stream status. The client callback also gets notified on its own as well. This allows me to periodically check read status and do some custom behavior but rely mostly on (stream) events.
static const CFOptionFlags kMyNetworkEvents =
kCFStreamEventOpenCompleted
| kCFStreamEventHasBytesAvailable
| kCFStreamEventEndEncountered
| kCFStreamEventErrorOccurred;
static void MyStreamCallBack(CFReadStreamRef readStream, CFStreamEventType type, void *clientCallBackInfo) {
[(id)clientCallBackInfo _handleNetworkEvent:type];
}
- (void)connect {
...
CFStreamClientContext streamContext = {0, self, NULL, NULL, NULL};
BOOL success = CFReadStreamSetClient(readStream_, kMyNetworkEvents, MyStreamCallBack, &streamContext);
CFReadStreamScheduleWithRunLoop(readStream_, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
if (!CFReadStreamOpen(readStream_)) {
// Notify error
}
while(!cancelled_ && !finished_) {
SInt32 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, NO);
if (result == kCFRunLoopRunStopped || result == kCFRunLoopRunFinished) {
break;
}
if (([NSDate timeIntervalSinceReferenceDate] - lastRead_) > MyConnectionTimeout) {
// Call timed out
break;
}
// Also handle stream status CFStreamStatus status = CFReadStreamGetStatus(readStream_);
if (![self _handleStreamStatus:status]) break;
}
CFRunLoopStop(CFRunLoopGetCurrent());
CFReadStreamSetClient(readStream_, 0, NULL, NULL);
CFReadStreamUnscheduleFromRunLoop(readStream_, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
CFReadStreamClose(readStream_);
}
- (void)_handleNetworkEvent:(CFStreamEventType)type {
switch(type) {
case kCFStreamEventOpenCompleted:
// Notify connected
break;
case kCFStreamEventHasBytesAvailable:
[self _handleBytes];
break;
case kCFStreamEventErrorOccurred:
[self _handleError];
break;
case kCFStreamEventEndEncountered:
[self _handleBytes];
[self _handleEnd];
break;
default:
Debug(#"Received unexpected CFStream event (%d)", type);
break;
}
}

Related

UDP server consuming high CPU

I am observing high CPU usage in my UDP server implementation which runs an infinite loop expecting 15 1.5KB packets every milliseconds. It looks like below:
struct RecvContext
{
enum { BufferSize = 1600 };
RecvContext()
{
senderSockAddrLen = sizeof(sockaddr_storage);
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
memset(&sendersSockAddr, 0, sizeof(sockaddr_storage));
buffer.clear();
buffer.resize(BufferSize);
wsabuf.buf = (char*)buffer.data();
wsabuf.len = ULONG(buffer.size());
}
void CloseEventHandle()
{
if (overlapped.hEvent != INVALID_HANDLE_VALUE)
{
CloseHandle(overlapped.hEvent);
overlapped.hEvent = INVALID_HANDLE_VALUE;
}
}
OVERLAPPED overlapped;
int senderSockAddrLen;
sockaddr_storage sendersSockAddr;
std::vector<uint8_t> buffer;
WSABUF wsabuf;
};
void Receive()
{
DWORD flags = 0, bytesRecv = 0;
SOCKET sockHandle =...;
while (//stopping condition//)
{
std::shared_ptr<RecvContext> _recvContext = std::make_shared<IO::RecvContext>();
if (SOCKET_ERROR == WSARecvFrom(sockHandle, &_recvContext->wsabuf, 1, nullptr, &flags, (sockaddr*)&_recvContext->sendersSockAddr,
(LPINT)&_recvContext->senderSockAddrLen, &_recvContext->overlapped, nullptr))
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
//error
}
else
{
if (WSA_WAIT_FAILED == WSAWaitForMultipleEvents(1, &_recvContext->overlapped.hEvent, FALSE, INFINITE, FALSE))
{
//error
}
if (!WSAGetOverlappedResult(sockHandle, &_recvContext->overlapped, &bytesRecv, FALSE, &flags))
{
//error
}
}
}
_recvContext->CloseEventHandle();
// async task to process _recvContext->buffer
}
}
The cpu consumption for this udp server is very high even when the packets are not being processed post receipt. How can the cpu consumption be improved here?
You've chosen about the most inefficient combination of mechanisms imaginable.
Why use overlapped I/O if you're only going to pend one operation and then wait for it complete?
Why use an event, which is about the slowest notification scheme that Windows has.
Why do you only pend one operation at a time? You're forcing the implementation to stash datagrams in its own buffers and then copy them into yours.
Why do you post the receive operation right before you're going to wait for it to complete rather than right after the previous one completes?
Why do you create a new receive context each time instead of re-using the existing buffer, event, and so on?
Use IOCP. Windows events are very slow and heavy.
Post lots of operations. You want the operating system to be able to put the datagram right in your buffer rather than having to allocate another buffer that it copies data into and out of.
Re-use your buffers and allocate all your receive buffers from a contiguous pool rather than fragmenting them throughout process memory. The memory used for your buffers has to be pinned and you want to minimize the amount of pinning needed.
Re-post operations as soon as they complete. Don't process them and then re-post. There's no reason to delay starting the operation. You can probably ignore this if you followed all the other suggestions because you wouldn't have a "spare" buffer to post anyway.
Alternatively, you can probably get away with having a thread that spins on a blocking receive operation. Just make sure your code has a loop that is as tight as possible, posting a different (already-allocated) buffer as soon as it returns after dispatching another thread to process the buffer it just filled with the receive operation.

Async sockets in D

Okay this is my first question here on Stack Overflow, so bare over with it if I'm not asking properly.
Basically I'm trying to code some asynchronous sockets using std.socket, but I'm not sure if I've understood the concept correct. I've only ever worked with asynchronous sockets in C# and in D it seem to be on a much lower level. I've researched a lot and looked up a lot of code, documentation etc. both for D and C/C++ to get an understanding, however I'm not sure if I understand the concept correctly and if any of you have some examples. I tried looking at splat, but it's very outdated and vibe seems to be too complex just for a simple asynchronous socket wrapper.
If I understood correctly there is no poll() function in std.socket so you'd have to use SocketSet with a single socket on select() to poll the status of the socket right?
So basically how I'd go about handling the sockets is polling to get the read status of the socket and if it has a success (value > 0) then I can call receive() which will return 0 for disconnection else the received value, but I'd have to keep doing this until the expected bytes are received.
Of course the socket is set to nonblocked!
Is that correct?
Here is the code I've made up so far.
void HANDLE_READ()
{
while (true)
{
synchronized
{
auto events = cast(AsyncObject[int])ASYNC_EVENTS_READ;
foreach (asyncObject; events)
{
int poll = pollRecv(asyncObject.socket.m_socket);
switch (poll)
{
case 0:
{
throw new SocketException("The socket had a time out!");
continue;
}
default:
{
if (poll <= -1)
{
throw new SocketException("The socket was interrupted!");
continue;
}
int recvGetSize = (asyncObject.socket.m_readBuffer.length - asyncObject.socket.readSize);
ubyte[] recvBuffer = new ubyte[recvGetSize];
int recv = asyncObject.socket.m_socket.receive(recvBuffer);
if (recv == 0)
{
removeAsyncObject(asyncObject.event_id, true);
asyncObject.socket.disconnect();
continue;
}
asyncObject.socket.m_readBuffer ~= recvBuffer;
asyncObject.socket.readSize += recv;
if (asyncObject.socket.readSize == asyncObject.socket.expectedReadSize)
{
removeAsyncObject(asyncObject.event_id, true);
asyncObject.event(asyncObject.socket);
}
break;
}
}
}
}
}
}
So basically how I'd go about handling the sockets is polling to get the read status of the socket
Not quite right. Usually, the idea is to build an event loop around select, so that your application is idle as long as there are no network or timer events that need to be handled. With polling, you'd have to check for new events continuously or on a timer, which leads to wasted CPU cycles, and events getting handled a bit later than they occur.
In the event loop, you populate the SocketSets with sockets whose events you are interested in. If you want to be notified of new received data on a socket, it goes to the "readable" set. If you have data to send, the socket should be in the "writable" set. And all sockets should be on the "error" set.
select will then block (sleep) until an event comes in, and fill the SocketSets with the sockets which have actionable events. Your application can then respond to them appropriately: receive data for readable sockets, send queued data for writable sockets, and perform cleanup for errored sockets.
Here's my D implementation of non-fiber event-based networking: ae.net.asockets.

is it possible to determine the level of memory warnings?

I am receiving memory warnings in didReceiveMemoryWarning. I know memory warnings have different levels like level-1,level-2. Is there any way determine the warning level? Example:
if(warning level == 1)
<blah>
Hope this helps!!!
There are 4 levels of warnings (0 to 3). These are set from the kernel memory watcher, and can be obtained by the not-so-public function OSMemoryNotificationCurrentLevel().
typedef enum {
OSMemoryNotificationLevelAny = -1,
OSMemoryNotificationLevelNormal = 0,
OSMemoryNotificationLevelWarning = 1,
OSMemoryNotificationLevelUrgent = 2,
OSMemoryNotificationLevelCritical = 3
} OSMemoryNotificationLevel;
How the levels are triggered is not documented. SpringBoard is configured to do the following in each memory level:
Warning (not-normal) — Relaunch, or delay auto relaunch of nonessential background apps e.g. Mail.
Urgent — Quit all background apps, e.g. Safari and iPod.
Critical and beyond — The kernel will take over, probably killing SpringBoard or even reboot.
I know there is no way to (except the private/undocumented API) know the memory level warning. So you should not use that.
Check out this question to see undocumented API to get memory warning level.
My first advice would be to research the memory warning notification in the docs (e.g., what are the contents of its userInfo dictionary, if present). I don't know if it provides any details or not.
But ultimately, you shouldn't speculate on the level of the memory warning, just assume the worst and release as much unused data as you can.
There is no (public, working) way to get the current memory pressure level from the system on a customer device. There is however a way to get notified of memory pressure changes using the Dispatch Source API.
Memory pressure dispatch sources can be used to notify an application of changes to memory pressure. This can be more fine-grained than the notifications provided by UIKit and includes the capability to be notified when memory pressure returns to normal.
For example:
Objective-C:
dispatch_source_t memorySource = NULL;
memorySource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0L, (DISPATCH_MEMORYPRESSURE_NORMAL | DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL), [self privateQueue]);
if (memorySource != NULL) {
dispatch_block_t eventHandler = dispatch_block_create(DISPATCH_BLOCK_ASSIGN_CURRENT, ^{
if (dispatch_source_testcancel(memorySource) == 0 ){
dispatch_source_memorypressure_flags_t memoryPressure = dispatch_source_get_data(memorySource);
[self didReceiveMemoryPressure:memoryPressure];
}
});
dispatch_source_set_event_handler(memorySource, eventHandler);
dispatch_source_set_registration_handler(memorySource, eventHandler);
[self setSource:memorySource];
dispatch_activate([self source]);
}
Swift 4:
if let source:DispatchSourceMemoryPressure = DispatchSource.makeMemoryPressureSource(eventMask: .all, queue:self.privateQueue) as? DispatchSource {
let eventHandler: DispatchSourceProtocol.DispatchSourceHandler = {
let event:DispatchSource.MemoryPressureEvent = source.data
if source.isCancelled == false {
self.didReceive(memoryPressureEvent: event)
}
}
source.setEventHandler(handler:eventHandler)
source.setRegistrationHandler(handler:eventHandler)
self.source = source
self.source?.activate()
}
Note that the event handler is also being used as the "registration handler". This will cause the event handler to fire when the dispatch source is activated, effectively telling the application of what the "current" value is when the source is activated.

how to deal with the block of ftp download request

I am downloading file with ftp protocol. Now, to check the ability of dealing with error, I am simulating happening of some network error. The code to handle the network inputStream is as below:
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
// An NSStream delegate callback that's called when events happen on our
// network stream.
{
#pragma unused(aStream)
assert(aStream == self.networkStream);
switch (eventCode) {
case NSStreamEventOpenCompleted: {
self.connected = YES;
} break;
case NSStreamEventHasBytesAvailable: {
NSInteger bytesRead;
uint8_t buffer[32768];
// Pull some data off the network.
bytesRead = [self.networkStream read:buffer maxLength:sizeof(buffer)];
DLog(#"%#,byteRead:%d",self.urlInput,bytesRead);
if (bytesRead == -1) {
[self _stopReceiveWithStatus:#"Network read error"];
} else if (bytesRead == 0) {
[self _stopReceiveWithStatus:#"success"];
} else {
NSInteger bytesWritten;
NSInteger bytesWrittenSoFar;
bytesWrittenSoFar = 0;
do {
bytesWritten = [self.fileStream write:&buffer[bytesWrittenSoFar] maxLength:bytesRead - bytesWrittenSoFar];
DLog(#"%#,bytesWritten:%d",self.urlInput,bytesWritten);
assert(bytesWritten != 0);
if (bytesWritten == -1) {
[self _stopReceiveWithStatus:#"File write error"];
break;
} else {
bytesWrittenSoFar += bytesWritten;
}
} while (bytesWrittenSoFar != bytesRead);
}
} break;
case NSStreamEventHasSpaceAvailable: {
assert(NO); // should never happen for the output stream
} break;
case NSStreamEventErrorOccurred: {
[self _stopReceiveWithStatus:#"Stream open error"];
} break;
case NSStreamEventEndEncountered: {
assert(NO);
} break;
default: {
assert(NO);
} break;
}
}
If I turn off the wifi manually or turn off my wireless router (Network connection flag is off), a "NSStreamEventErrorOccurred" will be return and the downloading process will be terminated correctly. However, if I turn off the Modem, while keeping the wireless router open (Network connection flag is on). The downloading process stuck at the case "NSStreamEventHasBytesAvailable". Even after I turn on the internet connection , it is still stuck.
I want to know why it is stuck and how can I detect this kind of error. How can I deal with this situation?
First, kudos for considering this and running tests. Many developers assume that "the network connection will always work."
Second, it seems a little odd that you are using NSStream for FTP downloads; you do know that NSURLConnection supports FTP, right? Unless you are doing something really strange you should probably use the built-in URL loading facilities.
In any case, the issue here is that there is in principle no way for an application (or computer) to determine whether there has been a pause in a connection because the connection failed (and should be restarted or canceled) or because it simply is running slowly (in which case patience is required).
I'm a little surprised that an active TCP session is not resumed when your modem is reconnected; that suggests that maybe your ISP's router is dropping the connection when the modem link goes down or that your IP is changing on reconnection, but this isn't important for your question anyway.
TCP sessions will ordinarily eventually get timed out by the OS (or an upstream router) after a period of inactivity, but this might be an unacceptably long time. So the thing you probably need to do is implement a timeout.
What I'd probably do (assuming you stay the course with NSStream as discussed above) is have an NSTimer firing off periodically - maybe every 15 seconds - and have the callback compare the current time to a timestamp that you set on each NSStreamEventHasBytesAvailable event. If the timestamp is too old (say, more than 15 seconds), cancel or restart the download as desired and notify the user.
But again, take a look at just using NSURLConnection.

iphone - how do I make a thread runs faster

I have two methods that I need to run, lets call them metA and metB.
When I start coding this app, I called both methods without using threads, but the app started freezing, so I decided to go with threads.
metA and metB are called by touch events, so they can occur any time in any order. They don't depend on each other.
My problem is the time it takes to either threads start running. There's a lag between the time the thread is created with
[NSThread detachNewThreadSelector:#selector(.... bla bla
and the time the thread starts running.
I suppose this time is related to the amount of time required by iOS to create the thread itself. How can I speed this? If I pre create both threads, how do I make them just do their stuff when needed and never terminate? I mean, a kind of sleeping thread that is always alive and works when asked and sleeps after that?
thanks.
If you want to avoid the expensive startup time of creating new threads, create both threads at startup as you suggested. To have them only run when needed, you can have them wait on a condition variable. Since you're using the NSThread class for threading, I'd recommend using the NSCondition class for condition variables (an alternative would be to use the POSIX threading (pthread) condition variables, pthread_cond_t).
One thing you'll have to be careful of is if you get another touch event while the thread is still running. In that case, I'd recommend using a queue to keep track of work items, and then the touch event handler can just add the work item to the queue, and the worker thread can process them as long as the queue is not empty.
Here's one way to do this:
typedef struct WorkItem
{
// information about the work item
...
struct WorkItem *next; // linked list of work items
} WorkItem;
WorkItem *workQueue = NULL; // head of linked list of work items
WorkItem *workQueueTail = NULL; // tail of linked list of work items
NSCondition *workCondition = NULL; // condition variable for the queue
...
-(id) init
{
if((self = [super init]))
{
// Make sure this gets initialized before the worker thread starts
// running
workCondition = [[NSCondition alloc] init];
// Start the worker thread
[NSThread detachNewThreadSelector:#selector(threadProc:)
toTarget:self withObject:nil];
}
return self;
}
// Suppose this function gets called whenever we receive an appropriate touch
// event
-(void) onTouch
{
// Construct a new work item. Note that this must be allocated on the
// heap (*not* the stack) so that it doesn't get destroyed before the
// worker thread has a chance to work on it.
WorkItem *workItem = (WorkItem *)malloc(sizeof(WorkItem));
// fill out the relevant info about the work that needs to get done here
...
workItem->next = NULL;
// Lock the mutex & add the work item to the tail of the queue (we
// maintain that the following invariant is always true:
// (workQueueTail == NULL || workQueueTail->next == NULL)
[workCondition lock];
if(workQueueTail != NULL)
workQueueTail->next = workItem;
else
workQueue = workItem;
workQueueTail = workItem;
[workCondition unlock];
// Finally, signal the condition variable to wake up the worker thread
[workCondition signal];
}
-(void) threadProc:(id)arg
{
// Loop & wait for work to arrive. Note that the condition variable must
// be locked before it can be waited on. You may also want to add
// another variable that gets checked every iteration so this thread can
// exit gracefully if need be.
while(1)
{
[workCondition lock];
while(workQueue == NULL)
{
[workCondition wait];
// The work queue should have something in it, but there are rare
// edge cases that can cause spurious signals. So double-check
// that it's not empty.
}
// Dequeue the work item & unlock the mutex so we don't block the
// main thread more than we have to
WorkItem *workItem = workQueue;
workQueue = workQueue->next;
if(workQueue == NULL)
workQueueTail = NULL;
[workCondition unlock];
// Process the work item here
...
free(workItem); // don't leak memory
}
}
If you can target iOS4 and higher, consider using blocks with Grand Central Dispatch asynch queue, which operates on background threads which the queue manages... or for backwards compatibility, as mentioned use NSOperations inside an NSOperation queue to have bits of work performed for you in the background. You can specify exactly how many background threads you want to support with an NSOperationQueue if both operations have to run at the same time.