From da654737f999018575d735b7e6af8681b5a3185c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 6 Nov 2013 12:28:43 +0800 Subject: [PATCH] AcessNative - Rework of thread handling --- AcessNative/acesskernel_src/Makefile | 3 +- AcessNative/acesskernel_src/include/arch.h | 9 +- .../acesskernel_src/include/threads_glue.h | 1 + .../acesskernel_src/include/threads_int.h | 70 ++- AcessNative/acesskernel_src/server.c | 490 +++++++++--------- AcessNative/acesskernel_src/syscalls.c | 12 +- AcessNative/acesskernel_src/threads.c | 253 +++++---- AcessNative/acesskernel_src/threads_glue.c | 37 +- AcessNative/acesskernel_src/vfs_handle.c | 18 +- 9 files changed, 500 insertions(+), 393 deletions(-) diff --git a/AcessNative/acesskernel_src/Makefile b/AcessNative/acesskernel_src/Makefile index ad47c25a..f90b18b4 100644 --- a/AcessNative/acesskernel_src/Makefile +++ b/AcessNative/acesskernel_src/Makefile @@ -15,6 +15,7 @@ KERNEL_SRC = ../../KernelLand/Kernel/ LDACESS_SRC = ../../Usermode/Libraries/ld-acess.so_src/ KERNEL_OBJ := logging.o adt.o lib.o debug.o messages.o drvutil_disk.o drvutil_video.o +KERNEL_OBJ += mutex.o semaphore.o rwlock.o workqueue.o events.o #KERNEL_OBJ += libc.o KERNEL_OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/io.o vfs/dir.o KERNEL_OBJ += vfs/nodecache.o vfs/mount.o vfs/memfile.o vfs/select.o @@ -62,7 +63,7 @@ clean: $(BIN): $(OBJ) $(N_OBJ) $(K_OBJ) $(BUILDINFO_OBJ) @echo [LINK] -o $@ - @$(CC) -o $@ $(N_OBJ) $(K_OBJ) $(OBJ) $(BUILDINFO_OBJ) $(LDFLAGS) + @$(CC) -o $@ $(N_OBJ) $(LDFLAGS) $(K_OBJ) $(OBJ) $(BUILDINFO_OBJ) @echo BUILD_NUM = $$(( $(BUILD_NUM) + 1 )) > Makefile.BuildNum $(OBJ): obj-$(PLATFORM)/%.o: %.c diff --git a/AcessNative/acesskernel_src/include/arch.h b/AcessNative/acesskernel_src/include/arch.h index e99948c9..1e2be703 100644 --- a/AcessNative/acesskernel_src/include/arch.h +++ b/AcessNative/acesskernel_src/include/arch.h @@ -28,6 +28,8 @@ typedef intptr_t tPAddr; typedef int BOOL; +#define HALT_CPU() exit(1) + #include #undef offsetof @@ -36,8 +38,11 @@ struct sShortSpinlock void *Mutex; }; -#define SHORTLOCK(...) -#define SHORTREL(...) +extern void Threads_int_ShortLock(void **Ptr); +extern void Threads_int_ShortRel(void **Ptr); + +#define SHORTLOCK(l) Threads_int_ShortLock(&(l)->Mutex) +#define SHORTREL(l) Threads_int_ShortRel(&(l)->Mutex) #define CPU_HAS_LOCK(...) 0 //#define NUM_CFG_ENTRIES 10 diff --git a/AcessNative/acesskernel_src/include/threads_glue.h b/AcessNative/acesskernel_src/include/threads_glue.h index 61346bd3..7e094430 100644 --- a/AcessNative/acesskernel_src/include/threads_glue.h +++ b/AcessNative/acesskernel_src/include/threads_glue.h @@ -10,6 +10,7 @@ extern void Threads_Glue_ReleaseMutex(void **Lock); extern void Threads_Glue_SemInit(void **Ptr, int Val); extern int Threads_Glue_SemWait(void *Ptr, int Max); extern int Threads_Glue_SemSignal( void *Ptr, int AmmountToAdd ); +extern void Threads_Glue_SemDestroy( void *Ptr ); #endif diff --git a/AcessNative/acesskernel_src/include/threads_int.h b/AcessNative/acesskernel_src/include/threads_int.h index 8061f1e9..479d70ee 100644 --- a/AcessNative/acesskernel_src/include/threads_int.h +++ b/AcessNative/acesskernel_src/include/threads_int.h @@ -1,6 +1,39 @@ #ifndef _THREADS_INT_H_ #define _THREADS_INT_H_ +#include + +enum eThreadStatus { + THREAD_STAT_NULL, // Invalid process + THREAD_STAT_ACTIVE, // Running and schedulable process + THREAD_STAT_SLEEPING, // Message Sleep + THREAD_STAT_MUTEXSLEEP, // Mutex Sleep + THREAD_STAT_SEMAPHORESLEEP, // Semaphore Sleep + THREAD_STAT_QUEUESLEEP, // Queue + THREAD_STAT_EVENTSLEEP, // Event sleep + THREAD_STAT_RWLOCKSLEEP, + THREAD_STAT_WAITING, // ??? (Waiting for a thread) + THREAD_STAT_PREINIT, // Being created + THREAD_STAT_ZOMBIE, // Died/Killed, but parent not informed + THREAD_STAT_DEAD, // Awaiting burial (free) + THREAD_STAT_BURIED // If it's still on the list here, something's wrong +}; +static const char * const casTHREAD_STAT[] = { + "THREAD_STAT_NULL", // Invalid process + "THREAD_STAT_ACTIVE", // Running and schedulable process + "THREAD_STAT_SLEEPING", // Message Sleep + "THREAD_STAT_MUTEXSLEEP", // Mutex Sleep + "THREAD_STAT_SEMAPHORESLEEP", // Semaphore Sleep + "THREAD_STAT_QUEUESLEEP", // Queue + "THREAD_STAT_EVENTSLEEP", // Event sleep + "THREAD_STAT_RWLOCKSLEEP", + "THREAD_STAT_WAITING", // ??? (Waiting for a thread) + "THREAD_STAT_PREINIT", // Being created + "THREAD_STAT_ZOMBIE", // Died/Killed, but parent not informed + "THREAD_STAT_DEAD", // Awaiting burial (free) + "THREAD_STAT_BURIED" // If it's still on the list here, something's wrong +}; + /** * \brief IPC Message */ @@ -14,11 +47,14 @@ typedef struct sMessage typedef struct sProcess { + tTID PID; int nThreads; int NativePID; char *CWD; char *Chroot; int MaxFD; + + tUID UID, GID; } tProcess; struct sThread @@ -27,16 +63,16 @@ struct sThread struct sThread *Next; int KernelTID; + tProcess *Process; - tTID TID, PID; - tUID UID, GID; + tTID TID; struct sThread *Parent; - char *ThreadName; + int bInstrTrace; - int Status; // 0: Dead, 1: Active, 2: Paused, 3: Asleep - int ExitStatus; + enum eThreadStatus Status; // 0: Dead, 1: Active, 2: Paused, 3: Asleep + int RetStatus; int _errno; // Threads waiting for this thread to exit. @@ -48,31 +84,25 @@ struct sThread struct sThread *WaitingThreads; struct sThread *WaitingThreadsEnd; - tProcess *Process; + + tShortSpinlock IsLocked; + + void *WaitPointer; Uint32 EventState, WaitMask; void *EventSem; // Should be SDL_sem, but I don't want SDL in this header + void *ClientPtr; + // Message queue tMsg * volatile Messages; //!< Message Queue tMsg *LastMessage; //!< Last Message (speeds up insertion) }; -enum { - THREAD_STAT_NULL, // Invalid process - THREAD_STAT_ACTIVE, // Running and schedulable process - THREAD_STAT_SLEEPING, // Message Sleep - THREAD_STAT_MUTEXSLEEP, // Mutex Sleep - THREAD_STAT_SEMAPHORESLEEP, // Semaphore Sleep - THREAD_STAT_QUEUESLEEP, // Queue - THREAD_STAT_EVENTSLEEP, // Event sleep - THREAD_STAT_WAITING, // ??? (Waiting for a thread) - THREAD_STAT_PREINIT, // Being created - THREAD_STAT_ZOMBIE, // Died/Killed, but parent not informed - THREAD_STAT_DEAD, // Awaiting burial (free) - THREAD_STAT_BURIED // If it's still on the list here, something's wrong -}; extern struct sThread *Threads_GetThread(Uint TID); +extern void Threads_int_WaitForStatusEnd(enum eThreadStatus Status); +extern int Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, tThread **ListHead, tThread **ListTail, tShortSpinlock *Lock); +extern void Threads_AddActive(tThread *Thread); #endif diff --git a/AcessNative/acesskernel_src/server.c b/AcessNative/acesskernel_src/server.c index 45806e2b..f3826db7 100644 --- a/AcessNative/acesskernel_src/server.c +++ b/AcessNative/acesskernel_src/server.c @@ -33,22 +33,24 @@ typedef int socklen_t; typedef struct { int ClientID; SDL_Thread *WorkerThread; + tRequestHeader *CurrentRequest; + SDL_cond *WaitFlag; + SDL_mutex *Mutex; #if USE_TCP int Socket; #else - tRequestHeader *CurrentRequest; struct sockaddr_in ClientAddr; - SDL_cond *WaitFlag; - SDL_mutex *Mutex; #endif } tClient; // === IMPORTS === -extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength); +// TODO: Move these to headers +extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, size_t *ReturnLength); extern int Threads_CreateRootProcess(void); -extern void Threads_SetThread(int TID); +extern void Threads_SetThread(int TID, void *ClientPtr); extern void *Threads_GetThread(int TID); extern void Threads_PostEvent(void *Thread, uint32_t Event); +extern void Threads_int_Terminate(void *Thread); // === PROTOTYPES === tClient *Server_GetClient(int ClientID); @@ -70,10 +72,9 @@ SDL_Thread *gpServer_ListenThread; // === CODE === int Server_GetClientID(void) { - int i; Uint32 thisId = SDL_ThreadID(); - for( i = 0; i < MAX_CLIENTS; i ++ ) + for( int i = 0; i < MAX_CLIENTS; i ++ ) { if( SDL_GetThreadID(gaServer_Clients[i].WorkerThread) == thisId ) return gaServer_Clients[i].ClientID; @@ -87,13 +88,12 @@ int Server_GetClientID(void) tClient *Server_GetClient(int ClientID) { tClient *ret = NULL; - int i; // Allocate an ID if needed if(ClientID == 0) ClientID = Threads_CreateRootProcess(); - for( i = 0; i < MAX_CLIENTS; i ++ ) + for( int i = 0; i < MAX_CLIENTS; i ++ ) { if( gaServer_Clients[i].ClientID == ClientID ) { return &gaServer_Clients[i]; @@ -104,25 +104,23 @@ tClient *Server_GetClient(int ClientID) // Uh oh, no free slots // TODO: Dynamic allocation - if( !ret ) + if( !ret ) { + Log_Error("Server", "Ran out of static client slots (%i)", MAX_CLIENTS); return NULL; + } // Allocate a thread for the process ret->ClientID = ClientID; + ret->CurrentRequest = NULL; #if USE_TCP ret->Socket = 0; - #else - ret->CurrentRequest = NULL; #endif if( !ret->WorkerThread ) { - #if USE_TCP - #else + Log_Debug("Server", "Creating worker for %p", ret); ret->WaitFlag = SDL_CreateCond(); ret->Mutex = SDL_CreateMutex(); SDL_mutexP( ret->Mutex ); - #endif - Log_Debug("Server", "Creating worker for %p", ret); ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret ); } @@ -133,135 +131,12 @@ int Server_WorkerThread(void *ClientPtr) { tClient *Client = ClientPtr; - Log_Debug("Server", "Worker %p", ClientPtr); - - #if USE_TCP - while( *((volatile typeof(Client->Socket)*)&Client->Socket) == 0 ) - ; - Threads_SetThread( Client->ClientID ); - - while( Client->ClientID != -1 ) - { - fd_set fds; - int nfd = Client->Socket+1; - FD_ZERO(&fds); - FD_SET(Client->Socket, &fds); - - int rv = select(nfd, &fds, NULL, NULL, NULL); // TODO: Timeouts? - if(rv < 0) { - perror("select"); - continue ; - } -// Log_Debug("Server", "%p: rv=%i", Client, rv); - - if( FD_ISSET(Client->Socket, &fds) ) - { - const int ciMaxParamCount = 6; - char lbuf[sizeof(tRequestHeader) + ciMaxParamCount*sizeof(tRequestValue)]; - tRequestHeader *hdr = (void*)lbuf; - size_t len = recv(Client->Socket, (void*)hdr, sizeof(*hdr), 0); -// Log_Debug("Server", "%i bytes of header", len); - if( len == 0 ) { - Log_Notice("Server", "Zero RX on %i (worker %p)", Client->Socket, Client); - break; - } - if( len == -1 ) { - perror("recv header"); -// Log_Warning("Server", "recv() error - %s", strerror(errno)); - break; - } - if( len != sizeof(*hdr) ) { - // Oops? - Log_Warning("Server", "FD%i bad sized (%i != exp %i)", - Client->Socket, len, sizeof(*hdr)); - continue ; - } - - if( hdr->NParams > ciMaxParamCount ) { - // Oops. - Log_Warning("Server", "FD%i too many params (%i > max %i)", - Client->Socket, hdr->NParams, ciMaxParamCount); - break ; - } - - if( hdr->NParams > 0 ) - { - len = recv(Client->Socket, (void*)hdr->Params, hdr->NParams*sizeof(tRequestValue), 0); -// Log_Debug("Server", "%i bytes of params", len); - if( len != hdr->NParams*sizeof(tRequestValue) ) { - // Oops. - perror("recv params"); - Log_Warning("Sever", "Recieving params failed"); - break ; - } - } - else - { -// Log_Debug("Server", "No params?"); - } - - // Get buffer size - size_t hdrsize = sizeof(tRequestHeader) + hdr->NParams*sizeof(tRequestValue); - size_t bufsize = hdrsize; - int i; - for( i = 0; i < hdr->NParams; i ++ ) - { - if( hdr->Params[i].Flags & ARG_FLAG_ZEROED ) - ; - else { - bufsize += hdr->Params[i].Length; - } - } - - // Allocate full buffer - hdr = malloc(bufsize); - memcpy(hdr, lbuf, hdrsize); - if( bufsize > hdrsize ) - { - size_t rem = bufsize - hdrsize; - char *ptr = (void*)( hdr->Params + hdr->NParams ); - while( rem ) - { - len = recv(Client->Socket, ptr, rem, 0); -// Log_Debug("Server", "%i bytes of data", len); - if( len == -1 ) { - // Oops? - perror("recv data"); - Log_Warning("Sever", "Recieving data failed"); - break ; - } - rem -= len; - ptr += len; - } - if( rem ) { - break; - } - } -// else -// Log_Debug("Server", "no data"); + Log_Debug("Server", "Worker %p active", ClientPtr); - int retlen; - tRequestHeader *retHeader; - retHeader = SyscallRecieve(hdr, &retlen); - if( !retHeader ) { - // Some sort of error - Log_Warning("Server", "SyscallRecieve failed?"); - continue ; - } - - send(Client->Socket, (void*)retHeader, retlen, 0); - - // Clean up - free(hdr); - } - } - #else - tRequestHeader *retHeader; tRequestHeader errorHeader; - int retSize = 0; - int sentSize; + size_t retSize = 0; int cur_client_id = 0; - while( Client->ClientID != -1 ) + while( Client->ClientID != 0 ) { // Wait for something to do if( Client->CurrentRequest == NULL ) @@ -269,26 +144,13 @@ int Server_WorkerThread(void *ClientPtr) if( Client->CurrentRequest == NULL ) continue ; -// Log_Debug("AcessSrv", "Worker got message %p", Client->CurrentRequest); - if(Client->ClientID != cur_client_id) { -// Log_Debug("AcessSrv", "Client thread ID changed from %i to %i", -// cur_client_id, Client->ClientID); - Threads_SetThread( Client->ClientID ); + Threads_SetThread( Client->ClientID, Client ); cur_client_id = Client->ClientID; } - // Debug - { - int callid = Client->CurrentRequest->CallID; - Log_Debug("AcessSrv", "Client %i request %i %s", - Client->ClientID, callid, - callid < N_SYSCALLS ? casSYSCALL_NAMES[callid] : "UNK" - ); - } - // Get the response - retHeader = SyscallRecieve(Client->CurrentRequest, &retSize); + tRequestHeader *retHeader = SyscallRecieve(Client->CurrentRequest, &retSize); if( !retHeader ) { // Return an error to the client @@ -305,26 +167,27 @@ int Server_WorkerThread(void *ClientPtr) // Mark the thread as ready for another job free(Client->CurrentRequest); Client->CurrentRequest = 0; - -// Log_Debug("AcessSrv", "Sending %i to %x:%i (Client %i)", -// retSize, ntohl(Client->ClientAddr.sin_addr.s_addr), -// ntohs(Client->ClientAddr.sin_port), -// Client->ClientID -// ); - - // Return the data - sentSize = sendto(gSocket, retHeader, retSize, 0, - (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr) - ); - if( sentSize != retSize ) { - perror("Server_WorkerThread - send"); + + // If the thread is being terminated, don't send reply + if( Client->ClientID > 0 ) + { + // Return the data + #if USE_TCP + size_t sentSize = send(Client->Socket, retHeader, retSize, 0); + #else + size_t sentSize = sendto(gSocket, retHeader, retSize, 0, + (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr) + ); + #endif + if( sentSize != retSize ) { + perror("Server_WorkerThread - send"); + } } // Free allocated header if( retHeader != &errorHeader ) free( retHeader ); } - #endif Log_Notice("Server", "Terminated Worker %p", ClientPtr); return 0; } @@ -405,83 +268,243 @@ int Server_Shutdown(void) return 0; } +#if USE_TCP +int Server_int_HandleRx(tClient *Client) +{ + const int ciMaxParamCount = 6; + char lbuf[sizeof(tRequestHeader) + ciMaxParamCount*sizeof(tRequestValue)]; + tRequestHeader *hdr = (void*)lbuf; + size_t len = recv(Client->Socket, (void*)hdr, sizeof(*hdr), 0); + if( len == 0 ) { + Log_Notice("Server", "Zero RX on %i (worker %p)", Client->Socket, Client); + return 1; + } + if( len == -1 ) { + perror("recv header"); + return 2; + } + if( len != sizeof(*hdr) ) { + // Oops? + Log_Warning("Server", "FD%i bad sized (%i != exp %i)", + Client->Socket, len, sizeof(*hdr)); + return 0; + } + + if( hdr->NParams > ciMaxParamCount ) { + // Oops. + Log_Warning("Server", "FD%i too many params (%i > max %i)", + Client->Socket, hdr->NParams, ciMaxParamCount); + return 0; + } + + if( hdr->NParams > 0 ) + { + len = recv(Client->Socket, (void*)hdr->Params, hdr->NParams*sizeof(tRequestValue), 0); + if( len != hdr->NParams*sizeof(tRequestValue) ) { + // Oops. + perror("recv params"); + Log_Warning("Sever", "Recieving params failed"); + return 0; + } + } + else + { + //Log_Debug("Server", "No params?"); + } + + // Get buffer size + size_t hdrsize = sizeof(tRequestHeader) + hdr->NParams*sizeof(tRequestValue); + size_t bufsize = hdrsize; + for( int i = 0; i < hdr->NParams; i ++ ) + { + if( hdr->Params[i].Flags & ARG_FLAG_ZEROED ) + ; + else { + bufsize += hdr->Params[i].Length; + } + } + + // Allocate full buffer + hdr = malloc(bufsize); + memcpy(hdr, lbuf, hdrsize); + if( bufsize > hdrsize ) + { + size_t rem = bufsize - hdrsize; + char *ptr = (void*)( hdr->Params + hdr->NParams ); + while( rem ) + { + len = recv(Client->Socket, ptr, rem, 0); + if( len == -1 ) { + // Oops? + perror("recv data"); + Log_Warning("Sever", "Recieving data failed"); + return 2; + } + rem -= len; + ptr += len; + } + if( rem ) { + // Extra data? + return 0; + } + } + else { + //Log_Debug("Server", "no data"); + } + + // Dispatch to worker + if( Client->CurrentRequest ) { + printf("Worker thread for client ID %i is busy\n", Client->ClientID); + return 1; + } + + // Give to worker + Log_Debug("Server", "Message from Client %i (%p)", Client->ClientID, Client); + Client->CurrentRequest = hdr; + SDL_CondSignal(Client->WaitFlag); + + return 0; +} + +int Server_int_HandshakeClient(int Socket, struct sockaddr_in *addr, socklen_t addr_size) +{ + ENTER("iSocket paddr iaddr_size", + Socket, addr, addr_size); + unsigned short port = ntohs(addr->sin_port); + char addrstr[4*8+8+1]; + getnameinfo((struct sockaddr*)addr, addr_size, addrstr, sizeof(addrstr), NULL, 0, NI_NUMERICHOST); + Log_Debug("Server", "Client connection %s:%i", addrstr, port); + + // Perform handshake + tRequestAuthHdr authhdr; + size_t len = recv(Socket, &authhdr, sizeof(authhdr), 0); + if( len != sizeof(authhdr) ) { + // Some form of error? + Log_Warning("Server", "Client auth block bad size (%i != exp %i)", + len, sizeof(authhdr)); + LEAVE('i', 1); + return 1; + } + + LOG("authhdr.pid = %i", authhdr.pid); + tClient *client = Server_GetClient(authhdr.pid); + if( authhdr.pid == 0 ) { + // Allocate PID and client structure/thread + client->Socket = Socket; + authhdr.pid = client->ClientID; + } + else { + Log_Debug("Server", "Client assumed PID %i", authhdr.pid); + + // Get client structure and make sure it's unused + // - Auth token / verifcation? + if( !client ) { + Log_Warning("Server", "Can't allocate a client struct for %s:%i", + addrstr, port); + LEAVE('i', 1); + return 1; + } + if( client->Socket != 0 ) { + Log_Warning("Server", "Client (%i)%p owned by FD%i but %s:%i tried to use it", + authhdr.pid, client, addrstr, port); + LEAVE('i', 1); + return 1; + } + + client->Socket = Socket; + } + + LOG("Sending auth reply"); + len = send(Socket, (void*)&authhdr, sizeof(authhdr), 0); + if( len != sizeof(authhdr) ) { + // Ok, this is an error + perror("Sending auth reply"); + LEAVE('i', 1); + return 1; + } + + // All done, client thread should be watching now + + LEAVE('i', 0); + return 0; +} + +void Server_int_RemoveClient(tClient *Client) +{ + // Trigger the thread to kill itself + Threads_int_Terminate( Threads_GetThread(Client->ClientID) ); + Client->ClientID = 0; + close(Client->Socket); +} + +#endif + int Server_ListenThread(void *Unused) { // Wait for something to do :) for( ;; ) { #if USE_TCP - struct sockaddr_in clientaddr; - socklen_t clientSize = sizeof(clientaddr); - int clientSock = accept(gSocket, (struct sockaddr*)&clientaddr, &clientSize); - if( clientSock < 0 ) { - perror("SyscallServer - accept"); - break ; - } + fd_set fds; + int maxfd = gSocket; + FD_ZERO(&fds); + FD_SET(gSocket, &fds); - char addrstr[4*8+8+1]; - getnameinfo((struct sockaddr*)&clientaddr, sizeof(clientaddr), - addrstr, sizeof(addrstr), NULL, 0, NI_NUMERICHOST); - Log_Debug("Server", "Client connection %s:%i", addrstr, ntohs(clientaddr.sin_port)); - - // Perform auth - size_t len; - tRequestAuthHdr authhdr; - len = recv(clientSock, (void*)&authhdr, sizeof(authhdr), 0); - if( len != sizeof(authhdr) ) { - // Some form of error? - Log_Warning("Server", "Client auth block bad size (%i != exp %i)", - len, sizeof(authhdr)); - close(clientSock); - continue ; + for( int i = 0; i < MAX_CLIENTS; i ++ ) { + tClient *client = &gaServer_Clients[i]; + if( client->ClientID == 0 ) + continue ; + FD_SET(client->Socket, &fds); + if(client->Socket > maxfd) + maxfd = client->Socket; } - Log_Debug("Server", "Client assumed PID %i", authhdr.pid); - - tClient *client; - if( authhdr.pid == 0 ) { - // Allocate PID and client structure/thread - client = Server_GetClient(0); - client->Socket = clientSock; - authhdr.pid = client->ClientID; + int rv = select(maxfd+1, &fds, NULL, NULL, NULL); + Log_Debug("Server", "Select rv = %i", rv); + if( rv <= 0 ) { + perror("select"); + return 1; } - else { - // Get client structure and make sure it's unused - // - Auth token / verifcation? - client = Server_GetClient(authhdr.pid); - if( !client ) { - Log_Warning("Server", "Can't allocate a client struct for %s:%i", - addrstr, clientaddr.sin_port); - close(clientSock); - continue ; + + // Incoming connection + if( FD_ISSET(gSocket, &fds) ) + { + struct sockaddr_in clientaddr; + socklen_t clientSize = sizeof(clientaddr); + int clientSock = accept(gSocket, (struct sockaddr*)&clientaddr, &clientSize); + if( clientSock < 0 ) { + perror("SyscallServer - accept"); + break ; } - if( client->Socket != 0 ) { - Log_Warning("Server", "Client (%i)%p owned by FD%i but %s:%i tried to use it", - authhdr.pid, client, addrstr, clientaddr.sin_port); + if( Server_int_HandshakeClient(clientSock, &clientaddr, clientSize) ) { + Log_Warning("Server", "Client handshake failed :("); close(clientSock); - continue; - } - else { - client->Socket = clientSock; } } - Log_Debug("Server", "Client given PID %i - info %p", authhdr.pid, client); - len = send(clientSock, (void*)&authhdr, sizeof(authhdr), 0); - if( len != sizeof(authhdr) ) { - // Ok, this is an error - perror("Sending auth reply"); + for( int i = 0; i < MAX_CLIENTS; i ++ ) + { + tClient *client = &gaServer_Clients[i]; + if( client->ClientID == 0 ) + continue ; + //Debug("Server_ListenThread: Idx %i ID %i FD %i", + // i, client->ClientID, client->Socket); + if( !FD_ISSET(client->Socket, &fds) ) + continue ; + + if( Server_int_HandleRx( client ) ) + { + Log_Warning("Server", "Client %p dropped, TODO: clean up", client); + Server_int_RemoveClient(client); + } } - - // All done, client thread should be watching now - + #else char data[BUFSIZ]; tRequestHeader *req = (void*)data; struct sockaddr_in addr; uint clientSize = sizeof(addr); int length; - tClient *client; length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize); @@ -490,13 +513,13 @@ int Server_ListenThread(void *Unused) break; } - // Hand off to a worker thread - // - TODO: Actually have worker threads + // Recive data // Log_Debug("Server", "%i bytes from %x:%i", length, // ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port)); - client = Server_GetClient(req->ClientID); - // NOTE: Hack - Should check if all zero + tClient *client = Server_GetClient(req->ClientID); + // NOTE: I should really check if the sin_addr is zero, but meh + // Shouldn't matter much if( req->ClientID == 0 || client->ClientAddr.sin_port == 0 ) { memcpy(&client->ClientAddr, &addr, sizeof(addr)); @@ -510,16 +533,15 @@ int Server_ListenThread(void *Unused) continue; } +// Log_Debug("AcessSrv", "Message from Client %i (%p)", +// client->ClientID, client); if( client->CurrentRequest ) { printf("Worker thread for %x:%i is busy\n", ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port)); continue; } -// Log_Debug("AcessSrv", "Message from Client %i (%p)", -// client->ClientID, client); - - // Make a copy of the request data + // Duplicate the data currently on the stack, and dispatch to worker req = malloc(length); memcpy(req, data, length); client->CurrentRequest = req; diff --git a/AcessNative/acesskernel_src/syscalls.c b/AcessNative/acesskernel_src/syscalls.c index 4194a36a..ae2c92c3 100644 --- a/AcessNative/acesskernel_src/syscalls.c +++ b/AcessNative/acesskernel_src/syscalls.c @@ -277,12 +277,12 @@ const int ciNumSyscalls = sizeof(caSyscalls)/sizeof(caSyscalls[0]); /** * \brief Recieve a syscall structure from the server code */ -tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength) +tRequestHeader *SyscallRecieve(tRequestHeader *Request, size_t *ReturnLength) { char formatString[Request->NParams+1]; char *inData = (char*)&Request->Params[Request->NParams]; int argListLen = 0; - int i, retVal; + int retVal; tRequestHeader *ret; int retValueCount; int retDataLen; @@ -309,7 +309,7 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength) retDataLen = sizeof(Uint64) + sizeof(Uint32); // Get size of argument list - for( i = 0; i < Request->NParams; i ++ ) + for( int i = 0; i < Request->NParams; i ++ ) { argSizes[i] = Request->Params[i].Length; switch(Request->Params[i].Type) @@ -344,7 +344,7 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength) return NULL; // ERROR! } } - formatString[i] = '\0'; + formatString[Request->NParams] = '\0'; LOG("Request %i(%s) '%s'", Request->CallID, casSYSCALL_NAMES[Request->CallID], formatString); @@ -352,7 +352,7 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength) char argListData[argListLen]; argListLen = 0; // Build argument list - for( i = 0; i < Request->NParams; i ++ ) + for( int i = 0; i < Request->NParams; i ++ ) { returnData[i] = NULL; switch(Request->Params[i].Type) @@ -449,7 +449,7 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength) //Log_Debug("Syscalls", "Return 0x%llx", retVal); retValueCount = 2; - for( i = 0; i < Request->NParams; i ++ ) + for( int i = 0; i < Request->NParams; i ++ ) { if( Request->Params[i].Type != ARG_TYPE_DATA ) continue; if( !(Request->Params[i].Flags & ARG_FLAG_RETURN) ) continue; diff --git a/AcessNative/acesskernel_src/threads.c b/AcessNative/acesskernel_src/threads.c index de61ef47..86b8a892 100644 --- a/AcessNative/acesskernel_src/threads.c +++ b/AcessNative/acesskernel_src/threads.c @@ -5,7 +5,7 @@ * threads.c * - Thread and process handling */ - +#define DEBUG 1 #include #include #include @@ -17,12 +17,14 @@ typedef signed long long int time_t; #include #include #include "include/threads_glue.h" +#include #define THREAD_EVENT_WAKEUP 0x80000000 // === IMPORTS === extern void VFS_CloneHandleList(int PID); extern void VFS_CloneHandlesFromList(int PID, int nFD, int FDs[]); +extern void VFS_ClearHandles(int PID); // === STRUCTURES === // === PROTOTYPES === @@ -52,25 +54,24 @@ tThread *Proc_GetCurThread(void) void Threads_Dump(void) { - tThread *thread; - for( thread = gpThreads; thread; thread = thread->GlobalNext ) + for( tThread *thread = gpThreads; thread; thread = thread->GlobalNext ) { Log_Log("Threads", "TID %i (%s), PID %i", - thread->TID, thread->ThreadName, thread->PID); + thread->TID, thread->ThreadName, thread->Process->PID); Log_Log("Threads", "User: %i, Group: %i", - thread->UID, thread->GID); + thread->Process->UID, thread->Process->GID); Log_Log("Threads", "Kernel Thread ID: %i", thread->KernelTID); } } -void Threads_SetThread(int TID) +void Threads_SetThread(int TID, void *Client) { - tThread *thread; - for( thread = gpThreads; thread; thread = thread->GlobalNext ) + for( tThread *thread = gpThreads; thread; thread = thread->GlobalNext ) { if( thread->TID == TID ) { gpCurrentThread = thread; + thread->ClientPtr = Client; return ; } } @@ -79,8 +80,7 @@ void Threads_SetThread(int TID) tThread *Threads_GetThread(Uint TID) { - tThread *thread; - for( thread = gpThreads; thread; thread = thread->GlobalNext ) + for( tThread *thread = gpThreads; thread; thread = thread->GlobalNext ) { if( thread->TID == TID ) { return thread; @@ -92,10 +92,9 @@ tThread *Threads_GetThread(Uint TID) /** * \brief Clone a thread control block (with a different TID) */ -tThread *Threads_CloneTCB(tThread *TemplateThread) +tThread *Threads_CloneTCB(tThread *TemplateThread, bool bNewProcess) { tThread *ret = malloc(sizeof(tThread)); - memcpy(ret, TemplateThread, sizeof(tThread)); ret->TID = giThreads_NextThreadID ++; @@ -105,7 +104,22 @@ tThread *Threads_CloneTCB(tThread *TemplateThread) ret->WaitingThreads = NULL; ret->WaitingThreadsEnd = NULL; - + + if( bNewProcess ) + { + tProcess *proc = malloc( sizeof(tProcess) ); + memcpy(proc, ret->Process, sizeof(tProcess)); + proc->nThreads = 0; + proc->CWD = strdup(proc->CWD); + proc->Chroot = strdup(proc->Chroot); + + proc->PID = ret->TID; + + ret->Process = proc; + } + + ret->Process->nThreads ++; + // Add to the end of the queue // TODO: Handle concurrency issues ret->GlobalNext = gpThreads; @@ -114,10 +128,53 @@ tThread *Threads_CloneTCB(tThread *TemplateThread) return ret; } -tUID Threads_GetUID() { return gpCurrentThread->UID; } -tGID Threads_GetGID() { return gpCurrentThread->GID; } +void Threads_int_Destroy(tThread *Thread) +{ + // Clear WaitingThreads + + Threads_Glue_SemDestroy(Thread->EventSem); + free(Thread->ThreadName); + Thread->Process->nThreads --; +} + +void Threads_Terminate(void) +{ + tThread *us = gpCurrentThread; + tProcess *proc = us->Process; + + if( us->TID == proc->PID ) + { + // If we're the process leader, then tear down the entire process + VFS_ClearHandles(proc->PID); + tThread **next_ptr = &gpThreads; + for( tThread *thread = gpThreads; thread; thread = *next_ptr ) + { + if( thread->Process == proc ) { + Threads_int_Destroy(thread); + } + else { + next_ptr = &thread->Next; + } + } + } + else + { + // Just a lowly thread, remove from process + Threads_int_Destroy(us); + } + + if( proc->nThreads == 0 ) + { + free(proc->Chroot); + free(proc->CWD); + free(proc); + } +} + +tUID Threads_GetUID() { return gpCurrentThread->Process->UID; } +tGID Threads_GetGID() { return gpCurrentThread->Process->GID; } tTID Threads_GetTID() { return gpCurrentThread->TID; } -tPID Threads_GetPID() { return gpCurrentThread->PID; } +tPID Threads_GetPID() { return gpCurrentThread->Process->PID; } int Threads_SetUID(tUID NewUID) { @@ -126,7 +183,7 @@ int Threads_SetUID(tUID NewUID) return -1; } - gpCurrentThread->UID = NewUID; + gpCurrentThread->Process->UID = NewUID; return 0; } @@ -137,7 +194,7 @@ int Threads_SetGID(tGID NewGID) return -1; } - gpCurrentThread->GID = NewGID; + gpCurrentThread->Process->GID = NewGID; return 0; } @@ -167,8 +224,8 @@ tTID Threads_WaitTID(int TID, int *Status) } // Specific Thread - if(TID > 0) { - + if(TID > 0) + { tThread *thread = Threads_GetThread(TID); tThread *us = gpCurrentThread; if(!thread) return -1; @@ -189,7 +246,7 @@ tTID Threads_WaitTID(int TID, int *Status) Threads_WaitEvents( THREAD_EVENT_WAKEUP ); - if(Status) *Status = thread->ExitStatus; + if(Status) *Status = thread->RetStatus; thread->WaitingThreads = thread->WaitingThreads->Next; us->Next = NULL; @@ -199,24 +256,13 @@ tTID Threads_WaitTID(int TID, int *Status) return 0; } -void Threads_Sleep(void) -{ - // TODO: Add to a sleeping queue - //pause(); -} - -void Threads_Yield(void) -{ -// yield(); -} - void Threads_Exit(int TID, int Status) { tThread *toWake; // VFS_Handles_Cleanup(); - gpCurrentThread->ExitStatus = Status; + gpCurrentThread->RetStatus = Status; #if 1 if( gpCurrentThread->Parent ) @@ -238,6 +284,12 @@ void Threads_Exit(int TID, int Status) } } +void Threads_Sleep() +{ + gpCurrentThread->Status = THREAD_STAT_SLEEPING; + Threads_int_WaitForStatusEnd(THREAD_STAT_SLEEPING); +} + int Threads_Wake(tThread *Thread) { Thread->Status = THREAD_STAT_ACTIVE; @@ -255,121 +307,108 @@ int Threads_WakeTID(tTID TID) int Threads_CreateRootProcess(void) { - tThread *thread = Threads_CloneTCB(&gThreadZero); - thread->PID = thread->TID; + tThread *thread = Threads_CloneTCB(&gThreadZero, true); // Handle list is created on first open - return thread->PID; + return thread->Process->PID; } int Threads_Fork(void) { - tThread *thread = Threads_CloneTCB(gpCurrentThread); - thread->PID = thread->TID; + tThread *thread = Threads_CloneTCB(gpCurrentThread, true); // Duplicate the VFS handles (and nodes) from vfs_handle.c - VFS_CloneHandleList(thread->PID); + VFS_CloneHandleList(thread->Process->PID); - return thread->PID; + return thread->Process->PID; } int Threads_Spawn(int nFD, int FDs[], struct s_sys_spawninfo *info) { - tThread *thread = Threads_CloneTCB(gpCurrentThread); - thread->PID = thread->TID; + tThread *thread = Threads_CloneTCB(gpCurrentThread, true); if( info ) { // TODO: PGID? //if( info->flags & SPAWNFLAG_NEWPGID ) // thread->PGID = thread->PID; - if( info->gid && thread->UID == 0 ) - thread->GID = info->gid; - if( info->uid && thread->UID == 0 ) // last because ->UID is used above - thread->UID = info->uid; + if( thread->Process->UID == 0 ) + { + if( info->gid ) + thread->Process->GID = info->gid; + if( info->uid ) + thread->Process->UID = info->uid; + } } - VFS_CloneHandlesFromList(thread->PID, nFD, FDs); + VFS_CloneHandlesFromList(thread->Process->PID, nFD, FDs); - Log_Debug("Threads", "_spawn: %i", thread->PID); - return thread->PID; -} - -// -------------------------------------------------------------------- -// Mutexes -// -------------------------------------------------------------------- -int Mutex_Acquire(tMutex *Mutex) -{ - Threads_Glue_AcquireMutex(&Mutex->Protector.Mutex); - return 0; -} - -void Mutex_Release(tMutex *Mutex) -{ - Threads_Glue_ReleaseMutex(&Mutex->Protector.Mutex); -} - -// -------------------------------------------------------------------- -// Semaphores -// -------------------------------------------------------------------- -void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name) -{ - memset(Sem, 0, sizeof(tSemaphore)); - // HACK: Use `Sem->Protector` as space for the semaphore pointer - Threads_Glue_SemInit( &Sem->Protector.Mutex, InitValue ); + return thread->Process->PID; } -int Semaphore_Wait(tSemaphore *Sem, int MaxToTake) +// ---- +// ---- +void Threads_int_Terminate(tThread *Thread) { - return Threads_Glue_SemWait( Sem->Protector.Mutex, MaxToTake ); + Thread->RetStatus = -1; + Threads_AddActive(Thread); } -int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd) +void Threads_int_WaitForStatusEnd(enum eThreadStatus Status) { - return Threads_Glue_SemSignal( Sem->Protector.Mutex, AmmountToAdd ); -} - -// -------------------------------------------------------------------- -// Event handling -// -------------------------------------------------------------------- -Uint32 Threads_WaitEvents(Uint32 Mask) -{ - Uint32 rv; - - //Log_Debug("Threads", "Mask = %x, ->Events = %x", Mask, gpCurrentThread->Events); - - gpCurrentThread->WaitMask = Mask; - if( !(gpCurrentThread->EventState & Mask) ) + tThread *us = Proc_GetCurThread(); + ASSERT(Status != THREAD_STAT_ACTIVE); + ASSERT(Status != THREAD_STAT_DEAD); + LOG("%i(%s) - %i", us->TID, us->ThreadName, Status); + while( us->Status == Status ) { if( Threads_Glue_SemWait(gpCurrentThread->EventSem, INT_MAX) == -1 ) { Log_Warning("Threads", "Wait on eventsem of %p, %p failed", gpCurrentThread, gpCurrentThread->EventSem); + return ; } - //Log_Debug("Threads", "Woken from nap (%i here)", SDL_SemValue(gpCurrentThread->EventSem)); + if( us->Status == Status ) + Log_Warning("Threads", "Thread %p(%i %s) rescheduled while in %s state", + us, us->TID, us->ThreadName, casTHREAD_STAT[Status]); } - rv = gpCurrentThread->EventState & Mask; - gpCurrentThread->EventState &= ~Mask; - gpCurrentThread->WaitMask = -1; - - //Log_Debug("Threads", "- rv = %x", rv); - - return rv; } -void Threads_PostEvent(tThread *Thread, Uint32 Events) +int Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, tThread **ListHead, tThread **ListTail, tShortSpinlock *Lock) { - Thread->EventState |= Events; -// Log_Debug("Threads", "Trigger event %x (->Events = %p) on %p", Events, Thread->Events, Thread); - - if( Events == 0 || Thread->WaitMask & Events ) { - Threads_Glue_SemSignal( Thread->EventSem, 1 ); -// Log_Debug("Threads", "Waking %p(%i %s)", Thread, Thread->TID, Thread->ThreadName); + tThread *us = Proc_GetCurThread(); + us->Next = NULL; + // - Mark as sleeping + us->Status = Status; + us->WaitPointer = Ptr; + us->RetStatus = Num; // Use RetStatus as a temp variable + + // - Add to waiting + if( ListTail ) { + if(*ListTail) { + (*ListTail)->Next = us; + } + else { + *ListHead = us; + } + *ListTail = us; } + else { + *ListHead = us; + } + + if( Lock ) { + SHORTREL( Lock ); + } + Threads_int_WaitForStatusEnd(Status); + us->WaitPointer = NULL; + return us->RetStatus; } -void Threads_ClearEvent(Uint32 EventMask) +void Threads_AddActive(tThread *Thread) { - gpCurrentThread->EventState &= ~EventMask; + LOG("%i(%s)", Thread->TID, Thread->ThreadName); + Thread->Status = THREAD_STAT_ACTIVE; + Threads_Glue_SemSignal(Thread->EventSem, 1); } // -------------------------------------------------------------------- diff --git a/AcessNative/acesskernel_src/threads_glue.c b/AcessNative/acesskernel_src/threads_glue.c index d400b27b..c2efb713 100644 --- a/AcessNative/acesskernel_src/threads_glue.c +++ b/AcessNative/acesskernel_src/threads_glue.c @@ -18,7 +18,6 @@ typedef void **tShortSpinlock; //#include "/usr/include/signal.h" #include #include -#include #define NORETURN __attribute__((noreturn)) #include // Kernel land, but uses standards @@ -66,35 +65,31 @@ int Threads_Glue_SemWait(void *Ptr, int Max) int Threads_Glue_SemSignal( void *Ptr, int AmmountToAdd ) { - int i; - for( i = 0; i < AmmountToAdd; i ++ ) + for( int i = 0; i < AmmountToAdd; i ++ ) SDL_SemPost( Ptr ); return AmmountToAdd; } -// -------------------------------------------------------------------- -// Event handling -// -------------------------------------------------------------------- -int RWLock_AcquireRead(tRWLock *Lock) +void Threads_Glue_SemDestroy( void *Ptr ) { - if( !Lock->ReaderWaiting ) { - Lock->ReaderWaiting = malloc(sizeof(pthread_rwlock_t)); - pthread_rwlock_init( (void*)Lock->ReaderWaiting, 0 ); - } - pthread_rwlock_rdlock( (void*)Lock->ReaderWaiting ); - return 0; + SDL_DestroySemaphore(Ptr); } -int RWLock_AcquireWrite(tRWLock *Lock) + +// --- +// Short Locks +// --- +void Threads_int_ShortLock(void **MutexPtr) { - if( !Lock->ReaderWaiting ) { - Lock->ReaderWaiting = malloc(sizeof(pthread_rwlock_t)); - pthread_rwlock_init( (void*)Lock->ReaderWaiting, 0 ); + if( !*MutexPtr ) { + *MutexPtr = malloc( sizeof(pthread_mutex_t) ); + pthread_mutex_init(*MutexPtr, NULL); } - pthread_rwlock_wrlock( (void*)Lock->ReaderWaiting ); - return 0; + pthread_mutex_lock(*MutexPtr); } -void RWLock_Release(tRWLock *Lock) + +void Threads_int_ShortRel(void **MutexPtr) { - pthread_rwlock_unlock( (void*)Lock->ReaderWaiting ); + pthread_mutex_unlock(*MutexPtr); } + diff --git a/AcessNative/acesskernel_src/vfs_handle.c b/AcessNative/acesskernel_src/vfs_handle.c index eb0bfc58..6c3992f8 100644 --- a/AcessNative/acesskernel_src/vfs_handle.c +++ b/AcessNative/acesskernel_src/vfs_handle.c @@ -155,11 +155,10 @@ tVFS_Handle *VFS_GetHandle(int FD) } else { - tUserHandles *ent; int pid = Threads_GetPID(); int maxhandles = *Threads_GetMaxFD(); - ent = VFS_int_GetUserHandles(pid, 0); + tUserHandles *ent = VFS_int_GetUserHandles(pid, 0); if(!ent) { Log_Error("VFS", "Client %i does not have a handle list (>)", pid); return NULL; @@ -248,3 +247,18 @@ int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode) return -1; } + +void VFS_ClearHandles(int PID) +{ + // Find the PID's handle list + tUserHandles *ent = VFS_int_GetUserHandles(PID, 0); + if( !ent ) return; + // Get a handle + int maxhandles = *Threads_GetMaxFD(); + for( int i = 0; i < maxhandles; i ++ ) + { + if(ent->Handles[i].Node) continue; + _CloseNode(ent->Handles[i].Node); + ent->Handles[i].Node = NULL; + } +} -- 2.20.1