From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/lib/voodoo/server.c | 459 ++++++++++++++++++++++++++++++++++++ 1 file changed, 459 insertions(+) create mode 100755 Source/DirectFB/lib/voodoo/server.c (limited to 'Source/DirectFB/lib/voodoo/server.c') diff --git a/Source/DirectFB/lib/voodoo/server.c b/Source/DirectFB/lib/voodoo/server.c new file mode 100755 index 0000000..0c543b6 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/server.c @@ -0,0 +1,459 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +typedef struct { + sem_t sem; + + pid_t gfxpid; +} ServerShared; + +typedef struct { + DirectLink link; + + VoodooLink vl; + VoodooManager *manager; +} Connection; + +typedef struct { + const char *name; + VoodooSuperConstruct func; + void *ctx; + + IAny *interface; +} Super; + +#define MAX_SUPER 8 + +struct __V_VoodooServer { + int fd; + + bool quit; + DirectLink *connections; + + int num_super; + Super supers[MAX_SUPER]; + + ServerShared *shared; +}; + +/**************************************************************************************************/ + +static DirectResult accept_connection( VoodooServer *server, int fd ); + +/**************************************************************************************************/ + +static const int one = 1; + +/**************************************************************************************************/ + +DirectResult +voodoo_server_create( VoodooServer **ret_server ) +{ + DirectResult ret; + struct sockaddr_in addr; + int fd = -1; + VoodooServer *server = NULL; + + D_ASSERT( ret_server != NULL ); + + /* Create the server socket. */ + fd = socket( PF_INET, SOCK_STREAM, 0 ); + if (fd < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Could not create the socket via socket()!\n" ); + goto error; + } + + /* Allow reuse of local address. */ + if (setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one) ) < 0) + D_PERROR( "Voodoo/Server: Could not set SO_REUSEADDR!\n" ); + + /* Bind the socket to the local port. */ + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr( "0.0.0.0" ); + addr.sin_port = htons( 2323 ); + + if (bind( fd, &addr, sizeof(addr) )) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Could not bind() the socket!\n" ); + goto error; + } + + /* Start listening. */ + if (listen( fd, 4 )) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Could not listen() to the socket!\n" ); + goto error; + } + + /* Allocate server structure. */ + server = D_CALLOC( 1, sizeof(VoodooServer) ); + if (!server) { + ret = D_OOM(); + D_WARN( "out of memory" ); + goto error; + } + + /* Initialize server structure. */ + server->fd = fd; + + { + int zfd; + + zfd = open( "/dev/zero", O_RDWR ); + if (zfd < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Failed to open /dev/zero!\n" ); + goto error; + } + + server->shared = mmap( NULL, sizeof(ServerShared), PROT_READ | PROT_WRITE, MAP_SHARED, zfd, 0 ); + + close( zfd ); + + if (server->shared == MAP_FAILED) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Failed to mmap /dev/zero!\n" ); + server->shared = NULL; + goto error; + } + + if (sem_init( &server->shared->sem, 1, 1 )) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Failed to create process shared semaphore!\n" ); + goto error; + } + } + + /* Return the new server. */ + *ret_server = server; + + return DR_OK; + + +error: + if (server) { + if (server->shared) + munmap( server->shared, sizeof(ServerShared) ); + + D_FREE( server ); + } + + if (fd >= 0) + close( fd ); + + return ret; +} + +DirectResult +voodoo_server_register( VoodooServer *server, + const char *name, + VoodooSuperConstruct func, + void *ctx ) +{ + Super *super; + + D_ASSERT( server != NULL ); + D_ASSERT( name != NULL ); + D_ASSERT( func != NULL ); + + if (server->num_super == MAX_SUPER) + return DR_LIMITEXCEEDED; + + super = &server->supers[server->num_super++]; + + super->name = name; + super->func = func; + super->ctx = ctx; + + return DR_OK; +} + +static inline Super * +lookup_super( VoodooServer *server, + const char *name ) +{ + int i; + + D_ASSERT( server != NULL ); + D_ASSERT( name != NULL ); + + for (i=0; inum_super; i++) { + Super *super = &server->supers[i]; + + if (! strcmp( name, super->name )) + return super; + } + + return NULL; +} + +DirectResult +voodoo_server_construct( VoodooServer *server, + VoodooManager *manager, + const char *name, + VoodooInstanceID *ret_instance ) +{ + DirectResult ret; + Super *super; + VoodooInstanceID instance; + + D_ASSERT( server != NULL ); + D_ASSERT( manager != NULL ); + D_ASSERT( name != NULL ); + D_ASSERT( ret_instance != NULL ); + + super = lookup_super( server, name ); + if (!super) { + D_ERROR( "Voodoo/Server: Super interface '%s' is not available!\n", name ); + return DR_UNSUPPORTED; + } + + if (!strcmp( name, "IDirectFB" )) { + sem_wait( &server->shared->sem ); + + if (server->shared->gfxpid) { + D_INFO( "Voodoo/Server: Killing previous graphics process with pid %d\n", server->shared->gfxpid ); + kill( server->shared->gfxpid, SIGTERM ); + } + + server->shared->gfxpid = getpid(); + + D_INFO( "Voodoo/Server: New graphics process has pid %d\n", server->shared->gfxpid ); + + sem_post( &server->shared->sem ); + } + + ret = super->func( server, manager, name, super->ctx, &instance ); + if (ret) { + D_ERROR( "Voodoo/Server: " + "Creating super interface '%s' failed (%s)!\n", name, DirectResultString(ret) ); + return ret; + } + + *ret_instance = instance; + + return DR_OK; +} + +DirectResult +voodoo_server_run( VoodooServer *server, + bool forking ) +{ + DirectLink *l, *n; + struct pollfd pf; + bool listener = true; + + D_ASSERT( server != NULL ); + + while (!server->quit) { + /* Cleanup dead connections. */ + direct_list_foreach_safe (l, n, server->connections) { + Connection *connection = (Connection*) l; + + if (voodoo_manager_is_closed( connection->manager )) { + sem_wait( &server->shared->sem ); + + if (server->shared->gfxpid == getpid()) { + D_INFO( "Voodoo/Server: Closing graphics process with pid %d\n", server->shared->gfxpid ); + server->shared->gfxpid = 0; + } + + sem_post( &server->shared->sem ); + + + voodoo_manager_destroy( connection->manager ); + + //connection->vl.Close( &connection->vl ); + + direct_list_remove( &server->connections, l ); + + D_INFO( "Voodoo/Server: Closed connection.\n" ); + + D_FREE( connection ); + + if (forking && !server->connections) + return DR_OK; + } + } + + if (listener) { + int i; + int fd; + struct sockaddr addr; + socklen_t addrlen = sizeof(addr); + + pf.fd = server->fd; + pf.events = POLLIN; + + switch (poll( &pf, 1, 200 )) { + default: + fd = accept( server->fd, &addr, &addrlen ); + if (fd < 0) { + D_PERROR( "Voodoo/Server: Could not accept() incoming connection!\n" ); + break; + } + + if (forking) { + switch (fork()) { + case 0: + listener = false; + + for (i=3; i<65535; i++) { + if (i != fd) + close( i ); + } + + accept_connection( server, fd ); + break; + + case -1: + D_PERROR( "Voodoo/Server: Could not fork()!\n" ); + break; + + default: + close( fd ); + break; + } + } + else { + accept_connection( server, fd ); + } + break; + + case 0: + waitpid( -1, NULL, WNOHANG ); + + D_DEBUG( "Voodoo/Server: Timeout during poll()\n" ); + break; + + case -1: + if (errno != EINTR) { + D_PERROR( "Voodoo/Server: Could not poll() the socket!\n" ); + server->quit = true; + } + break; + } + } + else + usleep( 200000 ); + } + + return DR_OK; +} + +DirectResult +voodoo_server_destroy( VoodooServer *server ) +{ + DirectLink *l; + + D_ASSERT( server != NULL ); + + close( server->fd ); + + /* Close all connections. */ + direct_list_foreach (l, server->connections) { + Connection *connection = (Connection*) l; + + voodoo_manager_destroy( connection->manager ); + + //connection->vl.Close( &connection->vl ); + + D_FREE( connection ); + } + + D_FREE( server ); + + return DR_OK; +} + +/**************************************************************************************************/ + +static DirectResult +accept_connection( VoodooServer *server, int fd ) +{ + DirectResult ret; + int fds[2] = { fd, fd }; + Connection *connection; + + connection = D_CALLOC( 1, sizeof(Connection) ); + if (!connection) { + D_WARN( "out of memory" ); + return DR_NOLOCALMEMORY; + } + + voodoo_link_init_fd( &connection->vl, fds ); + + ret = voodoo_manager_create( &connection->vl, NULL, server, &connection->manager ); + if (ret) { + connection->vl.Close( &connection->vl ); + D_FREE( connection ); + return ret; + } + + direct_list_prepend( &server->connections, &connection->link ); + + return DR_OK; +} + -- cgit