#include <stdio.h>
#include <errno.h>
#include <OS.h>
+#include "utils/elog.h"
+
+
+/* Control of a semaphore pool. The pool is an area in which we stored all
+the semIds of the pool. The first 4 bytes are the number of semaphore allocated
+in the pool followed by SemIds */
-// Controle d'un pool de sémaphores
-// On considere que le semId utilisé correspond bien a une area de notre adress space
-// Les informations du pool de sémaphore sont stockés dans cette area
int semctl(int semId,int semNum,int flag,union semun semun)
{
-
- // Recherche de l'adresse de base de l'area
int32* Address;
area_info info;
-// printf("semctl : semid %d, semnum %d, cmd %d\n",semId,semNum,flag);
+
+ /* Try to find the pool */
if (get_area_info(semId,&info)!=B_OK)
{
-// printf("area not found\n");
+ /* pool is invalid (BeOS area id is invalid) */
errno=EINVAL;
return -1;
}
+
+ /* Get the pool address */
Address=(int32*)info.address;
- // semnum peut etre égal à 0
- // semun.array contient la valeur de départ du sémaphore
- // si flag = set_all il faut définir la valeur du sémaphore sue semun.array
+ /* semNum might be 0 */
+ /* semun.array contain the sem initial values */
+
+ /* Fix the count of all sem of the pool to semun.array */
if (flag==SETALL)
{
long i;
-// printf("setall %d\n",Address[0]);
for (i=0;i<Address[0];i++)
{
int32 cnt;
+ /* Get the current count */
get_sem_count(Address[i+1],&cnt);
-// printf("Set de ALl %d %d = %d\n",Address[i+1],semun.array[i],cnt);
+
+ /* Compute and set the new count (relative to the old one) */
cnt-=semun.array[i];
if (cnt > 0)
- acquire_sem_etc(Address[i+1],cnt,0,0);
+ while(acquire_sem_etc(Address[i+1],cnt,0,0)==B_INTERRUPTED);
if (cnt < 0)
release_sem_etc(Address[i+1],-cnt,0);
}
return 1;
}
- /* si flag = SET_VAL il faut définir la valeur du sémaphore sur semun.val*/
+ /* Fix the count of one semaphore to semun.val */
if (flag==SETVAL)
{
int32 cnt;
+ /* Get the current count */
get_sem_count(Address[semNum+1],&cnt);
-// printf("semctl set val id : %d val : %d = %d\n",semId,semun.val,cnt);
+
+ /* Compute and set the new count (relative to the old one) */
cnt-=semun.val;
if (cnt > 0)
- acquire_sem_etc(Address[semNum+1],cnt,0,0);
+ while(acquire_sem_etc(Address[semNum+1],cnt,0,0)==B_INTERRUPTED);
if (cnt < 0)
release_sem_etc(Address[semNum+1],-cnt,0);
return 1;
}
- /* si flag=rm_id il faut supprimer le sémaphore*/
+ /* Delete the pool */
if (flag==IPC_RMID)
{
long i;
- // Suppression des sémaphores (ils appartienent au kernel maintenant)
+
thread_info ti;
-// printf("remove set\n");
get_thread_info(find_thread(NULL),&ti);
+
+ /* Loop over all semaphore to delete them */
for (i=0;i<Address[0];i++)
{
+ /* Don't remember why I do that */
set_sem_owner(Address[i+1],ti.team);
+
+ /* Delete the semaphore */
delete_sem(Address[i+1]);
+
+ /* Reset to an invalid semId (in case other process try to get the infos from a cloned area */
+ Address[i+1]=0;
}
- // Il faudrait supprimer en boucle toutes les area portant le même nom
+
+ /* Set the semaphore count to 0 */
+ Address[0]=0;
+
+ /* Delete the area (it might be cloned by other process. Let them live with it,
+ in all cases semIds are 0 so if another process try to use it, it will fail */
delete_area(semId);
+
return 1;
}
- /* si flag = GETNCNT il faut renvoyer le semaphore count*/
+ /* Get the current semaphore count */
if (flag==GETNCNT)
{
-// printf("getncnt : impossible sur BeOS\n");
- return 0; // a faire (peut etre impossible sur Beos)
+ /* TO BE IMPLEMENTED */
+ elog(ERROR,"beos : semctl error : GETNCNT not implemented");
+ return 0;
}
- /* si flag = GETVAL il faut renvoyer la valeur du sémaphore*/
+ /* Get the current semaphore count of the first semaphore in the pool */
if (flag==GETVAL)
{
int32 cnt;
get_sem_count(Address[semNum+1],&cnt);
-// printf("semctl getval id : %d cnt : %d\n",semId,cnt);
return cnt;
}
-// printf("semctl erreur\n");
+
+ elog(ERROR,"beos : semctl error : unknown flag");
+
return 0;
}
-// L'area dans laquelle est stockée le pool est identifiée par son nom (convention à moi : SYSV_IPC_SEM : "semId)
+/* Find a pool id based on IPC key */
int semget(int semKey, int semNum, int flags)
{
char Nom[50];
area_id parea;
void* Address;
-// printf("semget get k: %d n: %d fl:%d\n",semKey,semNum,flags);
- // Construction du nom que doit avoir l'area
+ /* Name of the area to find */
sprintf(Nom,"SYSV_IPC_SEM : %d",semKey);
- // Recherche de l'area
+ /* find area */
parea=find_area(Nom);
- // L'area existe
+ /* Test of area existance */
if (parea!=B_NAME_NOT_FOUND)
{
-// printf("area found\n");
- // On demande une creatrion d'un pool existant : erreur
+ /* Area exist and creation is requested, error */
if ((flags&IPC_CREAT)&&(flags&IPC_EXCL))
{
-// printf("creat asking exist\n");
errno=EEXIST;
return -1;
}
- // Clone de l'area et renvoi de son ID
+ /* Get an area clone (in case it's not in our address space) */
+ /* TODO : a check of address space might be done to avoid duplicate areas in the same address space*/
parea=clone_area(Nom,&Address,B_ANY_ADDRESS,B_READ_AREA | B_WRITE_AREA,parea);
return parea;
}
- // L'area n'existe pas
else
{
-// printf("set don't exist\n");
- // Demande de creation
+ /* Area does not exist, but creation is requested, so create it */
if (flags&IPC_CREAT)
{
int32* Address;
- thread_info ti;
void* Ad;
long i;
-// printf("create set\n");
- // On ne peut pas creer plus de 500 semaphores dans un pool (limite tout à fait arbitraire de ma part)
+ /* Limit to 500 semaphore in a pool */
if (semNum>500)
{
errno=ENOSPC;
return -1;
}
-
- // Creation de la zone de mémoire partagée
+
+ /* Create the shared memory area which will hold the pool */
parea=create_area(Nom,&Ad,B_ANY_ADDRESS,4096,B_NO_LOCK,B_READ_AREA | B_WRITE_AREA);
if ((parea==B_BAD_VALUE)|| (parea==B_NO_MEMORY)||(parea==B_ERROR))
{
errno=ENOMEM;
return -1;
}
+
+ /* fill up informations (sem number and sem ids) */
Address=(int32*)Ad;
Address[0]=semNum;
for (i=1;i<=Address[0];i++)
{
- // Creation des sémaphores 1 par 1
+ /* Create the semaphores */
Address[i]=create_sem(0,Nom);
if ((Address[i]==B_BAD_VALUE)|| (Address[i]==B_NO_MEMORY)||(Address[i]==B_NO_MORE_SEMS))
}
}
-// printf("returned %d\n",parea);
return parea;
}
- // Le pool n'existe pas et pas de demande de création
else
{
-// printf("set does not exist no creat requested\n");
+ /* Area does not exist and no creation is requested */
errno=ENOENT;
return -1;
}
}
}
-// Opération sur le pool de sémaphores
+/* Acquire or release in the semaphore pool */
int semop(int semId, struct sembuf *sops, int nsops)
{
- // Recherche de l'adresse du pool
- int32* Address;
+ int32* Address; /*Pool address*/
area_info info;
long i;
-// printf("semop id : %d n: %d\n",semId,sops->sem_op);
+ /* Get the pool address (semId IS an area id) */
get_area_info(semId,&info);
Address=(int32*)info.address;
+
+ /* Check the validity of semId (it should be an area id) */
if ((semId==B_BAD_VALUE)||(semId==B_NO_MEMORY)||(semId==B_ERROR))
{
errno=EINVAL;
return -1;
}
- // Execution de l'action
+ /* Perform acquire or release */
for(i=0;i<nsops;i++)
{
-
-// printf("semid %d, n %d\n",Address[sops[i].sem_num+1],sops[i].sem_op);
+ /* For each sem in the pool, check the operation to perform */
if (sops[i].sem_op < 0)
{
- acquire_sem_etc(Address[sops[i].sem_num+1],-sops[i].sem_op,0,0);
+ /* Try acuiring the semaphore till we are not inteerupted by a signal */
+ while (acquire_sem_etc(Address[sops[i].sem_num+1],-sops[i].sem_op,0,0)==B_INTERRUPTED);
}
if (sops[i].sem_op > 0)
{
#include <stdio.h>
#include <OS.h>
-// Detachement d'une zone de mémoire partagée
-// On detruit le clone de l'area dans notre adress-space
+/* Emulating SYS shared memory with beos areas. WARNING : fork clone
+areas in copy on write mode */
+
+
+/* Detach from a shared mem area based on its address */
int shmdt(char* shmaddr)
{
- // Recherche de l'id de l'area présente à cette adresse
+ /* Find area id for this address */
area_id s;
s=area_for(shmaddr);
-// printf("detach area %d\n",s);
-
- // Suppression de l'area
+
+ /* Delete area */
return delete_area(s);
}
-// Attachement à une zone de mémoire partagée
-// L'area doit bien partie de notre adress-space et on retourne directement l'adress
+/* Attach to an existing area */
int* shmat(int memId,int m1,int m2)
{
-// printf("shmat %d %d %d\n",memId,m1,m2);
-
- // Lecture de notre team_id
+ /* Get our team id */
thread_info thinfo;
team_info teinfo;
area_info ainfo;
get_thread_info(find_thread(NULL),&thinfo);
get_team_info(thinfo.team,&teinfo);
- // Lecture du teamid de l'area
+ /* Get area teamid */
if (get_area_info(memId,&ainfo)!=B_OK)
printf("AREA %d Invalide\n",memId);
if (ainfo.team==teinfo.team)
{
- //retour de l'adresse
-// printf("attach area %d add %d\n",memId,ainfo.address);
+ /* the area is already in our address space, just return the address */
return (int*)ainfo.address;
}
else
{
- // Clone de l'area
+ /* the area is not in our address space, clone it before and return the address */
area_id narea;
narea = clone_area(ainfo.name,&(ainfo.address),B_CLONE_ADDRESS,B_READ_AREA | B_WRITE_AREA,memId);
get_area_info(narea,&ainfo);
-// printf("attach area %d in %d add %d\n",memId,narea,ainfo.address);
return (int*)ainfo.address;
}
}
-// Utilisé uniquement pour supprimer une zone de mémoire partagée
-// On fait la meme chose que le detach mais avec un id direct
+/* Control a shared mem area : Used only to delete it */
int shmctl(int shmid,int flag, struct shmid_ds* dummy)
{
-// printf("shmctl %d %d \n",shmid,flag);
+ /* Delete the area */
delete_area(shmid);
return 0;
}
-// Recupération d'une area en fonction de sa référence
-// L'area source est identifiée par son nom (convention à moi : SYSV_IPC_SHM : "memId)
+/* Get an area based on the IPC key */
int shmget(int memKey,int size,int flag)
{
- int32 n_size;
char nom[50];
- area_id parea;
void* Address;
- area_id a;
-
- n_size=((size/4096)+1)*4096;
-
-// printf("shmget %d %d %d %d\n",memKey,size,flag,nsize);
+ area_id parea;
- // Determination du nom que doit avoir l'area
+ /* Area name */
sprintf(nom,"SYSV_IPC_SHM : %d",memKey);
-
- // Recherche de cette area
+ /* Find area */
parea=find_area(nom);
- // L'area existe
+ /* area exist, just return its id */
if (parea!=B_NAME_NOT_FOUND)
{
-// printf("area found\n");
return parea;
}
- // L'area n'existe pas et on n'en demande pas la création : erreur
+ /* area does not exist and no creation is requested : error */
if (flag==0)
{
-// printf("area %s not found\n",nom);
return -1;
}
- // L'area n'existe pas mais on demande sa création
- a=create_area(nom,&Address,B_ANY_ADDRESS,n_size,B_NO_LOCK,B_READ_AREA | B_WRITE_AREA);
-// printf("area %s : %d created addresse %d\n",nom,a,Address);
- return a;
+ /* area does not exist and its creation is requested, create it (be sure to have a 4ko multiple size */
+ return create_area(nom,&Address,B_ANY_ADDRESS,((size/4096)+1)*4096,B_NO_LOCK,B_READ_AREA | B_WRITE_AREA);
}
#include "postgres.h"
/* Support Globals */
-char* self_binary=NULL;
port_id beos_dl_port_in=0;
port_id beos_dl_port_out=0;
sem_id beos_shm_sem;
+/* Global var containing the postgres path */
+extern char pg_pathname[];
+
+
+/* Shared library loading doesn't work after fork in beos. The solution is to use an exact
+copy of the process and use it to perform the loading, then just map the Text and Data segment
+of the add-on in our address space. Both process must have the exact same memory mapping, so
+we use the postgres executable. When it's lauched with the -beossupportserver parameter, the
+postgres executable just run a loop to wait command on a port. Its only action is to load the addon,
+the beos_dl_open will then remap the good areas in the backend address space. */
+
+
image_id beos_dl_open(char * filename)
{
image_id im;
- /* Start the support server */
- if (self_binary==NULL)
- {
- /* Can't start support server without binary name */
- elog(NOTICE, "Error loading BeOS support server : can't find binary");
- return B_ERROR;
- }
- else
+ /* If a port doesn't exist, lauch support server */
+ if ((beos_dl_port_in<=0)||(beos_dl_port_out<=0))
{
- /* If a port doesn't exist, lauch support server */
+ /* Create communication port */
+ beos_dl_port_in=create_port(50,"beos_support_in");
+ beos_dl_port_out=create_port(50,"beos_support_in");
+
+
if ((beos_dl_port_in<=0)||(beos_dl_port_out<=0))
{
- /* Create communication port */
- beos_dl_port_in=create_port(50,"beos_support_in");
- beos_dl_port_out=create_port(50,"beos_support_in");
-
+ elog(NOTICE, "Error loading BeOS support server : can't create communication ports");
+ return B_ERROR;
+ }
+ else
+ {
+ char Cmd[4000];
+
+ /* Build arg list */
+ sprintf(Cmd,"%s -beossupportserver %d %d &",pg_pathname,(int)beos_dl_port_in,(int)beos_dl_port_out);
- if ((beos_dl_port_in<=0)||(beos_dl_port_out<=0))
- {
- elog(NOTICE, "Error loading BeOS support server : can't create communication ports");
- return B_ERROR;
- }
- else
- {
- char Cmd[4000];
-
- /* Build arg list */
- sprintf(Cmd,"%s -beossupportserver %d %d &",self_binary,(int)beos_dl_port_in,(int)beos_dl_port_out);
-
- /* Lauch process */
- system(Cmd);
- }
+ /* Lauch process */
+ system(Cmd);
}
}
{
if (strlen(argv[0]) >= 10 && !strcmp(argv[0] + strlen(argv[0]) - 10, "postmaster"))
{
- /* Shared memory cloning protection semaphore */
+ /* We are in the postmaster, create the protection semaphore for shared mem remapping */
beos_shm_sem=create_sem(1,"beos_shm_sem");
}
if (argc > 1 && strcmp(argv[1], "-beossupportserver") == 0)
{
+ /* We are in the support server, run it ... */
+
port_id port_in;
port_id port_out;
}
-void beos_backend_startup(char * binary)
+
+/* The behavior of fork is borken on beos regarding shared memory. In fact
+all shared memory areas are clones in copy on write mode in the new process.
+
+We need to do a remapping of these areas. Just afer the fork we performe the
+following actions :
+
+ * Find all areas with a name begining by SYS_V_IPC_ in our process
+ (areas created by the SYSV IPC emulation functions). The name is
+ followed by the IPC KEY in decimal format
+
+ * For each area we do :
+
+ * 1 : Get its name
+ * 2 : destroy it
+ * 3 : find another area with the exact same name
+ * 4 : clone it in our address space with a different name
+
+ There is a race condition in 3-4 : if there two fork in a very short
+ time, in step 3 we might end up with two areas with the same name, and no
+ possibility to find the postmaster one. So the whole process is protected
+ by a semaphore which is acquires just before the fork and released in case
+ of fork failure or just after the end of the remapping.*/
+
+void beos_before_backend_startup(void)
+{
+ /* Just before forking, acquire the semaphore */
+ if(acquire_sem(beos_shm_sem)!=B_OK)
+ exit(1); /* Fatal error, exiting with error */
+}
+
+void beos_backend_startup_failed(void)
+{
+ /* The foek failed, just release the semaphore */
+ release_sem(beos_shm_sem);
+}
+
+
+void beos_backend_startup(void)
{
- team_id ct;
- thread_info inft;
char nom[50];
char nvnom[50];
area_info inf;
int32 cook=0;
- /* remember full path binary name to load dl*/
- self_binary=strdup(binary);
+ /* Perform the remapping process */
- /* find the current team */
- get_thread_info(find_thread(NULL),&inft);
- ct=inft.team;
-
- /* find all area with a name begining by pgsql and destroy / clone then */
-
- /* This operation must be done by only one backend at a time */
- if(acquire_sem(beos_shm_sem)==B_OK)
+ /* Loop in all our team areas */
+ while (get_next_area_info(0, &cook, &inf) == B_OK)
{
- while (get_next_area_info(0, &cook, &inf) == B_OK)
+ strcpy(nom,inf.name);
+ strcpy(nvnom,inf.name);
+ nom[9]=0;
+ nvnom[5]='i';
+ /* Is it a SYS V area ? */
+ if (!strcmp(nom,"SYSV_IPC_"))
{
- strcpy(nom,inf.name);
- strcpy(nvnom,inf.name);
- nom[9]=0;
- nvnom[5]='i';
- if (!strcmp(nom,"SYSV_IPC_"))
- {
- void* add;
- area_id ar;
- add=inf.address;
- delete_area(inf.area);
- ar=find_area(inf.name);
- clone_area(nvnom,&add,B_CLONE_ADDRESS,B_READ_AREA|B_WRITE_AREA,ar);
- }
- }
- release_sem(beos_shm_sem);
- }
- else
- {
- /* Fatal error, exiting with error */
- exit(1);
- }
+ void* area_address;
+ area_id area_postmaster;
+ /* Get the area address */
+ area_address=inf.address;
+ /* Destroy the bad area */
+ delete_area(inf.area);
+ /* Find the postmaster area */
+ area_postmaster=find_area(inf.name);
+ /* Clone it at the exact same address */
+ clone_area(nvnom,&area_address,B_CLONE_ADDRESS,B_READ_AREA|B_WRITE_AREA,area_postmaster);
+ }
+ }
+
+ /* remapping done release semaphore to allow other backend to startup */
+
+ release_sem(beos_shm_sem);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.175 2000/10/25 22:27:25 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.176 2000/10/28 18:27:55 momjian Exp $
*
* NOTES
*
fflush(stdout);
fflush(stderr);
+#ifdef __BEOS__
+ /* Specific beos actions before backend startup */
+ beos_before_backend_startup();
+#endif
if ((pid = fork()) == 0)
{ /* child */
+#ifdef __BEOS__
+ /* Specific beos backend stratup actions */
+ beos_backend_startup();
+#endif
if (DoBackend(port))
{
fprintf(stderr, "%s child[%d]: BackendStartup: backend startup failed\n",
/* in parent */
if (pid < 0)
{
+#ifdef __BEOS__
+ /* Specific beos backend stratup actions */
+ beos_backend_startup_failed();
+#endif
fprintf(stderr, "%s: BackendStartup: fork failed: %s\n",
progname, strerror(errno));
return STATUS_ERROR;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.183 2000/10/28 01:07:00 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.184 2000/10/28 18:27:56 momjian Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
if (IsUnderPostmaster)
{
-#ifdef __BEOS__
- /* Specific beos backend stratup actions */
- beos_backend_startup(argv[0]);
-#endif
-
/* noninteractive case: nothing should be left after switches */
if (errs || argc != optind || DBName == NULL)
{
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.183 $ $Date: 2000/10/28 01:07:00 $\n");
+ puts("$Revision: 1.184 $ $Date: 2000/10/28 18:27:56 $\n");
}
/*
#include <kernel/OS.h>
+#include "kernel/image.h"
+
#define USE_POSIX_TIME
#define HAS_TEST_AND_SET
#define AF_UNIX 1 /* no domain sockets on BeOS */
-#ifdef __cplusplus
-extern "C" {
-#endif
- #include "kernel/image.h"
-
- #undef HAVE_UNION_SEMUN
- #define HAVE_UNION_SEMUN 1
- #undef HAVE_SYS_SEM_H
- #undef HAVE_SYS_SHM_H
+/* SYS V emulation */
- union semun
- {
- int val;
- struct semid_ds *buf;
- unsigned short *array;
- };
- /* SYS V emulation */
+#undef HAVE_UNION_SEMUN
+#define HAVE_UNION_SEMUN 1
- #define IPC_RMID 256
- #define IPC_CREAT 512
- #define IPC_EXCL 1024
- #define IPC_PRIVATE 234564
+#define IPC_RMID 256
+#define IPC_CREAT 512
+#define IPC_EXCL 1024
+#define IPC_PRIVATE 234564
- #define EACCESS 2048
- #define EIDRM 4096
+#define EACCESS 2048
+#define EIDRM 4096
- #define SETALL 8192
- #define GETNCNT 16384
- #define GETVAL 65536
- #define SETVAL 131072
+#define SETALL 8192
+#define GETNCNT 16384
+#define GETVAL 65536
+#define SETVAL 131072
- struct sembuf
- {
- int sem_flg;
- int sem_op;
- int sem_num;
- };
+union semun
+{
+ int val;
+ struct semid_ds *buf;
+ unsigned short *array;
+};
- int semctl(int semId,int semNum,int flag,union semun);
- int semget(int semKey, int semNum, int flags);
- int semop(int semId, struct sembuf *sops, int flag);
+struct sembuf
+{
+ int sem_flg;
+ int sem_op;
+ int sem_num;
+};
- struct shmid_ds
- {
- int dummy;
- };
+struct shmid_ds
+{
+ int dummy;
+};
- int shmdt(char* shmaddr);
- int* shmat(int memId,int m1,int m2);
- int shmctl(int shmid,int flag, struct shmid_ds* dummy);
- int shmget(int memKey,int size,int flag);
+int semctl(int semId,int semNum,int flag,union semun);
+int semget(int semKey, int semNum, int flags);
+int semop(int semId, struct sembuf *sops, int flag);
+
+int shmdt(char* shmaddr);
+int* shmat(int memId,int m1,int m2);
+int shmctl(int shmid,int flag, struct shmid_ds* dummy);
+int shmget(int memKey,int size,int flag);
+
+/* Support functions */
- /* Support functions */
- /* Specific beos action made on postgres/postmaster startup */
- void beos_startup(int argc,char** argv);
- /* Load a shared library */
- image_id beos_dl_open(char * filename);
- /* UnLoad a shared library */
- status_t beos_dl_close(image_id im);
- /* Specific beos action made on backend startup */
- void beos_backend_startup(char* binary);
-#ifdef __cplusplus
-}
-#endif
\ No newline at end of file
+/* Specific beos action made on postgres/postmaster startup */
+void beos_startup(int argc,char** argv);
+/* Load a shared library */
+image_id beos_dl_open(char * filename);
+/* UnLoad a shared library */
+status_t beos_dl_close(image_id im);
+/* Specific beos action made on backend startup */
+void beos_before_backend_startup(void);
+/* Specific beos action made on backend startup */
+void beos_backend_startup(void);
+/* Specific beos action made on backend startup failure*/
+void beos_backend_startup_failed(void);