* Moved the private kernel locking functions into kernelland_emu.cpp because the

actual versions cannot work in userland.
* Extended the tcp_tester to be able to connect and quit connections.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19330 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2006-11-19 23:35:07 +00:00
parent 30ea523ad1
commit 6ff565b0d6
3 changed files with 480 additions and 48 deletions
-5
View File
@@ -8,7 +8,6 @@ SharedLibrary libkernelland_emu.so :
kernelland_emu.cpp
strlcpy.c
khash.c
lock.c
list.c
: be stdc++.r4 ;
@@ -20,10 +19,6 @@ SEARCH on [ FGristFiles
strlcpy.c
] = [ FDirName $(HAIKU_TOP) src system libroot posix string ] ;
SEARCH on [ FGristFiles
lock.c
] = [ FDirName $(HAIKU_TOP) src system kernel ] ;
SEARCH on [ FGristFiles
list.c khash.c
] = [ FDirName $(HAIKU_TOP) src system kernel util ] ;
+236 -4
View File
@@ -1,8 +1,7 @@
// kernelland_emu.cpp
#include <set>
#include <stdio.h>
#include <string>
#include <lock.h>
#include <fs/devfs.h>
#include <Autolock.h>
#include <Directory.h>
@@ -15,7 +14,9 @@
#include <Path.h>
#include <String.h>
#include <fs/devfs.h>
#include <set>
#include <stdio.h>
#include <string>
#ifdef TRACE
#undef TRACE
@@ -786,3 +787,234 @@ arch_int_are_interrupts_enabled(void)
return true;
}
// #pragma mark - Private locking functions
int
recursive_lock_get_recursion(recursive_lock *lock)
{
thread_id thid = find_thread(NULL);
if (lock->holder == thid)
return lock->recursion;
return -1;
}
status_t
recursive_lock_init(recursive_lock *lock, const char *name)
{
if (lock == NULL)
return B_BAD_VALUE;
if (name == NULL)
name = "recursive lock";
lock->holder = -1;
lock->recursion = 0;
lock->sem = create_sem(1, name);
if (lock->sem >= B_OK)
return B_OK;
return lock->sem;
}
void
recursive_lock_destroy(recursive_lock *lock)
{
if (lock == NULL)
return;
delete_sem(lock->sem);
lock->sem = -1;
}
bool
recursive_lock_lock(recursive_lock *lock)
{
thread_id thid = find_thread(NULL);
bool retval = false;
if (thid != lock->holder) {
acquire_sem(lock->sem);
lock->holder = thid;
retval = true;
}
lock->recursion++;
return retval;
}
bool
recursive_lock_unlock(recursive_lock *lock)
{
thread_id thid = find_thread(NULL);
bool retval = false;
if (thid != lock->holder)
panic("recursive_lock %p unlocked by non-holder thread!\n", lock);
if (--lock->recursion == 0) {
lock->holder = -1;
release_sem(lock->sem);
retval = true;
}
return retval;
}
// #pragma mark -
status_t
mutex_init(mutex *m, const char *name)
{
if (m == NULL)
return EINVAL;
if (name == NULL)
name = "mutex_sem";
m->holder = -1;
m->sem = create_sem(1, name);
if (m->sem >= B_OK)
return B_OK;
return m->sem;
}
void
mutex_destroy(mutex *mutex)
{
if (mutex == NULL)
return;
if (mutex->sem >= 0) {
delete_sem(mutex->sem);
mutex->sem = -1;
}
mutex->holder = -1;
}
void
mutex_lock(mutex *mutex)
{
thread_id me = find_thread(NULL);
// ToDo: if acquire_sem() fails, we shouldn't panic - but we should definitely
// change the mutex API to actually return the status code
if (acquire_sem(mutex->sem) == B_OK) {
if (me == mutex->holder)
panic("mutex_lock failure: mutex %p (sem = 0x%lx) acquired twice by thread 0x%lx\n", mutex, mutex->sem, me);
}
mutex->holder = me;
}
void
mutex_unlock(mutex *mutex)
{
thread_id me = find_thread(NULL);
if (me != mutex->holder)
panic("mutex_unlock failure: thread 0x%lx is trying to release mutex %p (current holder 0x%lx)\n",
me, mutex, mutex->holder);
mutex->holder = -1;
release_sem(mutex->sem);
}
// #pragma mark -
status_t
benaphore_init(benaphore *ben, const char *name)
{
if (ben == NULL || name == NULL)
return B_BAD_VALUE;
ben->count = 1;
ben->sem = create_sem(0, name);
if (ben->sem >= B_OK)
return B_OK;
return ben->sem;
}
void
benaphore_destroy(benaphore *ben)
{
delete_sem(ben->sem);
ben->sem = -1;
}
// #pragma mark -
status_t
rw_lock_init(rw_lock *lock, const char *name)
{
if (lock == NULL)
return B_BAD_VALUE;
if (name == NULL)
name = "r/w lock";
lock->sem = create_sem(RW_MAX_READERS, name);
if (lock->sem >= B_OK)
return B_OK;
return lock->sem;
}
void
rw_lock_destroy(rw_lock *lock)
{
if (lock == NULL)
return;
delete_sem(lock->sem);
}
status_t
rw_lock_read_lock(rw_lock *lock)
{
return acquire_sem(lock->sem);
}
status_t
rw_lock_read_unlock(rw_lock *lock)
{
return release_sem(lock->sem);
}
status_t
rw_lock_write_lock(rw_lock *lock)
{
return acquire_sem_etc(lock->sem, RW_MAX_READERS, 0, 0);
}
status_t
rw_lock_write_unlock(rw_lock *lock)
{
return release_sem_etc(lock->sem, RW_MAX_READERS, 0);
}
+244 -39
View File
@@ -9,8 +9,10 @@
#include <KernelExport.h>
#include <module.h>
#include <util/AutoLock.h>
#include <netinet/in.h>
#include <new>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -36,9 +38,9 @@ extern module_info *modules[];
extern struct net_protocol_module_info gDomainModule;
static struct net_protocol sDomainProtocol;
struct net_interface gInterface;
struct net_socket_module_info gNetSocketModule;
extern struct net_socket_module_info gNetSocketModule;
struct net_protocol_module_info *gTCPModule;
struct net_socket gServerSocket, gClientSocket;
struct net_socket *gServerSocket, *gClientSocket;
static struct net_domain sDomain = {
"ipv4",
@@ -128,54 +130,68 @@ static net_stack_module_info gNetStackModule = {
};
// #pragma mark - protocol/socket
// #pragma mark - socket
net_protocol*
init_protocol(net_socket& socket)
status_t
socket_create(int family, int type, int protocol, net_socket **_socket)
{
memset(&socket, 0, sizeof(net_socket));
socket.family = AF_INET;
socket.type = SOCK_STREAM;
socket.protocol = IPPROTO_TCP;
struct net_socket *socket = new (std::nothrow) net_socket;
if (socket == NULL)
return B_NO_MEMORY;
memset(socket, 0, sizeof(net_socket));
socket->family = family;
socket->type = type;
socket->protocol = protocol;
status_t status = benaphore_init(&socket->lock, "socket");
if (status < B_OK)
goto err1;
// set defaults (may be overridden by the protocols)
socket.send.buffer_size = 65536;
socket.send.low_water_mark = 1;
socket.send.timeout = B_INFINITE_TIMEOUT;
socket.receive.buffer_size = 65536;
socket.receive.low_water_mark = 1;
socket.receive.timeout = B_INFINITE_TIMEOUT;
socket->send.buffer_size = 65536;
socket->send.low_water_mark = 1;
socket->send.timeout = B_INFINITE_TIMEOUT;
socket->receive.buffer_size = 65536;
socket->receive.low_water_mark = 1;
socket->receive.timeout = B_INFINITE_TIMEOUT;
net_protocol* protocol = gTCPModule->init_protocol(&socket);
if (protocol == NULL) {
list_init_etc(&socket->pending_children, offsetof(net_socket, link));
list_init_etc(&socket->connected_children, offsetof(net_socket, link));
socket->first_protocol = gTCPModule->init_protocol(socket);
if (socket->first_protocol == NULL) {
fprintf(stderr, "tcp_tester: cannot create protocol\n");
return NULL;
goto err2;
}
socket.first_info = gTCPModule;
socket.first_protocol = protocol;
socket->first_info = gTCPModule;
protocol->next = &sDomainProtocol;
protocol->module = gTCPModule;
protocol->socket = &socket;
socket->first_protocol->next = &sDomainProtocol;
socket->first_protocol->module = gTCPModule;
socket->first_protocol->socket = socket;
status_t status = gTCPModule->open(protocol);
if (status < B_OK) {
fprintf(stderr, "tcp_tester: cannot open client: %s\n", strerror(status));
return NULL;
}
*_socket = socket;
return B_OK;
return protocol;
err2:
benaphore_destroy(&socket->lock);
err1:
delete socket;
return status;
}
void
close_protocol(net_protocol* protocol)
socket_delete(net_socket *socket)
{
gTCPModule->close(protocol);
gTCPModule->free(protocol);
gTCPModule->uninit_protocol(protocol);
if (socket->parent != NULL)
panic("socket still has a parent!");
socket->first_info->uninit_protocol(socket->first_protocol);
benaphore_destroy(&socket->lock);
delete socket;
}
@@ -261,6 +277,187 @@ socket_listen(net_socket *socket, int backlog)
}
status_t
socket_spawn_pending(net_socket *parent, net_socket **_socket)
{
BenaphoreLocker locker(parent->lock);
// We actually accept more pending connections to compensate for those
// that never complete, and also make sure at least a single connection
// can always be accepted
if (parent->child_count > 3 * parent->max_backlog / 2)
return ENOBUFS;
net_socket *socket;
status_t status = socket_create(parent->family, parent->type, parent->protocol, &socket);
if (status < B_OK)
return status;
// inherit parent's properties
socket->send = parent->send;
socket->receive = parent->receive;
socket->options = parent->options & ~SO_ACCEPTCONN;
socket->linger = parent->linger;
memcpy(&socket->address, &parent->address, parent->address.ss_len);
memcpy(&socket->peer, &parent->peer, parent->peer.ss_len);
// add to the parent's list of pending connections
list_add_item(&parent->pending_children, socket);
parent->child_count++;
*_socket = socket;
return B_OK;
}
status_t
socket_dequeue_connected(net_socket *parent, net_socket **_socket)
{
benaphore_lock(&parent->lock);
net_socket *socket = (net_socket *)list_remove_head_item(&parent->connected_children);
if (socket != NULL) {
socket->parent = NULL;
parent->child_count--;
*_socket = socket;
}
benaphore_unlock(&parent->lock);
return socket != NULL ? B_OK : B_ENTRY_NOT_FOUND;
}
status_t
socket_set_max_backlog(net_socket *socket, uint32 backlog)
{
// we enforce an upper limit of connections waiting to be accepted
if (backlog > 256)
backlog = 256;
benaphore_lock(&socket->lock);
// first remove the pending connections, then the already connected ones as needed
net_socket *child;
while (socket->child_count > backlog
&& (child = (net_socket *)list_remove_tail_item(&socket->pending_children)) != NULL) {
child->parent = NULL;
socket->child_count--;
}
while (socket->child_count > backlog
&& (child = (net_socket *)list_remove_tail_item(&socket->connected_children)) != NULL) {
child->parent = NULL;
socket_delete(child);
socket->child_count--;
}
socket->max_backlog = backlog;
benaphore_unlock(&socket->lock);
return B_OK;
}
/*!
The socket has been connected. It will be moved to the connected queue
of its parent socket.
*/
status_t
socket_connected(net_socket *socket)
{
net_socket *parent = socket->parent;
if (parent == NULL)
return B_BAD_VALUE;
benaphore_lock(&parent->lock);
list_remove_item(&parent->pending_children, socket);
list_add_item(&parent->connected_children, socket);
benaphore_unlock(&parent->lock);
return B_OK;
}
net_socket_module_info gNetSocketModule = {
{
NET_SOCKET_MODULE_NAME,
0,
std_ops
},
NULL, //socket_open,
NULL, //socket_close,
NULL, //socket_free,
NULL, //socket_readv,
NULL, //socket_writev,
NULL, //socket_control,
NULL, //socket_read_avail,
NULL, //socket_send_avail,
NULL, //socket_send_data,
NULL, //socket_receive_data,
// connections
socket_spawn_pending,
socket_delete,
socket_dequeue_connected,
socket_set_max_backlog,
socket_connected,
// notifications
NULL, //socket_request_notification,
NULL, //socket_cancel_notification,
NULL, //socket_notify,
// standard socket API
NULL, //socket_accept,
NULL, //socket_bind,
NULL, //socket_connect,
NULL, //socket_getpeername,
NULL, //socket_getsockname,
NULL, //socket_getsockopt,
NULL, //socket_listen,
NULL, //socket_recv,
NULL, //socket_recvfrom,
NULL, //socket_send,
NULL, //socket_sendto,
NULL, //socket_setsockopt,
NULL, //socket_shutdown,
};
// #pragma mark - protocol
net_protocol*
init_protocol(net_socket** _socket)
{
net_socket *socket;
status_t status = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, &socket);
if (status < B_OK)
return NULL;
status = socket->first_info->open(socket->first_protocol);
if (status < B_OK) {
fprintf(stderr, "tcp_tester: cannot open client: %s\n", strerror(status));
socket_delete(socket);
return NULL;
}
*_socket = socket;
return socket->first_protocol;
}
void
close_protocol(net_protocol* protocol)
{
gTCPModule->close(protocol);
gTCPModule->free(protocol);
gTCPModule->uninit_protocol(protocol);
}
// #pragma mark - datalink
@@ -493,7 +690,7 @@ server_thread(void *)
net_socket* connectionSocket;
sockaddr_in address;
uint32 size = sizeof(struct sockaddr_in);
status_t status = socket_accept(&gServerSocket, (struct sockaddr *)&address,
status_t status = socket_accept(gServerSocket, (struct sockaddr *)&address,
&size, &connectionSocket);
if (status < B_OK) {
fprintf(stderr, "SERVER: accepting failed: %s\n", strerror(status));
@@ -523,7 +720,7 @@ do_connect(int argc, char** argv)
address.sin_port = htons(port);
address.sin_addr.s_addr = INADDR_ANY;
status_t status = socket_connect(&gClientSocket, (struct sockaddr *)&address,
status_t status = socket_connect(gClientSocket, (struct sockaddr *)&address,
sizeof(struct sockaddr));
if (status < B_OK)
fprintf(stderr, "tcp_tester: could not connect: %s\n", strerror(status));
@@ -561,6 +758,7 @@ main(int argc, char** argv)
_add_builtin_module((module_info *)&gNetStackModule);
_add_builtin_module((module_info *)&gNetBufferModule);
_add_builtin_module((module_info *)&gNetSocketModule);
_add_builtin_module((module_info *)&gNetDatalinkModule);
_add_builtin_module(modules[0]);
@@ -568,6 +766,7 @@ main(int argc, char** argv)
sockaddr_in interfaceAddress;
interfaceAddress.sin_len = sizeof(sockaddr_in);
interfaceAddress.sin_family = AF_INET;
interfaceAddress.sin_addr.s_addr = htonl(0xc0a80001);
gInterface.address = (sockaddr*)&interfaceAddress;
status = get_module("network/protocols/tcp/v1", (module_info **)&gTCPModule);
@@ -577,10 +776,10 @@ main(int argc, char** argv)
return 1;
}
net_protocol* client = init_protocol(gClientSocket);
net_protocol* client = init_protocol(&gClientSocket);
if (client == NULL)
return 1;
net_protocol* server = init_protocol(gServerSocket);
net_protocol* server = init_protocol(&gServerSocket);
if (server == NULL)
return 1;
@@ -594,12 +793,12 @@ main(int argc, char** argv)
address.sin_port = htons(1024);
address.sin_addr.s_addr = INADDR_ANY;
status = socket_bind(&gServerSocket, (struct sockaddr *)&address, sizeof(struct sockaddr));
status = socket_bind(gServerSocket, (struct sockaddr *)&address, sizeof(struct sockaddr));
if (status < B_OK) {
fprintf(stderr, "tcp_tester: cannot bind server: %s\n", strerror(status));
return 1;
}
status = socket_listen(&gServerSocket, 40);
status = socket_listen(gServerSocket, 40);
if (status < B_OK) {
fprintf(stderr, "tcp_tester: server cannot listen: %s\n", strerror(status));
return 1;
@@ -639,13 +838,19 @@ main(int argc, char** argv)
|| !strcmp(argv[0], "q"))
break;
bool found = false;
for (cmd_entry* command = sBuiltinCommands; command->name != NULL; command++) {
if (!strncmp(command->name, argv[0], length)) {
command->func(argc, argv);
found = true;
break;
}
}
if (!found)
fprintf(stderr, "Unknown command \"%s\". Type \"help\" for a list of commands.\n", argv[0]);
free(argv);
}