LDACESS_SRC = ../../Usermode/Libraries/ld-acess.so_src/\r
\r
KERNEL_OBJ := logging.o adt.o lib.o debug.o messages.o drvutil_disk.o drvutil_video.o\r
+KERNEL_OBJ += mutex.o semaphore.o rwlock.o workqueue.o events.o\r
#KERNEL_OBJ += libc.o\r
KERNEL_OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/io.o vfs/dir.o\r
KERNEL_OBJ += vfs/nodecache.o vfs/mount.o vfs/memfile.o vfs/select.o\r
\r
$(BIN): $(OBJ) $(N_OBJ) $(K_OBJ) $(BUILDINFO_OBJ)\r
@echo [LINK] -o $@\r
- @$(CC) -o $@ $(N_OBJ) $(K_OBJ) $(OBJ) $(BUILDINFO_OBJ) $(LDFLAGS)\r
+ @$(CC) -o $@ $(N_OBJ) $(LDFLAGS) $(K_OBJ) $(OBJ) $(BUILDINFO_OBJ)\r
@echo BUILD_NUM = $$(( $(BUILD_NUM) + 1 )) > Makefile.BuildNum\r
\r
$(OBJ): obj-$(PLATFORM)/%.o: %.c\r
typedef int BOOL;
+#define HALT_CPU() exit(1)
+
#include <stddef.h>
#undef offsetof
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
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
#ifndef _THREADS_INT_H_
#define _THREADS_INT_H_
+#include <threads.h>
+
+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
*/
typedef struct sProcess
{
+ tTID PID;
int nThreads;
int NativePID;
char *CWD;
char *Chroot;
int MaxFD;
+
+ tUID UID, GID;
} tProcess;
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.
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
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);
// === 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;
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];
// 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 );
}
{
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 )
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
// 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;
}
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);
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));
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;
/**
* \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;
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)
return NULL; // ERROR!
}
}
- formatString[i] = '\0';
+ formatString[Request->NParams] = '\0';
LOG("Request %i(%s) '%s'", Request->CallID, casSYSCALL_NAMES[Request->CallID], formatString);
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)
//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;
* threads.c
* - Thread and process handling
*/
-
+#define DEBUG 1
#include <arch.h>
#include <acess.h>
#include <mutex.h>
#include <threads_int.h>
#include <limits.h>
#include "include/threads_glue.h"
+#include <stdbool.h>
#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 ===
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 ;
}
}
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;
/**
* \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 ++;
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;
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)
{
return -1;
}
- gpCurrentThread->UID = NewUID;
+ gpCurrentThread->Process->UID = NewUID;
return 0;
}
return -1;
}
- gpCurrentThread->GID = NewGID;
+ gpCurrentThread->Process->GID = NewGID;
return 0;
}
}
// Specific Thread
- if(TID > 0) {
-
+ if(TID > 0)
+ {
tThread *thread = Threads_GetThread(TID);
tThread *us = gpCurrentThread;
if(!thread) return -1;
Threads_WaitEvents( THREAD_EVENT_WAKEUP );
- if(Status) *Status = thread->ExitStatus;
+ if(Status) *Status = thread->RetStatus;
thread->WaitingThreads = thread->WaitingThreads->Next;
us->Next = NULL;
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 )
}
}
+void Threads_Sleep()
+{
+ gpCurrentThread->Status = THREAD_STAT_SLEEPING;
+ Threads_int_WaitForStatusEnd(THREAD_STAT_SLEEPING);
+}
+
int Threads_Wake(tThread *Thread)
{
Thread->Status = THREAD_STAT_ACTIVE;
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);
}
// --------------------------------------------------------------------
//#include "/usr/include/signal.h"
#include <SDL/SDL.h>
#include <pthread.h>
-#include <assert.h>
#define NORETURN __attribute__((noreturn))
#include <logdebug.h> // Kernel land, but uses standards
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);
}
+
}
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;
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;
+ }
+}