2 * Copyright 2006-2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler, axeld@pinc-software.de
12 #include <ByteOrder.h>
13 #include <KernelExport.h>
15 #include <condition_variable.h>
16 #include <net_buffer.h>
17 #include <syscall_restart.h>
18 #include <util/AutoLock.h>
20 #include "stack_private.h"
23 //#define TRACE_UTILITY
25 # define TRACE(x...) dprintf(x)
27 # define TRACE(x...) ;
31 // internal Fifo class which doesn't maintain it's own lock
32 // TODO: do we need this one for anything?
35 Fifo(const char* name
, size_t maxBytes
);
38 status_t
InitCheck() const;
40 status_t
Enqueue(net_buffer
* buffer
);
41 status_t
EnqueueAndNotify(net_buffer
* _buffer
, net_socket
* socket
,
43 status_t
Wait(mutex
* lock
, bigtime_t timeout
);
44 net_buffer
* Dequeue(bool clone
);
49 bool IsEmpty() const { return current_bytes
== 0; }
52 // these field names are kept so we can use templatized
53 // functions together with net_fifo
63 static struct list sTimers
;
64 static mutex sTimerLock
;
65 static sem_id sTimerWaitSem
;
66 static ConditionVariable sWaitForTimerCondition
;
67 static net_timer
* sCurrentTimer
;
68 static thread_id sTimerThread
;
69 static bigtime_t sTimerTimeout
;
73 fifo_notify_one_reader(int32
& waiting
, sem_id sem
)
77 release_sem_etc(sem
, 1, B_DO_NOT_RESCHEDULE
);
82 template<typename FifoType
> static inline status_t
83 base_fifo_init(FifoType
* fifo
, const char* name
, size_t maxBytes
)
85 fifo
->notify
= create_sem(0, name
);
86 fifo
->max_bytes
= maxBytes
;
87 fifo
->current_bytes
= 0;
89 list_init(&fifo
->buffers
);
95 template<typename FifoType
> static inline status_t
96 base_fifo_enqueue_buffer(FifoType
* fifo
, net_buffer
* buffer
)
98 if (fifo
->max_bytes
> 0
99 && fifo
->current_bytes
+ buffer
->size
> fifo
->max_bytes
)
102 list_add_item(&fifo
->buffers
, buffer
);
103 fifo
->current_bytes
+= buffer
->size
;
104 fifo_notify_one_reader(fifo
->waiting
, fifo
->notify
);
110 template<typename FifoType
> static inline status_t
111 base_fifo_clear(FifoType
* fifo
)
114 net_buffer
* buffer
= (net_buffer
*)list_remove_head_item(&fifo
->buffers
);
118 gNetBufferModule
.free(buffer
);
121 fifo
->current_bytes
= 0;
126 // #pragma mark - UserBuffer
130 UserBuffer::Push(void* source
, size_t length
)
135 if (fAvailable
< length
) {
141 fStatus
= user_memcpy(fBuffer
, source
, length
);
145 memcpy(fBuffer
, source
, length
);
148 void* current
= fBuffer
;
150 fAvailable
-= length
;
158 UserBuffer::Pad(size_t length
)
163 if (fAvailable
< length
)
164 return fStatus
= ENOBUFS
;
166 fStatus
= user_memset(fBuffer
, 0, length
);
170 fAvailable
-= length
;
178 UserBuffer::PadToNext(size_t length
)
180 return Pad((BytesConsumed() + length
- 1) / length
- BytesConsumed());
188 compute_checksum(uint8
* _buffer
, size_t length
)
190 uint16
* buffer
= (uint16
*)_buffer
;
193 // TODO: unfold loop for speed
194 // TODO: write processor dependent version for speed
195 while (length
>= 2) {
201 // give the last byte it's proper endian-aware treatment
202 #if B_HOST_IS_LENDIAN
203 sum
+= *(uint8
*)buffer
;
206 ordered
[0] = *(uint8
*)buffer
;
208 sum
+= *(uint16
*)ordered
;
213 sum
= (sum
& 0xffff) + (sum
>> 16);
221 checksum(uint8
* buffer
, size_t length
)
223 return ~compute_checksum(buffer
, length
);
227 // #pragma mark - Notifications
231 notify_socket(net_socket
* socket
, uint8 event
, int32 value
)
233 return gNetSocketModule
.notify(socket
, event
, value
);
237 // #pragma mark - FIFOs
240 Fifo::Fifo(const char* name
, size_t maxBytes
)
242 base_fifo_init(this, name
, maxBytes
);
254 Fifo::InitCheck() const
256 return !(notify
< B_OK
);
261 Fifo::Enqueue(net_buffer
* buffer
)
263 return base_fifo_enqueue_buffer(this, buffer
);
268 Fifo::EnqueueAndNotify(net_buffer
* _buffer
, net_socket
* socket
, uint8 event
)
270 net_buffer
*buffer
= gNetBufferModule
.clone(_buffer
, false);
274 status_t status
= Enqueue(buffer
);
276 gNetBufferModule
.free(buffer
);
278 notify_socket(socket
, event
, current_bytes
);
285 Fifo::Wait(mutex
* lock
, bigtime_t timeout
)
289 status_t status
= acquire_sem_etc(notify
, 1,
290 B_CAN_INTERRUPT
| B_ABSOLUTE_TIMEOUT
, timeout
);
297 Fifo::Dequeue(bool clone
)
299 net_buffer
* buffer
= (net_buffer
*)list_get_first_item(&buffers
);
301 // assert(buffer != NULL);
304 buffer
= gNetBufferModule
.clone(buffer
, false);
305 fifo_notify_one_reader(waiting
, notify
);
307 list_remove_item(&buffers
, buffer
);
308 current_bytes
-= buffer
->size
;
318 return base_fifo_clear(this);
326 release_sem_etc(notify
, 0, B_RELEASE_ALL
);
328 release_sem_etc(notify
, 0, waiting
);
334 init_fifo(net_fifo
* fifo
, const char* name
, size_t maxBytes
)
336 mutex_init_etc(&fifo
->lock
, name
, MUTEX_FLAG_CLONE_NAME
);
338 status_t status
= base_fifo_init(fifo
, name
, maxBytes
);
340 mutex_destroy(&fifo
->lock
);
347 uninit_fifo(net_fifo
* fifo
)
351 mutex_destroy(&fifo
->lock
);
352 delete_sem(fifo
->notify
);
357 fifo_enqueue_buffer(net_fifo
* fifo
, net_buffer
* buffer
)
359 MutexLocker
locker(fifo
->lock
);
360 return base_fifo_enqueue_buffer(fifo
, buffer
);
364 /*! Gets the first buffer from the FIFO. If there is no buffer, it
365 will wait depending on the \a flags and \a timeout.
366 The following flags are supported (the rest is ignored):
367 MSG_DONTWAIT - ignores the timeout and never wait for a buffer; if your
368 socket is O_NONBLOCK, you should specify this flag. A \a timeout of
369 zero is equivalent to this flag, though.
370 MSG_PEEK - returns a clone of the buffer and keep the original
374 fifo_dequeue_buffer(net_fifo
* fifo
, uint32 flags
, bigtime_t timeout
,
375 net_buffer
** _buffer
)
377 MutexLocker
locker(fifo
->lock
);
378 bool dontWait
= (flags
& MSG_DONTWAIT
) != 0 || timeout
== 0;
382 net_buffer
* buffer
= (net_buffer
*)list_get_first_item(&fifo
->buffers
);
383 if (buffer
!= NULL
) {
384 if ((flags
& MSG_PEEK
) != 0) {
385 // we need to clone the buffer for inspection; we can't give a
386 // handle to a buffer that we're still using
387 buffer
= gNetBufferModule
.clone(buffer
, false);
388 if (buffer
== NULL
) {
389 status
= B_NO_MEMORY
;
393 list_remove_item(&fifo
->buffers
, buffer
);
394 fifo
->current_bytes
-= buffer
->size
;
408 return B_WOULD_BLOCK
;
410 // we need to wait until a new buffer becomes available
411 status
= acquire_sem_etc(fifo
->notify
, 1,
412 B_CAN_INTERRUPT
| B_RELATIVE_TIMEOUT
, timeout
);
419 // if another thread is waiting for data, since we didn't
420 // eat the buffer, it will get it
421 if (flags
& MSG_PEEK
)
422 fifo_notify_one_reader(fifo
->waiting
, fifo
->notify
);
429 clear_fifo(net_fifo
* fifo
)
431 MutexLocker
locker(fifo
->lock
);
432 return base_fifo_clear(fifo
);
437 fifo_socket_enqueue_buffer(net_fifo
* fifo
, net_socket
* socket
, uint8 event
,
440 net_buffer
*buffer
= gNetBufferModule
.clone(_buffer
, false);
444 MutexLocker
locker(fifo
->lock
);
446 status_t status
= base_fifo_enqueue_buffer(fifo
, buffer
);
448 gNetBufferModule
.free(buffer
);
450 notify_socket(socket
, event
, fifo
->current_bytes
);
456 // #pragma mark - Timer
460 timer_thread(void* /*data*/)
462 status_t status
= B_OK
;
465 bigtime_t timeout
= B_INFINITE_TIMEOUT
;
467 if (status
== B_TIMED_OUT
|| status
== B_OK
) {
468 // scan timers for new timeout and/or execute a timer
469 mutex_lock(&sTimerLock
);
471 struct net_timer
* timer
= NULL
;
473 timer
= (net_timer
*)list_get_next_item(&sTimers
, timer
);
477 if (timer
->due
< system_time()) {
479 list_remove_item(&sTimers
, timer
);
481 sCurrentTimer
= timer
;
483 mutex_unlock(&sTimerLock
);
484 timer
->hook(timer
, timer
->data
);
485 mutex_lock(&sTimerLock
);
487 sCurrentTimer
= NULL
;
488 sWaitForTimerCondition
.NotifyAll();
491 // restart scanning as we unlocked the list
493 // calculate new timeout
494 if (timer
->due
< timeout
)
495 timeout
= timer
->due
;
499 sTimerTimeout
= timeout
;
500 mutex_unlock(&sTimerLock
);
503 status
= acquire_sem_etc(sTimerWaitSem
, 1, B_ABSOLUTE_TIMEOUT
, timeout
);
504 // the wait sem normally can't be acquired, so we
505 // have to look at the status value the call returns:
507 // B_OK - a new timer has been added or canceled
508 // B_TIMED_OUT - look for timers to be executed
509 // B_BAD_SEM_ID - we are asked to quit
510 } while (status
!= B_BAD_SEM_ID
);
517 Initializes a timer before use. You can also use this function to change
518 a timer later on, but make sure you have canceled it before using set_timer().
521 init_timer(net_timer
* timer
, net_timer_func hook
, void* data
)
530 /*! Sets or cancels a timer. When the \a delay is below zero, an eventually
531 running timer is canceled, if not, it is scheduled to be executed after the
533 You need to have initialized the timer before calling this function.
535 In case you need to change a running timer, you have to cancel it first,
536 before making any changes.
539 set_timer(net_timer
* timer
, bigtime_t delay
)
541 MutexLocker
locker(sTimerLock
);
543 TRACE("set_timer %p, hook %p, data %p\n", timer
, timer
->hook
, timer
->data
);
545 if (timer
->due
> 0 && delay
< 0) {
546 // this timer is scheduled, cancel it
547 list_remove_item(&sTimers
, timer
);
552 // reschedule or add this timer
554 list_add_item(&sTimers
, timer
);
556 timer
->due
= system_time() + delay
;
558 // notify timer about the change if necessary
559 if (sTimerTimeout
> timer
->due
)
560 release_sem(sTimerWaitSem
);
566 cancel_timer(struct net_timer
* timer
)
568 MutexLocker
locker(sTimerLock
);
570 TRACE("cancel_timer %p, hook %p, data %p\n", timer
, timer
->hook
,
576 // this timer is scheduled, cancel it
577 list_remove_item(&sTimers
, timer
);
584 wait_for_timer(struct net_timer
* timer
)
586 if (find_thread(NULL
) == sTimerThread
) {
587 // let's not wait for ourselves...
592 MutexLocker
locker(sTimerLock
);
594 if (timer
->due
<= 0 && sCurrentTimer
!= timer
)
597 // we actually need to wait for this timer
598 ConditionVariableEntry entry
;
599 sWaitForTimerCondition
.Add(&entry
);
611 is_timer_active(net_timer
* timer
)
613 return timer
->due
> 0;
618 is_timer_running(net_timer
* timer
)
620 return timer
== sCurrentTimer
;
625 dump_timer(int argc
, char** argv
)
627 kprintf("timer hook data due in\n");
629 struct net_timer
* timer
= NULL
;
631 timer
= (net_timer
*)list_get_next_item(&sTimers
, timer
);
635 kprintf("%p %p %p %" B_PRId64
"\n", timer
, timer
->hook
, timer
->data
,
636 timer
->due
> 0 ? timer
->due
- system_time() : -1);
647 sTimerTimeout
= B_INFINITE_TIMEOUT
;
649 status_t status
= B_OK
;
650 mutex_init(&sTimerLock
, "net timer");
652 sTimerWaitSem
= create_sem(0, "net timer wait");
653 if (sTimerWaitSem
< B_OK
) {
654 status
= sTimerWaitSem
;
658 sTimerThread
= spawn_kernel_thread(timer_thread
, "net timer",
659 B_NORMAL_PRIORITY
, NULL
);
660 if (sTimerThread
< B_OK
) {
661 status
= sTimerThread
;
665 sWaitForTimerCondition
.Init(NULL
, "wait for net timer");
667 add_debugger_command("net_timer", dump_timer
,
668 "Lists all active network timer");
670 return resume_thread(sTimerThread
);
673 mutex_destroy(&sTimerLock
);
675 delete_sem(sTimerWaitSem
);
683 delete_sem(sTimerWaitSem
);
686 wait_for_thread(sTimerThread
, &status
);
688 mutex_lock(&sTimerLock
);
690 mutex_destroy(&sTimerLock
);
692 remove_debugger_command("net_timer", dump_timer
);
696 // #pragma mark - Syscall restart
702 return is_called_via_syscall();
707 is_restarted_syscall(void)
709 return syscall_restart_is_restarted();
714 store_syscall_restart_timeout(bigtime_t timeout
)
716 Thread
* thread
= thread_get_current_thread();
717 if ((thread
->flags
& THREAD_FLAGS_SYSCALL
) != 0)
718 *(bigtime_t
*)thread
->syscall_restart
.parameters
= timeout
;
723 restore_syscall_restart_timeout(void)
725 Thread
* thread
= thread_get_current_thread();
726 return *(bigtime_t
*)thread
->syscall_restart
.parameters
;