Removed the old, historical and no longer working IPC support.

oldstable
Marcus Meissner 1999-07-11 14:13:56 +00:00 committed by Alexandre Julliard
parent 3dff7bb842
commit e32a317b76
43 changed files with 269 additions and 5918 deletions

View File

@ -51,7 +51,6 @@ LIBSUBDIRS = \
graphics/metafiledrv \
graphics/psdrv \
graphics/ttydrv \
ipc \
library \
loader \
loader/ne \
@ -127,7 +126,6 @@ LIBOBJS = \
graphics/metafiledrv/metafiledrv.o \
graphics/psdrv/psdrv.o \
graphics/ttydrv/ttydrv.o \
ipc/ipc.o \
loader/loader.o \
loader/ne/ne.o \
loader/dos/dos.o \

537
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -31,10 +31,6 @@ AC_ARG_ENABLE(lib,
[ --disable-lib build the Wine without building libwine.a],
[if test "$enableval" = "no"; then ALT_LINK="\$(LIBOBJS) \$(X11OBJS)"; LIB_TARGET=""; fi])
dnl AC_ARG_WITH(ipc,
dnl [ --enable-ipc use inter-process communication for DDE],
dnl [if test "$enableval" = "no"; then : ; else OPTIONS="-DCONFIG_IPC"; fi])
AC_ARG_ENABLE(debug,
[ --disable-debug compile out all debugging messages],
[if test "$enableval" = "no"; then DEBUG_MSGS="no"; fi])
@ -785,7 +781,6 @@ graphics/win16drv/Makefile
graphics/x11drv/Makefile
if1632/Makefile
include/Makefile
ipc/Makefile
library/Makefile
libtest/Makefile
loader/Makefile

View File

@ -12,7 +12,6 @@
#define __WINE_DDE_H
#include "windef.h"
#include "dde_proc.h"
#define WM_DDE_INITIATE 0x3E0
#define WM_DDE_TERMINATE 0x3E1

View File

@ -1,28 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: dde_atom.h
* Purpose : atom functionality for DDE
***************************************************************************
*/
#ifndef __WINE_DDE_ATOM_H
#define __WINE_DDE_ATOM_H
#ifdef CONFIG_IPC
#include "windef.h"
#define DDE_ATOMS 157 /* a prime number for hashing */
void ATOM_GlobalInit(void);
ATOM DDE_GlobalAddAtom( SEGPTR str );
ATOM DDE_GlobalDeleteAtom( ATOM atom );
ATOM DDE_GlobalFindAtom( SEGPTR str );
WORD DDE_GlobalGetAtomName( ATOM atom, LPSTR buffer, short count );
#endif /* CONFIG_IPC */
#endif __WINE_DDE_ATOM_H

View File

@ -1,39 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: dde_mem.h
* Purpose : shared DDE memory functionality for DDE
***************************************************************************
*/
#ifndef __WINE_DDE_MEM_H
#define __WINE_DDE_MEM_H
#ifdef CONFIG_IPC
#include "windef.h"
#include "global.h"
#include "shm_block.h"
#define DDE_HANDLES 0x0400
#define is_dde_handle(block) ( (block) >= (1<<15) && (block) < (1<<15)+DDE_HANDLES )
typedef struct {
int shmid;
REL_PTR rel;
}DDE_HWND;
WORD DDE_SyncHandle(HGLOBAL16 handle, WORD sel);
void *DDE_malloc(unsigned int flags,unsigned long size, SHMDATA *shmdata);
HANDLE16 DDE_GlobalReAlloc(WORD,long,WORD);
HGLOBAL16 DDE_GlobalFree(HGLOBAL16 block);
void *DDE_AttachHandle(HGLOBAL16 handle, SEGPTR *segptr);
WORD DDE_GlobalHandleToSel( HGLOBAL16 handle );
int DDE_GlobalUnlock(int);
HANDLE16 DDE_GlobalSize(WORD);
HANDLE16 DDE_GlobalHandle(WORD);
HANDLE16 DDE_GlobalFlags(WORD);
#endif /* CONFIG_IPC */
#endif /* __WINE_DDE_MEM_H */

View File

@ -1,63 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: dde_proc.h
* Purpose : DDE signals and processes functionality for DDE
***************************************************************************
*/
#ifndef __WINE_DDE_PROC_H
#define __WINE_DDE_PROC_H
#ifdef CONFIG_IPC
#include <setjmp.h>
#include "windef.h"
#include "windows.h"
#define DDE_PROCS 64
#define DDE_WINDOWS 64
struct _dde_proc {
int msg; /* message queue for this process */
int shmid; /* first shared memory block id. */
int sem; /* semaphore for fragment allocation */
int pid;
} ;
typedef struct _dde_proc *dde_proc;
extern sigjmp_buf env_wait_x;
enum stop_wait_op { /* The action to be taken upon SIGUSR2 */
CONT, /* Don't do anything */
STOP_WAIT_ACK, /* Use siglongjmp to stop wait_ack() */
STOP_WAIT_X /* siglongjmp to stop MSG_WaitXEvent() */
};
typedef struct {
WORD proc_idx; /* index into wine's process table */
HWND16 wnd; /* Window on the local proccess */
} WND_DATA;
extern enum stop_wait_op stop_wait_op;
extern int had_SIGUSR2;
extern int curr_proc_idx;
void stop_wait(int a); /* signal handler for SIGUSR2
(interrupts "select" system call) */
void dde_proc_init(dde_proc proc); /* init proc array */
void dde_proc_done(dde_proc proc); /* delete a proc entry */
void dde_proc_refresh(dde_proc proc); /* delete entry, if old junk */
void dde_proc_add(dde_proc proc); /* Add current proc to proc array */
void dde_msg_setup(int *msg_ptr);
int dde_reschedule();
void dde_wnd_setup(); /* setup Data structure of DDE windows */
/* Send ack. to hnd indicating that posted/sent msg. got to destination*/
void dde_proc_send_ack(HWND16 wnd, BOOL val);
BOOL DDE_PostMessage( MSG16 *msg);
BOOL DDE_SendMessage( MSG16 *msg);
int DDE_GetRemoteMessage();
void DDE_DestroyWindow(HWND16 hwnd); /* delete DDE info regarding hwnd */
void DDE_TestDDE(HWND16 hwnd); /* do we have dde handling in the window ?*/
#endif /* CONFIG_IPC */
#endif /* __WINE_DDE_PROC_H */

View File

@ -1,90 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: shm_block.ch
* Purpose: treat a shared memory block.
***************************************************************************
*/
#ifndef __WINE_SHM_BLOCK_H
#define __WINE_SHM_BLOCK_H
#ifdef CONFIG_IPC
#include <sys/shm.h>
#include "windef.h"
#define SEGSIZE 0x10000 /* 64 */
#define SHM_GRANULARITY SEGSIZE
#define SHM_MINBLOCK SHM_GRANULARITY
#define SHM_MAXBLOCK (((int)SHMMAX/(int)SHM_GRANULARITY)* \
SHM_GRANULARITY)
#define PTR2REL(block,ptr) (REL_PTR) ( (char *) (ptr) - (char *) (block) )
#define REL2PTR(block,rel) (void *) ( (char *) (block) + (rel) )
typedef int REL_PTR;
/* full info for each shm block. */
struct shm_block {
/* private */
int next_shm_id; /* IPC shm ID (for initial linking) */
/* public (read only) */
int size; /* size of the shm block */
int free; /* how much of the block is free */
int proc_idx; /* The index of the owner */
/* public - writable for shm_fragment */
REL_PTR free_list; /* first item in the free list */
};
/* used for mapping local attachments */
struct local_shm_map {
struct local_shm_map *next;
int shm_id;
int proc_idx;
/* 32 bit pointer to the beginning of the block */
struct shm_block *ptr;
};
extern struct local_shm_map *shm_map;
void shm_setup_block(struct shm_block *block, REL_PTR first, int size);
/* shm_create_block:
* allocate and setup a new block:
* first - first non header byte.
* size - block size (in bytes).
* shm_id- IPC shared memory ID.
*/
struct shm_block *shm_create_block(REL_PTR first, int size, int *shm_id);
/* shm_locate_block:
* locate existing block according to shm_id,
* Attach the block if needed. Assume the shm_id is wine's
* Set selectors also.
*/
struct shm_block *shm_locate_block(int shm_id, struct local_shm_map *map);
/* shm_locate_attached_block:
* locate existing block according to shm_id,
* Blocks are never attached.
* if proc_idx is not NULL, it will be set to owner's index.
* map - localy mapped info about block may be NULL;
*/
struct shm_block *shm_locate_attached_block(int shm_id,
struct local_shm_map *map);
/* shm_attach_block: attach existing shm block, setup selectors
* shm_id - id of the block to attach.
* proc_idx - if not -1, puts this data into local mapping
* map - localy mapped info about this block. (may be NULL)
* NOTE: same block can be attached many times
*/
struct shm_block *shm_attach_block(int shm_id, int proc_idx,
struct local_shm_map *map);
/* delete chain of shm blocks (pointing to each other */
void shm_delete_chain(int *shmid);
#endif /* CONFIG_IPC */
#endif /* __WINE_SHM_BLOCK_H */

View File

@ -1,51 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: shm_fragment.h
* Purpose: Data fragments and free list items. Allocate and free blocks.
***************************************************************************
*/
#ifndef __WINE_SHM_FRAGMENT_H
#define __WINE_SHM_FRAGMENT_H
#ifdef CONFIG_IPC
#include "shm_block.h"
#define NIL ((int) 0)
/* memory fragment: used or free (when free - it's an item of "free list",
* when allocated it contains the data, and it's size)
*/
struct shm_fragment {
int size; /* fragment's size */
/* The type of info depends on fragment's status (free/allocated) */
union info {
int next; /* next free fragment */
char data[1]; /* the data */
} info;
};
/* setup first item in the free list */
void shm_FragmentInit(struct shm_block *block,REL_PTR first,int size);
/* allocate shm fragment. return: offset to data in fragment, or NULL */
REL_PTR shm_FragmentAlloc(struct shm_block *block, int size);
/* like shm_FragmentAlloc, returns pointer instead of offset */
char *shm_FragPtrAlloc(struct shm_block *block, int size);
/* free shm fragment - according to offset */
void shm_FragmentFree(struct shm_block *block, int ofs);
/* free shm fragment - according to pointer */
void shm_FragPtrFree(struct shm_block *block, void *ptr);
/* This is used for debugging only */
void shm_print_free_list(struct shm_block *block);
#endif /* CONFIG_IPC */
#endif /* __WINE_SHM_FRAGMENT_H */

View File

@ -1,55 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: shm_main_blk.h
* Purpose: Main Wine's shared memory block
***************************************************************************
*/
#ifndef __WINE_SHM_MAIN_BLK_H
#define __WINE_SHM_MAIN_BLK_H
#ifdef CONFIG_IPC
#include <sys/shm.h>
#include "shm_block.h"
#include "shm_semaph.h"
#include "dde_proc.h"
#include "dde_atom.h"
#include "dde_mem.h"
/*****************************************************************************
*
* main block object
*
*****************************************************************************
*/
#define DDE_HANDLES_BIT_ARRAY_SIZE (DDE_HANDLES/sizeof(int)/8)
#define SHM_MAXID SHMSEG /* maximum shm blocks (Wine's limit) */
struct shm_main_block {
/* NOTE: "block" declaration must be the first */
struct shm_block block;
char magic[64]; /* magic string to identify the block */
int build_lock; /* =1 when data structure not stable yet */
shm_sem sem; /* semaphores for main_block integrity */
struct _dde_proc proc[DDE_PROCS]; /* information about processes */
REL_PTR atoms[DDE_ATOMS]; /* relative reference to global atoms */
/* Translation from global window handles to local handles */
WND_DATA windows[DDE_WINDOWS];
DDE_HWND handles[DDE_HANDLES];
/* bit array stating if a handle is free (bit=0), LSB in */
/* free_handles[0] refers handle 0x8000, the MSB refers 0x801F */
unsigned free_handles[DDE_HANDLES_BIT_ARRAY_SIZE];
};
extern struct shm_main_block *main_block;
int shm_init(void);
void shm_delete_all(int shm_id);
void DDE_mem_init();
int DDE_no_of_attached();
#define DDE_IPC_init() ( (main_block==NULL) ? (DDE_mem_init()) : 0 )
#endif /* CONFIG_IPC */
#endif /* __WINE_SHM_MAIN_BLK_H */

View File

@ -1,28 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: shm_semaph.h
* Purpose: Handle semaphores for shared memory operations.
***************************************************************************
*/
#ifndef __WINE_SHM_SEMAPH_H
#define __WINE_SHM_SEMAPH_H
/* IMPORTANT: If possible, restrict usage of these functions. */
#ifdef CONFIG_IPC
typedef int shm_sem;
void shm_read_wait(shm_sem semid);
void shm_write_wait(shm_sem semid);
void shm_write_signal(shm_sem semid);
void shm_read_signal(shm_sem semid);
void shm_sem_init(shm_sem *semptr);
void shm_sem_done(shm_sem *semptr);
#endif /* CONFIG_IPC */
#endif /* __WINE_SHM_SEMAPH_H */

View File

@ -1 +0,0 @@
Makefile

View File

@ -1,23 +0,0 @@
DEFS = @DLLFLAGS@ -D__WINE__
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = ipc
C_SRCS = \
bit_array.c \
dde_atom.c \
dde_mem.c \
dde_proc.c \
generic_hash.c \
shm_block.c \
shm_fragment.c \
shm_main_blk.c \
shm_semaph.c
all: $(MODULE).o
@MAKE_RULES@
### Dependencies:

View File

@ -1,34 +0,0 @@
Technion- Israel Institute of Technology
Electrical Engineering software lab.
Author : Michael Veksler 11678223
Tutor: Avner Lottem
DDE support for Wine
====================
Wine emulator is able to run MS-Windows 3.1 applications under Linux
(Linux is a UNIX clone) . Wine is also a toolkit allowing MS-Windows
applications to compile under Linux. Wine is a world-wide Internet
project with more than 20 developers. Wine is still under development
so many vital MS-Windows features are still missing.
DDE is Dynamic Data Exchange used for communication between MS-Windows
applications. This project adds DDE capabilities into Wine. The new
improved Wine will be able to send messages and share memory between
two different Wine processes.
This project uses System-V IPC mechanisms to implement DDE.
Besides sharing memory handles and sending DDE messages, Wine processes
are synchronize to emulates MS-Windows non-preemptive task switching.
(MS-Windows switches tasks only on given instructions). This is done
without hurting the performance or stability of a single Wine process.
The project adds DDE to Wine emulator and to the toolkit. This allows
old MS-Windows applications to be compiled for UNIX, and have DDE
working among them.

View File

@ -1,42 +0,0 @@
After shm_FragmentInit
{0x0020,0xffe0} [total free=ffe0]
0: After shm_FragmentAlloc(block, 0x010000) == NULL
{0x0020,0xffe0} [total free=ffe0]
1: After shm_FragmentAlloc(block, 0x003fdc) == 0x00c024
{0x0020,0xc000} [total free=c000]
2: After shm_FragmentAlloc(block, 0x003ffc) == 0x008024
{0x0020,0x8000} [total free=8000]
3: After shm_FragmentAlloc(block, 0x003ffc) == 0x004024
{0x0020,0x4000} [total free=4000]
4: After shm_FragmentAlloc(block, 0x003ffd) == NULL
{0x0020,0x4000} [total free=4000]
5: After shm_FragmentAlloc(block, 0x003ffc) == 0x000024
no free fragments [total free=0000]
6: Doing shm_FragmentFree(block, 0x000024)
{0x0020,0x4000} [total free=4000]
7: After shm_FragmentAlloc(block, 0x001bfc) == 0x002424
{0x0020,0x2400} [total free=2400]
8: After shm_FragmentAlloc(block, 0x0013fc) == 0x001024
{0x0020,0x1000} [total free=1000]
9: After shm_FragmentAlloc(block, 0x000ffc) == 0x000024
no free fragments [total free=0000]
10: Doing shm_FragmentFree(block, 0x000024)
{0x0020,0x1000} [total free=1000]
11: Doing shm_FragmentFree(block, 0x004024)
{0x0020,0x1000} {0x4020,0x4000} [total free=5000]
12: Doing shm_FragmentFree(block, 0x00c024)
{0x0020,0x1000} {0x4020,0x4000} {0xc020,0x3fe0} [total free=8fe0]
13: After shm_FragmentAlloc(block, 0x000ffc) == 0x000024
{0x4020,0x4000} {0xc020,0x3fe0} [total free=7fe0]
14: Doing shm_FragmentFree(block, 0x000024)
{0x0020,0x1000} {0x4020,0x4000} {0xc020,0x3fe0} [total free=8fe0]
15: After shm_FragmentAlloc(block, 0x000ffd) == 0x007014
{0x0020,0x1000} {0x4020,0x2ff0} {0xc020,0x3fe0} [total free=7fd0]
16: Doing shm_FragmentFree(block, 0x008024)
{0x0020,0x1000} {0x4020,0x2ff0} {0x8020,0x7fe0} [total free=bfd0]
17: Doing shm_FragmentFree(block, 0x001024)
{0x0020,0x2400} {0x4020,0x2ff0} {0x8020,0x7fe0} [total free=d3d0]
18: Doing shm_FragmentFree(block, 0x002424)
{0x0020,0x6ff0} {0x8020,0x7fe0} [total free=efd0]
19: Doing shm_FragmentFree(block, 0x007014)
{0x0020,0xffe0} [total free=ffe0]

View File

@ -1,283 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: bit_array.c
* Purpose : manipulate array of bits
* Portability: This is not completely portable, non CISC arcitectures
* Might not have atomic Clear/Set/Toggle bit. On those
* architectures semaphores should be used.
* Big Endian Concerns: This code is big endian compatible,
* but the byte order will be different (i.e. bit 0 will be
* located in byte 3).
***************************************************************************
*/
#ifdef CONFIG_IPC
/*
** uncoment the following line to disable assertions,
** this may boost performance by up to 50%
*/
/* #define NDEBUG */
#if defined(linux) && !defined(NO_ASM)
#include <linux/version.h>
#if LINUX_VERSION_CODE <= 131328 /* Linux 2.1.x doesn't return values with clear_bit and set_bit */
#define HAS_BITOPS
#endif
#endif
#include <stdio.h>
#include <assert.h>
#include "bit_array.h"
#ifdef HAS_BITOPS
#include <asm/bitops.h>
#else
static inline int clear_bit(int bit, int *mem);
static inline int set_bit(int bit, int *mem);
#endif /* HAS_BITOPS */
#define INT_NR(bit_nr) ((bit_nr) >> INT_LOG2)
#define INT_COUNT(bit_count) INT_NR( bit_count + BITS_PER_INT - 1 )
#define BIT_IN_INT(bit_nr) ((bit_nr) & (BITS_PER_INT - 1))
#if !defined(HAS_BITOPS)
/* first_zero maps bytes value to the index of first zero bit */
static char first_zero[256];
static int arrays_initialized=0;
/*
** initialize static arrays used for bit operations speedup.
** Currently initialized: first_zero[256]
** set "arrays_initialized" to inidate that arrays where initialized
*/
static void initialize_arrays()
{
int i;
int bit;
for (i=0 ; i<256 ; i++) {
/* find the first zero bit in `i' */
for (bit=0 ; bit < BITS_PER_BYTE ; bit++)
/* break if the bit is zero */
if ( ( (1 << bit) & i )
== 0)
break;
first_zero[i]= bit;
}
arrays_initialized=1;
}
/*
** Find first zero bit in the integer.
** Assume there is at least one zero.
*/
static inline int find_zbit_in_integer(unsigned int integer)
{
int i;
/* find the zero bit */
for (i=0 ; i < sizeof(int) ; i++, integer>>=8) {
int byte= integer & 0xff;
if (byte != 0xff)
return ( first_zero[ byte ]
+ (i << BYTE_LOG2) );
}
assert(0); /* never reached */
return 0;
}
/* return -1 on failure */
static inline int find_first_zero_bit(unsigned *array, int bits)
{
unsigned int integer;
int i;
int bytes=INT_COUNT(bits);
if (!arrays_initialized)
initialize_arrays();
for ( i=bytes ; i ; i--, array++) {
integer= *array;
/* test if integer contains a zero bit */
if (integer != ~0U)
return ( find_zbit_in_integer(integer)
+ ((bytes-i) << INT_LOG2) );
}
/* indicate failure */
return -1;
}
static inline int test_bit(int pos, unsigned *array)
{
unsigned int integer;
int bit = BIT_IN_INT(pos);
integer= array[ pos >> INT_LOG2 ];
return ( (integer & (1 << bit)) != 0
? 1
: 0 ) ;
}
/*
** The following two functions are x86 specific ,
** other processors will need porting
*/
/* inputs: bit number and memory address (32 bit) */
/* output: Value of the bit before modification */
static inline int clear_bit(int bit, int *mem)
{
int ret;
__asm__("xor %1,%1\n"
"btrl %2,%0\n"
"adcl %1,%1\n"
:"=m" (*mem), "=&r" (ret)
:"r" (bit));
return (ret);
}
static inline int set_bit(int bit, int *mem)
{
int ret;
__asm__("xor %1,%1\n"
"btsl %2,%0\n"
"adcl %1,%1\n"
:"=m" (*mem), "=&r" (ret)
:"r" (bit));
return (ret);
}
#endif /* !deined(HAS_BITOPS) */
/* AssembleArray: assemble an array object using existing data */
bit_array *AssembleArray(bit_array *new_array, unsigned int *buff, int bits)
{
assert(new_array!=NULL);
assert(buff!=NULL);
assert(bits>0);
assert((1 << INT_LOG2) == BITS_PER_INT); /* if fails, redefine INT_LOG2 */
new_array->bits=bits;
new_array->array=buff;
return new_array;
}
/* ResetArray: reset the bit array to zeros */
int ResetArray(bit_array *bits)
{
int i;
int *p;
assert(bits!=NULL);
assert(bits->array!=NULL);
for(i= INT_COUNT(bits->bits), p=bits->array; i ; p++, i--)
*p=0;
return 1;
}
/* VacantBit: find a vacant (zero) bit in the array,
* Return: Bit index on success, -1 on failure.
*/
int VacantBit(bit_array *bits)
{
int bit;
assert(bits!=NULL);
assert(bits->array!=NULL);
bit= find_first_zero_bit(bits->array, bits->bits);
if (bit >= bits->bits) /* failed? */
return -1;
return bit;
}
int SampleBit(bit_array *bits, int i)
{
assert(bits != NULL);
assert(bits->array != NULL);
assert(i >= 0 && i < bits->bits);
return ( test_bit(i,bits->array) != 0
? 1
: 0
);
}
/*
** Use "compare and exchange" mechanism to make sure
** that bits are not modified while "integer" value
** is calculated.
**
** This may be the slowest technique, but it is the most portable
** (Since most architectures have compare and exchange command)
*/
int AssignBit(bit_array *bits, int bit_nr, int val)
{
int ret;
assert(bits != NULL);
assert(bits->array != NULL);
assert(val==0 || val==1);
assert(bit_nr >= 0 && bit_nr < bits->bits);
if (val==0)
ret= clear_bit(BIT_IN_INT(bit_nr), &bits->array[ INT_NR(bit_nr) ]);
else
ret= set_bit(BIT_IN_INT(bit_nr), &bits->array[ INT_NR(bit_nr) ]);
return ( (ret!=0) ? 1 : 0);
}
/*
** Allocate a free bit (==0) and make it used (==1).
** This operation is guaranteed to resemble an atomic instruction.
**
** Return: allocated bit index, or -1 on failure.
**
** There is a crack between locating free bit, and allocating it.
** We assign 1 to the bit, test it was not '1' before the assignment.
** If it was, restart the seek and assign cycle.
**
*/
int AllocateBit(bit_array *bits)
{
int bit_nr;
int orig_bit;
assert(bits != NULL);
assert(bits->array != NULL);
do {
bit_nr= VacantBit(bits);
if (bit_nr == -1) /* No vacant bit ? */
return -1;
orig_bit = AssignBit(bits, bit_nr, 1);
} while (orig_bit != 0); /* it got assigned before we tried */
return bit_nr;
}
#endif /* CONFIG_IPC */

View File

@ -1,93 +0,0 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "bit_array.h"
#define SIZE (8*sizeof(int)*3)
static bit_array array;
static int simple_array[SIZE];
static int bits;
int are_equal()
{
int i;
for (i=0 ; i < SIZE ; i++)
if (SampleBit(&array,i) != simple_array[i]){
printf("failed bit %d (packed=%d, simple=%d)\n", i,
SampleBit(&array,i), simple_array[i]);
return 0;
}
return 1;
}
int is_same_vacant()
{
int vacant;
for (vacant =0 ; simple_array[vacant]!=0 ; vacant++)
if ( vacant >= SIZE) {
vacant=-1;
break;
}
if ( VacantBit(&array) == vacant )
return 1;
else
return 0;
}
void assign_both(int bit_nr, int bit_val)
{
int old_bit= simple_array[bit_nr];
simple_array[bit_nr]= bit_val;
bits+=bit_val - old_bit;
assert(AssignBit(&array, bit_nr, bit_val) == old_bit);
assert(are_equal());
assert(is_same_vacant());
}
int main()
{
unsigned int integers[SIZE >> 5];
int i,j;
assert( AssembleArray(&array, integers, SIZE)
== &array);
ResetArray(&array);
for (i=0 ; i<SIZE ; i++)
simple_array[i]=0;
for (j=5 ; j ; j--) {
printf("\rleft %d\r",j);
for (i=0 ; VacantBit(&array) != -1 ; i++ ) {
if (i % 256 == 0) {
printf("left %d ",j);
printf("%3d up \r", bits);
fflush(stdout);
}
assign_both(rand() % SIZE,
(rand()% SIZE > bits ) ? 0 : 1 );
}
assign_both(rand() % SIZE, 1);
for (i=0 ; bits ; i++ ) {
if (i % 256 == 0) {
printf("left %d ",j);
printf("%3d down\r", bits);
fflush(stdout);
}
assign_both(rand() % SIZE,
(rand()% SIZE <= (SIZE-bits) ) ? 0 : 1 );
}
assign_both(rand() % SIZE, 0);
}
putchar('\n');
return 0;
}

View File

@ -1,962 +0,0 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Written by Michael Veksler.
%% May be freely redistributed as long as this header is unchanged.
%% The file be modified as long as there will be appropriate comment
%% containing the Author and a description.
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentstyle{article}
\renewcommand{\thepage}{}
\newcommand{\Wine}{Wine}
\newcommand{\WINE}{{\em WINdows Emulator}}
\newcommand{\DDE}{{\em Dynamic Data Exchange}}
\newcommand{\windoz}{MS-Win\-dows}
\newcommand{\fname}[1]{{\tt #1}}
\newcommand{\libwine}{\fname{libwine.a}}
\title{DDE\footnote{DDE is \DDE\ mechanism provided by \windoz.
(Appendix~\protect\ref{sec:DDE}).
}
\ capability for \Wine\footnote{\Wine\ (\WINE) Runs \windoz\
programs under UNIX\@. (Appendix~\protect\ref{sec:Wine}).
}
}
\author{Michael Veksler 11678223}
%%\date{Aug 6, 1995}
\begin{document}
\maketitle
\vfill
\abstract{\Wine{} provides an environment for running or compiling
\windoz{} applications for UNIX clones (such as Linux).
\Wine{} is not yet finished and lacks many basic important features.
One of the missing features is DDE\@. DDE implementation
(especially for \libwine) requires
UNIX IPC\footnote{IPC - Inter-Process Communication}. This Project
introduces the IPC mechanism into \Wine{}, thus allowing DDE to work
between different \Wine{} processes.}
\vfill
{\LARGE
\begin{itemize}
\item[Instructor:] Avner Lottem
\item[Done for:] Technion- Israel Institute of Technology,\\
Electrical Engineering software lab$^{\mbox{\small\copyright}}$.
\end{itemize}
}
\vfill
\newpage
\renewcommand{\thepage}{\roman{page}}
\setcounter{page}{1}
\begin{center}
{\LARGE Table Of Contents}
\end{center}
\tableofcontents
\newpage
\renewcommand{\thepage}{\arabic{page}}
\setcounter{page}{1}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% end of title
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Introduction}
\subsection{The project}
The purpose of the project is to add DDE capabilities into \Wine.
The project enables \Wine{} DDE client-server applications communication.
This involved messing around with:
\begin{itemize}
\item \windoz\ message mechanism.
\item \windoz\ memory management.
\item \windoz\ task management.
\item UNIX messages among \Wine\ processes.
\item Exchanging (sharing) UNIX memory.
\end{itemize}
\subsection{Problem description}
DDE is essentially a communication protocol between \windoz\
tasks. Implementing this protocol requires communication among
\Wine{} processes and among tasks in one process (each \Wine{} process
can contain several tasks). Since \Wine\ already provides
communication among internal tasks, this project provides communication
between \Wine\ processes.
Different \Wine\ processes should be able to send \windoz\ messages
and to pass \windoz\ memory handles. There also has to be a
synchronization mechanism between the processes (\windoz\ applications
make assumptions about task switching - and don't use semaphores, or
any \windoz\ equivalent).
Passing messages is a bit tricky. \windoz\ gives a feedback about the
success of a message (fails if the window does not exist).
In case of SendMessage (see Appendix~\ref{sec:WindozMsg}), the process
will have to halt until the message has been processed.
In case of PostMessage, things are simpler - only the existence of the
recipient has to be checked.
\windoz\ switches tasks only when certain system calls are used (such
as delivering or polling messages). \windoz\ applications rely on this
behavior. The problem arises when two applications run on different
\Wine\ processes. Since UNIX preempts processes there is no guaranty
that the UNIX task will occur at the correct place (in respect of the
application).
One one hand is the need for compatibility (no UNIX ``current''
execution), and on the other hand is performance and stability.
Another problem is passing handles between \Wine\ processes. \windoz\
applications pass atoms\footnote{See appendix~\ref{sec:WhatAreAtoms}},
memory handles and window handles. These handles have to be allocated
globally (in shared memory) or translated on the fly.
If a process dies from ``unnatural causes'' (e.g.\ kill $-9$). It will
leave garbage in memory and other IPC handles will start floating
around. There should be some way to collect this garbage.
\subsection{Solutions}
\label{sec:ProjSolutions}
\Wine\ uses Sys-V IPC mechanism (See
Appendix~\ref{sec:SysV-IPC}). This allows sharing data and passing
data between processes (The alternatives are not that good in that
respect - see Appendix~\ref{DDE-Alternatives}).
The shared data contains only essential information (performance or
compatibility). The minimum is kept on shared memory in order to get
maximum stability (\windoz\ is known as an unstable system, \Wine\
should not imitate \windoz\ in this respect).
Communications are done by Sys-V messages and UNIX signals (a signal
wakes \Wine\ up and the message passes the data). Sys-V messages are
used for carrying \windoz\ messages, as well as synchronization
information. There are 3 types of messages: sent, posted and ack.
Ack message is used for synchronization as well as for returning error
codes (In case sending/posting messages fail). When a message is sent,
the sending process will block until \Wine's {\em ack}{} message is
received.
Synchronization between \Wine\ processes is divided into 2 categories,
in both cases the sender of a message waits for an ack message:
\begin{enumerate}
\item Sent messages - Wait until the recipient delivers ack message.
(When the recipient finished message processing)
\item Posted message - The recipient will send ack only during
task switching instructions (like PostMessage, GetMessage, Yield,
etc.). This way nothing will be done after PostMessage until it is
safe.
\end{enumerate}
There is no real \Wine\ server. Every \Wine\ process has to handle
it's end. This approach somehow resembles a distributed OS\@. This
introduces some problems (Resources might not be freed in case of a
crash). On the other hand this ``distributed OS'' approach simplifies
installation and use, and improves performance.
Atoms are stored on shared memory, so every two \Wine\ processes will
be in sync in this respect (atom 5 will mean the same on both
processes). Shared memory handles are stored on shared memory as
well. Shared memory handles are not from the same range as local
memory handles (\windoz\ requires an plication to declare about it's
shared memory). Since local memory handles have different range they
can be allocated locally (without any sync requirements - handle x may
appear on 10 different \Wine\ processes and address different data).
Window handles are allocated locally. This approach gives stability,
but window handles are no longer unique (same handle may appear
on different processes). This requires on the fly window handle
translation. When an \windoz\ message is transfered, \Wine\ will
translate any contained window handle. The sender translates the
handle to a global (unique) handle, the receiver translates the global
handle to the local window handle.
Collecting the garbage of dead processes is done in two cases:
\begin{enumerate}
\item When setting up a new \Wine\ process: If no \Wine\ process is
running and shared memory is floating around all the IPC stuff is
deleted.
\item When sending a message: If the recipient is dead it's IPC
handles are deleted.
\end{enumerate}
\section{The software}
\subsection{DDE project structure}
Old \Wine\ functions call the new DDE functions whenever needed.
(e.g.\ when sending a DDE message, the original SendMessage function calls
DDE\_SendMessage). This approach minimizes changes to original \Wine{}
code. The new code was written in C. The new capabilities where written
as much as possible in OOP\footnote{OOP stands for Object Oriented
Programming}{} style.
Currently DDE uses Sys-V IPC mechanism, for it's operation.
\paragraph{Major OOP objects and files:}
\begin{table}[h]
\begin{center}
\leavevmode
\begin{tabular}{|l|p{20em}|} \hline
Object & Description \\ \hline
shm\_block & shared memory block operations. \\
shm\_main\_block & (derived from shm\_block.) Things all
DDE applications need access to. \\
shm\_fragment & Allocation of in-block fragments. \\
shm\_semaph & Semaphore operations. \\
dde\_proc & Process and DDE message handling. \\
dde\_mem & Front end of DDE memory handling
(Interface of DDE to outer world). \\
dde\_atom & Handling global atoms. \\
bit\_array & Array of bits. It has atomic
operations, so bits can be used instead
of semaphores. \\ \hline
\end{tabular}
\caption{Objects constructing the DDE extension.}
\label{tab:ObjList}
\end{center}
\end{table}
Table~\ref{tab:ObjList}{} lists the objects used in the DDE code.
The following rules apply to objects:
\begin{itemize}
\item Object names that begin with {\em dde\_$\cdots$}{} are the front
end. These objects are working directly with the rest of
\Wine. Objects that start with {\em shm\_$\cdots$}{} are the back
end. These objects provide services for the rest of the
implementation.
\item The objects are stored in file with the same name as the object.
(e.g.\ dde\_mem is stored in dde\_mem.c and dde\_mem.h).
\item For each object there is a test file (that partially tests it).
The name of this file is object's name with the word ``test''
(e.g.\ dde\_mem object has dde\_mem\_test.c).
\item dde.h file has declarations used by dde\_proc and external DDE
users.
\end{itemize}
\subsection{Major algorithms}
\paragraph{Delivering messages:}
\label{sec:DeliveringMessages}
\windoz\ messages are passed using Sys-V IPC messages. Processing
starts with SendMessage() or PostMessage() \windoz\ system
functions:
\begin{enumerate}
\item SendMessage and PostMessage call the DDE functions (same names
prefixed with DDE\_). If the DDE functions pass, don't go any
further. If it fails try to process the message in the
conventional way.
\item The DDE message functions call DDE\_DoMessage, which is
the main DDE message processing function. From now on there is no
difference between sending and posting messages (from initiator's
point of view).
\item If the message is not a DDE message or the recipient is not
remote, fail and return to original message functions.
\item Bring the message to a format suitable for IPC delivery. The
format includes:
\begin{itemize}
\item message type (sent or posted).
\item Sender window handle (translated to global window id.)
\item Other message ingredients (msg, lParam).
\end{itemize}
\item Deliver the message to every recipients using
DDE\_DoOneMessage. There might be many recipients in case of a
broadcast (when the ``recipient'' window is -1).
\item DDE\_DoOneMessage delivers the message and waits for response.
Fail if timeout is reached.
\end{enumerate}
\paragraph{Receiving messages:}
Messages from other \Wine\ processes are received. Processing start
from DDE\_GetRemoteMessage():
\begin{enumerate}
\item DDE\_GetRemoteMessage is called whenever wine is going to wait
or receive X-windows message. If wine is sleeping (waiting for X),
it will waken by a SIGUSR2 signal. In this case the handler will
siglongjmp() out of the select() function.
\item If no remote message is pending in the message queue - exit.
(Sys-V message queue holds the remote messages until they are
read).
\item If the message is broadcasted, goto stage~\ref{BroadcastAlgo}.
\item Translate the global window handle of the recipient to local
handle.
\item Do this if the message was sent. Send the message to the
recipient window. Reply with ack to the sender. (Reply with the
return code of the SendMessage function). {\em \bf Return}\ with
positive return value.
\item Post the message.
\item If PostMessage fails - send failing ack message.
\item If PostMessage passes, add the message data into a FIFO\@. This
FIFO contains all messages that have to be acknowledged (who's
sender is waiting for ack). Whenever internal task switch occurs,
a item from this FIFO is popped out and an ack message is sent.
\item \label{BroadcastAlgo} Iterate through the local windows and
deliver the message to every one of them.
\item Send a positive ack message.
\end{enumerate}
\paragraph{Allocating memory:}
Shared memory allocation is divided into two categories: internal wine
and \windoz\ application. The memory used by \windoz\ applications is
allocated in two phases - allocate internal wine, and then prepare all
the stuff needed by \windoz.
The internal allocation (DDE\_malloc):
\begin{enumerate}
\item Try to allocate big enough memory fragment in allocated shared
memory.
\item If fragment could not be allocated, allocate a new shared
memory block. Allocate the memory fragment.
\item Allocate a shared memory handle (call the dde\_alloc\_handle()
function). The allocated handle is from a range used only by
shared memory handles. This allocation function is used only for
shared DDE memory.
\item Write the handle in the data structure. Also write the
relative location of this handle (Pointer location is useless since
it differs from one \Wine\ process to another).
This information is written in the main shared memory block.
\end{enumerate}
When a fragment is allocated, it is removed from the list of free
memory.
Allocation for \windoz\ applications (this is done in GlobalAlloc):
\begin{enumerate}
\item Do the internal allocation (instead of malloc in the local
allocation).
\item Everything else is the same as with local memory. A segment is
allocated for the new memory, and it's data is kept in the data
structure.
\end{enumerate}
\paragraph{Atoms:}
Atoms have pretty simple algorithms operating on them. Since atoms are
supposed to give a unique number for each string - atoms are
implemented as hash tables. The id of the atom is the entry in the
hash table. The disadvantage of this approach is that there is a limit
on the number of atoms, the big advantages are simplicity and
speed.
Since implementing a hash tables is strait forward, I will not
discuss it in depth. This hash table has two hash functions - primary
and secondary. When searching for an item (for deletion, addition, or
a seek) the following steps are taken:
\begin{enumerate}
\item The primary hash function returns the first entry.
\item \label{AtomHashLoop}
If the entry is empty or no unchecked entries {\bf \em fail}.
\item If the entry is correct, {\bf \em success!!!}.
\item Add the result of secondary hash function to the item index.
\item Goto step~\ref{AtomHashLoop}.
\end{enumerate}
\subsection{Major data structures}
There are two kinds of data structure, local and shared. The local
data structures are strait forward and will not be discussed in
detail.
The shared data structures have four level hierarchy. Each level
depend on the other and can not exist without it. Most structures have
much less than four levels.
\paragraph{Level one data structure - the main block:}
This data structure is part of the shm\_main\_block object. It
contains essential information needed by all \Wine\ processes. :
\begin{enumerate}
\item Semaphore identifier used for locking the data structure.
\item A table containing information about \Wine\ processes.
\item Relative pointers to atoms.
\item A table containing window information.
\item Tables with global memory handles.
\end{enumerate}
The first level is allocated and initialized when \Wine\ calls a DDE
function the first time. DDE functions are: global memory allocation,
global atoms or DDE messages.
The first level data structure contains the second level data
structure.
\paragraph{Atom element (level two):}
Each element is allocated dynamically (the size of the string is
unknown). The allocation is gained from the shm\_fragment object (each
atom is an instance of that object). Each atom contains:
\begin{enumerate}
\item Count of links. Each allocation of the atom establishes a new
link and each deallocation deletes one link (until all links are
removed).
\item The string of the atom. The string ends with a null character.
\end{enumerate}
\paragraph{Wine processes data (level two):}
(part of the dde\_proc object) :
\begin{enumerate}
\item pid (\Wine\ process id).
\item Message queue id.
\item Semaphore used for locking process's data structure.
\item Sys-V shared memory id of the first block in the chain of
process's blocks.
\end{enumerate}
\paragraph{Window information (level two):}
This is part of the dde\_proc object. The index of array entry
specifies the window handle. Each entry contains:
\begin{enumerate}
\item The process index of the \Wine\ process running this window.
\item The local window handle of this window (remember that each DDE
window has different global and local handles).
\end{enumerate}
\paragraph{Global memory handles (Level two):}
(part of bit\_array and dde\_mem objects):
\begin{enumerate}
\item A bit array contains '1' in every entry that refers to
used global memory handle.
\item Array of handles contains handle data. Each entry refers
to a global memory handle (The index is a function of the
handle). The data includes: 1) Sys-V shared memory handles 2)
offset into the memory block.
\end{enumerate}
\paragraph{Block allocation data structure (Level three):}
This data structure a part of the shm\_block object. It is local to
each shared memory block, so every memory block has it's own data
structure. The shared memory blocks are organized in chains grouped by
processes (each DDE process has one and only one chain):
\begin{enumerate}
\item The id of the next shared memory block in the chain.
\item The size of the block.
\item Number of free bytes in the block.
\item The index of the owner process.
\item The first item in the free list (a linked list of free items).
\end{enumerate}
\paragraph{Fragment allocation (Level four):}
This data is a part of the shm\_fragment object. It is a part of the shared
memory allocation mechanism. Every fragment is a part of shared memory
block. Each fragments contain:
\begin{enumerate}
\item The size of the fragment (for allocating and freeing this
fragment).
\item A union that contains one of:
\begin{itemize}
\item data - if it is allocated.
\item offset of the next free fragment (if it is a member of the
free list).
\end{itemize}
\end{enumerate}
\paragraph{Local reference to global memory:}
Global memory blocks are referenced from local memory. This is used
for storing pointers that refer to the memory block. It contains:
\begin{enumerate}
\item next item in the list.
\item shared memory block id.
\item Owner process.
\item Pointer to the data.
\end{enumerate}
\paragraph{Local mirroring of global handles:}
Global handles require local segments handles (when they are locked).
These segments have to be deleted when the handle is freed.
There is a minimal mirroring of handles in the original tables of
wine, this information is stored the way local handles have always
been stored.
\subsection{Interface and IO}
The DDE section of wine has several interfaces to different entities:
\begin{enumerate}
\item User debug information.
\item Interface between several \Wine\ processes.
\item Interface to the `old' code of \Wine.
\end{enumerate}
\paragraph{User debug information:}
The debug information is written according to \Wine's
conventions. This means that dprintf\_$\cdots$ macros are used to
print the debug information. (These macros allow runtime or compile time
disabling of a any sort of debug information).
In some cases the dprintf\_$\cdots$ macros are not powerful enough. In
those cases the following construct is used instead:
\begin{verbatim}
if (debugging_dde) {
/* print whatever is needed for dde debugging */
}
\end{verbatim}
\paragraph{Interface between \Wine\ processes:}
The interface between processes includes:
\begin{itemize}
\item Message delivery (see Section~\ref{sec:DeliveringMessages}).
\item Sharing \windoz\ constructs (atoms, memory, window
handles).
\item Synchronization among different \Wine\ processes so it will
appear to a \windoz\ as if there is only one process.
\end{itemize}
\paragraph{Interface to the rest of \Wine:}
Most of the interface has been minimized to an additional few lines in
the original functions. The hook for DDE are in the following
locations:
\begin{itemize}
\item Global atoms functions - these are called directly from
\windoz\ applications.
\item Message delivery - a hook calls the DDE functions from the
original message delivery functions.
\item Initialization - Every PeekMessage() call a DDE function to
check if the current window has DDE management (by sending
a dummy WM\_DDE\_INITIATE message).
\item Waiting on messages - The original code for waiting on X
messages was enhanced to wait on DDE messages as well. This
includes aborting sleeps when SIGUSR2 signal is sent. The actual
test for DDE messages is done in the DDE code.
\end{itemize}
\subsection{Major functions and their role}
\paragraph{Message delivery functions:}
\begin{itemize}
\item DDE\_SendMessage and DDE\_PostMessage - hooks used by original
\Wine's SendMessage and PostMessage. They return true if the
message could be successfully sent to a remote \Wine\ process.
Only in this case SendMessage and PostMessage stop further
processing.
\item DDE\_DoMessage - Try to post or send a message to another
\Wine\ process. This function can do broadcasting as well as
sending. (A message is `broadcasted' if it is delivered to every
window on the system).
\item DDE\_DoOneMessage - Deliver a message to a given wine
{\bf process}.
\item dde\_proc\_send\_ack - Send ack message to \Wine\
process. The input window handle is used for detecting the
process.
\item get\_ack - wait for ack or timeout.
\end{itemize}
\paragraph{Memory allocation functions:}
\begin{itemize}
\item DDE\_malloc - Allocate a shared memory fragment. This function
also allocates global memory handle.
\item DDE\_GlobalFree - Free a shared memory fragment according to
it's handle. And free the handle.
\item DDE\_SyncHandle - synchronize the global handles mirrored
locally. Delete any outdated handles, or remap reallocated
handles.
\item DDE\_mem\_init - initialize or attach the main shared memory
block, and relevant local data structures.
\item shm\_delete\_all - delete all IPC stuff related to this
process. Kill the main memory block if appropriate.
\end{itemize}
\section{Software testing}
The testing of this module was a substantial part of the
development. Testing revealed bugs just as they where created.
\subsection{Testing methods utilized}
\label{sec:TestMethod}
Two major testing methods where used:
\begin{enumerate}
\item Running DDE \windoz\ applications. The applications used are
DDE demonstration applications. This applications seem to show
precisely what DDE is all about. The applications used where:
ddepop1.exe (server), showpop1.exe (client). These
applications come with \windoz\ programming manual by Charles
Petzold \cite{bib:WinManual}.
\item Running standalone DDE objects linked with a test
object. Every object was tested this way. Some objects had to be
linked with a stub that emulated \Wine's functions. The stub is
pretty poor with dde\_mem object since this object requires hard
to emulate functionalities (things like allocating a segment).
For some objects the coverage seems to be perfect (100\%). For
some object the coverage is poor. The objects with massive stub
usage suffer from this (especially dde\_mem).
\end{enumerate}
\subsection{input for testing}
Most of the testing described in section~\ref{sec:TestMethod} has no
input. Most of the testing knowledge is in the test objects
themselves. There are two exceptions to this rule:
\begin{enumerate}
\item The \windoz\ applications described in
section~\ref{sec:TestMethod} - which are essentially an input to
the software. These applications can't be distributed since it
will be a \copyright{} violation.
\item A trace file which is used for comparing test's output with
the expected trace result. This trace file is used for
shm\_fragment validation. This file is implementation Dependants
and should be updated whenever the object is rewritten. When
updating the trace, it should be inspected manually before it is
released.
\end{enumerate}
\subsection{usage instructions}
\paragraph{Running the DDE applications:}
To test the DDE applications one must run:
\begin{verbatim}
prompt> wine /full-path/ddepop1.exe > /dev/null &
\end{verbatim}
Wait for the server window to pop up (A tiny window should appear at
the lower left corner of your screen). Then activate the client by
typing:
\begin{verbatim}
prompt> wine /full-path/showpop1.exe > /dev/null
\end{verbatim}
The server updates ``USA population'' data every 5 seconds. The client
asks for a hot link (i.e.\ it sends a WM\_DDE\_ADVISE on every
item). From that point on the server updates the client of any
population change.
\paragraph{Running the object tests:}
The {\em run\_tests}{} script is provided to automate the object
tests. Every object test is run and the script checks for results. At
the end the script prints a nice summary table.
Invoking tests outside the {\em run\_tests}{} script is not as simple
as it may look. Every test has differently looking output.
\begin{itemize}
\item dde\_atom\_test - The executable is run. It passes if no
errors are printed at the bottom.
\item dde\_mem\_test - The same as for dde\_atom\_test.
\item shm\_semaph\_test - The same as for dde\_atom\_test.
\item bit\_array\_test - The same as for dde\_atom\_test.
\item shm\_fragment\_test - After the executable is run, the output
has to be compared with TEST\_FRAGMENT.std
\item dde\_proc\_test - This actually runs as a client and as a
server. To activate the server one should write:
\begin{verbatim}
prompt> dde_proc_test 1 > server.log
\end{verbatim}
Then the client has to be activated within five seconds by
writing:
\begin{verbatim}
prompt> dde_proc_test > client.log
\end{verbatim}
The log files should contain:
\begin{description}
\item[server.log:] Should contain traces of received
WM\_DDE\_INITIATE message, and ack sent for it. (Pretty much
the same what {\em run\_tests}{} does).
\item[client.log:] Should contain traces of sending
WM\_DDE\_INITIATE and then receiving an ack message.
\end{description}
No `timeout' traces should be present in the log files.
\end{itemize}
\section{Summary}
\subsection{Software limitations}
\begin{itemize}
\item Only most fundamental memory management functions where
written. This means that the following functions will not work:
\begin{itemize}
\item GlobalReAlloc
\item GlobalSize - two line fix.
\item GlobalFlags - two line fix.
\item LockSegment - two line fix.
\item UnlockSegment - two line fix.
\item GlobalFreeAll - will not free DDE memory.
\item GlobalPageLock - two line fix.
\item GlobalPageUnlock - two line fix.
\item GlobalFix - two line fix.
\item GlobalUnfix - two line fix.
\end{itemize}
\item Non DDE messages to remote windows will not work. This is
currently only a sanity check, it may be removed in the future.
\item Message sending has a timeout limit. This is incompatible with
\windoz. This limit increases stability of a singe \Wine\ process.
\item Synchronization mechanism between wine processes is not
perfect. It was not proved theoretically. I never saw it fail.
\end{itemize}
\subsection{Concluding Remarks}
This extension to \Wine{} enables further development of \windoz\ IPC
support. Things like OLE can be extended using these features -
although some modifications might be inevitable.
The most important contribution of this project is the support for
\libwine{}. Any \windoz\ application compiled under UNIX and linked to
\libwine{} will need the IPC mechanism provided by this project.
During the progress of the project it got a bit outdated. During that
time \Wine{} started to handle tasks internally, so the external IPC
was no longer needed for the emulator configuration of
wine. Nevertheless the support of IPC for \libwine will never
be obsolete.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Appendixes
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\clearpage
\appendix
\section{\Wine}
\label{sec:Wine}
\Wine\ stand for {\em WINdows Emulator}. It is an X-windows - UNIX
application (Linux and FreeBSD). \Wine\ emulates \windoz\ environment
for the \windoz\ applications. It has two uses:
\begin{enumerate}
\item Run \windoz\ binary code (compiled under \windoz).
\item To be used as a toolkit for compiling \windoz\ applications
under UNIX. (The \libwine\ library is provided)
\end{enumerate}
For emulation, only Intel-Architecture CPU (386, 486, Pentium) are
supported. \libwine\ Toolkit should run on any platforms, but it was not
tested. \Wine\ is still in alpha state, and does not support all \windoz\
capabilities yet.
\section{Messages under \windoz}
\label{sec:WindozMsg}
Messages are the means of communication to a user window (from another
window or from \windoz\ itself).
Messages can be delivered in two ways:
\begin{itemize}
\item Messages can be sent. The sent message enters the window handler
asynchronously (The handler may be reentered many times).
A window sending the message waits for the recipient to process
the message and return an exit code.
\item Messages can be posted. The posted message enters a queue, and
it's up to the recipient to process it. If the recipient ignores
it, the message might be eventually sent to the recipient from
WinMain handler.
\end{itemize}
\section{DDE}
\label{sec:DDE}
DDE stands for \DDE\@. DDE is an \windoz\
protocol used for data exchange between applications.
It has synchronous and asynchronous operation modes.
DDE mechanism is based on messages, atoms
(Section~\ref{sec:WhatAreAtoms}) and shared memory.
DDE applications are divided roughly into two classes: servers AND
clients. Clients have the initiative, they try to connect to the
server. Servers only maintain an existing DDE link.
\subsection{DDE Messages}
\paragraph{DDE message format}:
\label{sec:DDEMessageFormat}
DDE messages contain the following fields.
\begin{description}
\item[wnd] The recipient of this message ($-1$ if every window
should receive).
\item[msg] The ID of the message.
\item[wParam] Who sent this message.
\item[lParam] 32 bit parameter, divided into two 16 bit words.
Usually, the lower 16 bits contain a memory handle. The handle
points to some extra DATA about this message.
\end{description}
\paragraph{Available messages:}
\begin{description}
\item[WM\_DDE\_INITIATE]
This message is sent by the client to the whole ``world''.
{\em lParam}{} contains the two atoms used for passing the topic and
application information.
Every server application checks if this message refers to it
(According to the Application and the Topic atoms).
\item[WM\_DDE\_ACK]
This is a generic response to various events
(one of them is WM\_DDE\_INITIATE).
The low part of {\em lParam}{} passes extra information, such as
success/failure.
\item[WM\_DDE\_TERMINATE]
Kill the DDE link.
\item[WM\_DDE\_ADVISE]
Tell the server to inform the client of any updates.
\item[WM\_DDE\_UNADVISE]
Stop the WM\_DDE\_UNADVISE mode.
\item[WM\_DDE\_DATA]
Transfer data handle (note that the data handle must be globally allocated
with the GMEM\_DDESHARE flag).
\item[WM\_DDE\_REQUEST]
Request a data item from the server. This message is used in a
cold link. {\em lParam}{} contains an atom describing the desired
item, and a WORD describing the wanted data format.
\item[WM\_DDE\_POKE]
The client gives the server new data.
\item[WM\_DDE\_EXECUTE]
The client asks the server to execute a procedure (according to a
command string).
\end{description}
\subsection{Atoms}
\label{sec:WhatAreAtoms}
Atoms are represented by numbers. Every atom maps uniquely to a string
(i.e.\ two atoms can't map to the same string).
There are two types of atoms - local and global. The local are visible
only to the application that created them. Global atoms are seen by all
\windoz\ applications.
Functions:
\begin{description}
\item[AddAtom(str)] create a local atom that maps to ``str''.
If it exists, increment the allocation-counter,
and return the atom.
\item[DeleteAtom(atom)] decrement the allocation-counter. When it
reaches zero the atom, will be deleted.
\item[FindAtom(str)] Find the atom that maps to this string (if exist).
\item[GetAtomName(\ldots)] Find the string that this atom points to.
\end{description}
NOTE:
\begin{description}
\item[Global atoms] Add ``Global'' before the listed names to get Global
atom functions.
\item[Case sensitivity] All atom operations ignore case.
\end{description}
\section{DDE under \Wine\ - Alternatives}
\label{DDE-Alternatives}
There where three possible approaches for this project. I have chosen
System-V IPC, but it can be easily changed.
\subsection{IPC - Inter-Process Communication}
\label{sec:SysV-IPC}
The IPC mechanism was originated from System-V UNIX\@. This mechanism
allows complicate communication between two process (on the same machine).
IPC includes the following capabilities:
\begin{enumerate}
\item Shared Memory (shm) - can be shared among few processes and users.
\item Semaphores (These semaphores allow grouped operations - i.e.\
operations gathered as an atomic operation).
\item Message Queues (allow few messages at a time).
\end{enumerate}
The advantages of IPC over the other variants are:
\begin{itemize}
\item Memory access speed is good. (after the memory was attached).
\item Easy to block critical code (don't enter critical code from two
processes at the same time)
\end{itemize}
Disadvantages of IPC:
\begin{itemize}
\item Impossible to communicate to other machine.
\item Requires complex mechanism to wait both for X and IPC messages.
\end{itemize}
\subsection{X-Windows Communication mechanisms}
The advantages of X-Windows Communication over the other variants are:
\begin{itemize}
\item Possible to communicate to other machines.
\item No need for additional mechanism that will wait both for X and DDE\@.
\item Many of the required capabilities are already there.
\end{itemize}
Disadvantages of X-windows communication:
\begin{itemize}
\item {\em Slow}\ and complex memory access.
\item May be hard to avoid two applications from entering critical
code at the same time.
\end{itemize}
\subsection{BSD Sockets}
The advantages of Sockets are:
\begin{itemize}
\item Possible to communicate to other machines.
\item No need for complex mechanism that will wait both for X and
DDE\@. (can use one ``select'' on X-windows socket in concert with
the DDE socket).
\end{itemize}
Disadvantages of socket are:
\begin{itemize}
\item {\em Slow}{} and complex memory access. (note that mmap on a
descriptor does not work for Linux 0.99).
\item May be hard to avoid two applications from entering critical
code at the same time.
\end{itemize}
\subsection{Why was it written in C? Pros and cons.}
Advantages of C:
\begin{itemize}
\item History- \Wine{} is already written in C.
\item Portability- not all systems have C++.
\item Speed- C++ sometimes makes it very difficult to write fast code.
\item Maintenance- More programmers know C than C++.
\end{itemize}
Advantages of C++:
\begin{itemize}
\item smaller code - Templates allow Smaller and more readable code.
\item Maintenance - It is easier to add and modify code in C++ (than in C).
\item Verification - Functionality can be verified and debugged for
individual objects.
\end{itemize}
I have decided to use C. Most of C++ advantages can be acquired
by using OOP methodologies. OOP methods that require inline functions
can't be used (without performance impact). GCC supports inline functions,
but this solution is not compatible.
\section{\Wine\ basics}
\subsection{How it runs}
\Wine\ works in the following order:
\begin{enumerate}
\item \Wine\ loads the \windoz\ application into it's memory.
(in the process it, links
DLL's\footnote{DLL (Dynamically Linked Library) is linked on load-time.}
creates 16-bit segments).
\item \windoz\ code is executed.
\end{enumerate}
\section{bibliography}
\begin{thebibliography}{99}
\bibitem{bib:WinManual} Charles Petzold {\em Programming
Windows~3.1}{} - 1992. \\
On cover: {\em the Microsoft guide to writing applications for
windows~3.1}. \\
Published by {\em Microsoft press}.
\end{thebibliography}
\newpage
\end{document}

View File

@ -1,287 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: dde_atom.c
* Purpose : atom functionality for DDE
*/
#ifdef CONFIG_IPC
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "dde_atom.h"
#include "shm_main_blk.h"
#include "shm_fragment.h"
#include "ldt.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(atom)
typedef struct
{
WORD count;
BYTE str[1];
} AtomData, *AtomData_ptr;
#define EMPTY 0 /* empty hash entry */
#define DELETED -1 /* deleted hash entry */
#define MIN_STR_ATOM 0xfc00
/* OFS2AtomData_ptr: extract AtomData_ptr from ofs */
#define OFS2AtomData_ptr(ofs) ((AtomData*)((int)&main_block->block+(ofs)))
/* OFS2AtomStr: find the string of the atom */
#define OFS2AtomStr(ofs) (OFS2AtomData_ptr(atom_ofs)->str)
/* offset of an atom according to index */
#define ATOM_OFS(idx) (main_block->atoms[idx])
/* rot_left: rotate (with wrap-around) */
static inline int rot_left(unsigned var,int count)
{
return (var<<count) | (var>> (sizeof(var)-count));
}
/* find the entry in the atom table for this string */
static int FindHash(LPCSTR str) /* ignore str case */
{
int i,j;
unsigned hash1,hash2;
int deleted=-1; /* hash for deleted entry */
int atom_ofs;
/* get basic hash parameters */
for (i= hash1= hash2= 0; str[i] ; i++) {
hash1= rot_left(hash1,5) ^ toupper(str[i]);
hash2= rot_left(hash2,4) ^ toupper(str[i]);
}
hash1%= DDE_ATOMS;
atom_ofs=ATOM_OFS(hash1);
switch (atom_ofs) {
case EMPTY: /* empty atom entry */
return hash1;
case DELETED: /* deleted atom entry */
deleted=hash1;
break;
default : /* non empty atom entry */
if (lstrcmpi16( OFS2AtomStr(atom_ofs) , str) == 0)
return hash1; /* found string in atom table */
}
hash2%= DDE_ATOMS-1 ; /* hash2=0..(DDE_ATOMS-2) */
hash2++; /* hash2=1..(DDE_ATOMS-1) */
/* make jumps in the hash table by hash2 steps */
for (i=hash1+hash2 ; ; i+=hash2) {
/* i wraps around into j */
j=i-DDE_ATOMS;
if (j >= 0)
i=j; /* i wraps around */
if (i==hash1)
/* here if covered all hash locations, and got back to beginning */
return deleted; /* return first empty entry - if any */
atom_ofs=ATOM_OFS(i);
switch (atom_ofs) {
case EMPTY: /* empty atom entry */
return i;
case DELETED: /* deleted atom entry */
if (deleted < 0)
/* consider only the first deleted entry */
deleted= i;
break;
default : /* nonempty atom entry */
if (lstrcmpi16( OFS2AtomStr(atom_ofs) , str) == 0)
return i; /* found string in atom table */
}
}
}
void ATOM_GlobalInit(void)
{
int i;
for (i=0 ; i < DDE_ATOMS ; i++)
ATOM_OFS(i)=EMPTY;
}
/***********************************************************************
* DDE_GlobalAddAtom
*/
/* important! don't forget to unlock semaphores before return */
ATOM DDE_GlobalAddAtom( SEGPTR name )
{
int atom_idx;
int atom_ofs;
AtomData_ptr ptr;
ATOM atom;
char *str;
/* First check for integer atom */
if (!HIWORD(name)) return (ATOM)LOWORD(name);
str = (char *)PTR_SEG_TO_LIN( name );
if (str[0] == '#')
{
ATOM atom= (ATOM) atoi(&str[1]);
return (atom<MIN_STR_ATOM) ? atom : 0;
}
TRACE("(\"%s\")\n",str);
DDE_IPC_init(); /* will initialize only if needed */
shm_write_wait(main_block->sem);
atom_idx=FindHash(str);
atom=(ATOM)0;
/* use "return" only at the end so semaphore handling is done only once */
if (atom_idx>=0) {
/* unless table full and item not found */
switch (atom_ofs= ATOM_OFS(atom_idx)) {
case DELETED:
case EMPTY: /* need to allocate new atom */
atom_ofs= shm_FragmentAlloc(&main_block->block,
strlen(str)+sizeof(AtomData));
if (atom_ofs==NIL)
break; /* no more memory (atom==0) */
ATOM_OFS(atom_idx)=atom_ofs;
ptr=OFS2AtomData_ptr(atom_ofs);
strcpy(ptr->str,str);
ptr->count=1;
atom=(ATOM)(atom_idx+MIN_STR_ATOM);
break;
default : /* has to update existing atom */
OFS2AtomData_ptr(atom_ofs)->count++;
atom=(ATOM)(atom_idx+MIN_STR_ATOM);
} /* end of switch */
} /* end of if */
shm_write_signal(main_block->sem);
return atom;
}
/***********************************************************************
* DDE_GlobalDeleteAtom
*/
ATOM DDE_GlobalDeleteAtom( ATOM atom )
{
int atom_idx;
int atom_ofs;
AtomData_ptr atom_ptr;
ATOM retval=(ATOM) 0;
TRACE("(\"%d\")\n",(int)atom);
atom_idx=(int)atom - MIN_STR_ATOM;
if (atom_idx < 0 )
return 0;
DDE_IPC_init(); /* will initialize only if needed */
shm_write_wait(main_block->sem);
/* return used only once from here on -- for semaphore simplicity */
switch (atom_ofs=ATOM_OFS(atom_idx)) {
case DELETED:
case EMPTY:
WARN("Trying to free unallocated atom %d\n", atom);
retval=atom;
break;
default :
atom_ptr=OFS2AtomData_ptr(atom_ofs);
if ( --atom_ptr->count == 0) {
shm_FragmentFree(&main_block->block,atom_ofs);
ATOM_OFS(atom_idx)=DELETED;
}
}
shm_write_signal(main_block->sem);
return retval;
}
/***********************************************************************
* DDE_GlobalFindAtom
*/
ATOM DDE_GlobalFindAtom( SEGPTR name )
{
int atom_idx;
int atom_ofs;
char *str;
TRACE("(%08lx)\n", name );
/* First check for integer atom */
if (!HIWORD(name)) return (ATOM)LOWORD(name);
str = (char *)PTR_SEG_TO_LIN( name );
if (str[0] == '#')
{
ATOM atom= (ATOM) atoi(&str[1]);
return (atom<MIN_STR_ATOM) ? atom : 0;
}
TRACE("(\"%s\")\n",str);
DDE_IPC_init(); /* will initialize only if needed */
shm_read_wait(main_block->sem);
atom_idx=FindHash(str);
if (atom_idx>=0)
atom_ofs=ATOM_OFS(atom_idx); /* is it free ? */
else
atom_ofs=EMPTY;
shm_read_signal(main_block->sem);
if (atom_ofs==EMPTY || atom_ofs==DELETED)
return 0;
else
return (ATOM)(atom_idx+MIN_STR_ATOM);
}
/***********************************************************************
* DDE_GlobalGetAtomName
*/
WORD DDE_GlobalGetAtomName( ATOM atom, LPSTR buffer, short count )
{
int atom_idx, atom_ofs;
int size;
/* temporary buffer to hold maximum "#65535\0" */
char str_num[7];
if (count<2) /* no sense to go on */
return 0;
atom_idx=(int)atom - MIN_STR_ATOM;
if (atom_idx < 0) { /* word atom */
/* use wine convention... */
sprintf(str_num,"#%d%n",(int)atom,&size);
if (size+1>count) { /* overflow ? */
/* truncate the string */
size=count-1;
str_num[size]='\0';
}
strcpy(buffer,str_num);
return size;
}
DDE_IPC_init(); /* will initialize only if needed */
/* string atom */
shm_read_wait(main_block->sem);
atom_ofs=ATOM_OFS(atom_idx);
if (atom_ofs==EMPTY || atom_ofs==DELETED) {
WARN("Illegal atom=%d\n",(int)atom);
size=0;
} else { /* non empty entry */
/* string length will be at most count-1, find actual size */
sprintf(buffer,"%.*s%n",count-1, OFS2AtomStr(atom_ofs), &size);
}
shm_read_signal(main_block->sem);
return size;
}
#endif /* CONFIG_IPC */

View File

@ -1,103 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: dde_atom_test.c
* Purpose : tests for dde_atom object
***************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <win.h>
#include "dde_atom.h"
#include "shm_main_blk.h"
#include "debugtools.h"
DECLARE_DEBUG_CHANNEL(atom)
DECLARE_DEBUG_CHANNEL(sem)
DECLARE_DEBUG_CHANNEL(shm)
#define TOGETHER (DDE_ATOMS/5)
/* run random sequences */
int main()
{
ATOM atom_list[TOGETHER];
char str[TOGETHER][80];
int i,j,atom_n;
int atom_len[TOGETHER];
TRACE_ON(shm)=1;
TRACE_ON(atom)=0;
TRACE_ON(sem)=0;
for (i=0 ; i<=10000/TOGETHER ; i++) {
for (atom_n=0 ; atom_n<TOGETHER ; atom_n++) {
atom_len[atom_n]=rand()%64+1;
for (j=atom_len[atom_n]-1; j>=0; j--)
do {
str[atom_n][j]=(char)(rand()%255+1);
} while (j==0 && str[atom_n][j]=='#');
str[atom_n][ atom_len[atom_n] ]='\0';
atom_list[atom_n]=GlobalAddAtom(str[atom_n]);
if (atom_list[atom_n]==0) {
fprintf(stderr,"failed i=%d, atom_n=%d\n",i,atom_n);
return 1;
}
if (atom_list[atom_n]!=GlobalAddAtom(str[atom_n])) {
fprintf(stderr,
"wrong second GlobalAddAtom(\"%s\")\n", str[atom_n]);
return 1;
}
} /* for */
for (atom_n=0 ; atom_n<TOGETHER ; atom_n++) {
char buf[80];
int len;
len=GlobalGetAtomName( atom_list[atom_n], buf, 79);
if (atom_len[atom_n] != len) {
fprintf(stderr, "i=%d, atom_n=%d; ", i, atom_n);
fprintf(stderr,
"wrong length of GlobalGetAtomName(\"%s\")\n",
str[atom_n]);
return 1;
}
}
for (atom_n=0 ; atom_n<TOGETHER ; atom_n++) {
GlobalDeleteAtom(atom_list[atom_n]);
if (atom_list[atom_n]!=GlobalAddAtom(str[atom_n])) {
fprintf(stderr, "i=%d, atom_n=%d; ", i, atom_n);
fprintf(stderr,
"wrong third GlobalAddAtom(\"%s\")\n", str[atom_n]);
return 1;
}
GlobalDeleteAtom(atom_list[atom_n]);
GlobalDeleteAtom(atom_list[atom_n]);
atom_list[atom_n]=GlobalAddAtom(str[atom_n]);
if (atom_list[atom_n]!=GlobalAddAtom(str[atom_n])) {
fprintf(stderr,
"i=%d, atom_n=%d wrong fifth GlobalAddAtom(\"%s\")\n",
i, atom_n,
str[atom_n]);
return 1;
}
GlobalDeleteAtom(atom_list[atom_n]);
if (atom_list[atom_n]!=GlobalFindAtom(str[atom_n])) {
fprintf(stderr,
"i=%d, atom_n=%d wrong GlobalFindAtom(\"%s\")\n",
i, atom_n,
str[atom_n]);
return 1;
}
GlobalDeleteAtom(atom_list[atom_n]);
}
}
return 0;
}

View File

@ -1,286 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: dde_mem.c
* Purpose : shared DDE memory functionality for DDE
***************************************************************************
*/
#ifdef CONFIG_IPC
#include <assert.h>
#include "debugtools.h"
#include "ldt.h"
#include "shm_main_blk.h"
#include "shm_fragment.h"
#include "shm_semaph.h"
#include "dde_mem.h"
#include "bit_array.h"
DECLARE_DEBUG_CHANNEL(dde)
DECLARE_DEBUG_CHANNEL(global)
#define SEGPTR2HANDLE_INFO(sptr) ( (struct handle_info*)PTR_SEG_TO_LIN(sptr) )
#define HINFO2DATAPTR(h_info_ptr) ( (void*) ( (char*)h_info_ptr + \
sizeof(struct handle_info) ) )
#define DDE_MEM_IDX(handle) ((handle)& 0x7fff)
#define DDE_MEM_HANDLE(idx) ((idx) | 0x8000)
#define DDE_MEM_INFO(handle) (main_block->handles[ DDE_MEM_IDX(handle) ])
/* List of shared handles.
* This entry resides on the shared memory, the data comes right
* after the `handle_info'.
* The entry is on the same block as the actual data.
* The `next' field gives relative reference (relative to the start of
* the blcok.
*/
struct handle_info {
WORD lock_count;
WORD flags;
int size; /* size of the data (net)*/
};
static bit_array free_handles;
int debug_last_handle_size= 0; /* for debugging purpose only */
/* locate_handle:
* locate a shared memory handle.
* Application:
* The handle is first searched for in attached blocks.
* At the beginning, only blocks owned by this process are
* attached.
* If a handle is not found, new blocks are attached.
* Arguments:
* h - the handle.
* RETURN: pointer to handle info.
*/
static struct handle_info *locate_handle(HGLOBAL16 h, struct local_shm_map *map)
{
struct shm_block *block;
TRACE_(global)("shm: (0x%04x)\n", h);
if (SampleBit( &free_handles, DDE_MEM_IDX(h)) == 0) {
TRACE_(global)("shm: return NULL\n");
return NULL; /* free!!! */
}
block= shm_locate_block(DDE_MEM_INFO(h).shmid, map);
if (block == NULL) {
/* nothing found */
TRACE_(global)("shm: return NULL\n");
return NULL;
}
return (struct handle_info *) REL2PTR(block, DDE_MEM_INFO(h).rel);
}
/* dde_alloc_handle: allocate shared DDE handle */
static HGLOBAL16 dde_alloc_handle()
{
int bit_nr;
bit_nr= AllocateBit( &free_handles);
if (bit_nr != -1)
return DDE_MEM_HANDLE(bit_nr);
TRACE_(global)("dde_alloc_handle: no free DDE handle found\n");
return 0;
}
/**********************************************************************
* DDE_malloc
*/
void *
DDE_malloc(unsigned int flags, unsigned long size, SHMDATA *shmdata)
{
int shmid;
struct shm_block *block;
struct handle_info *h_info;
struct local_shm_map *curr;
HGLOBAL16 handle;
TRACE_(global)("DDE_malloc flags %4X, size %ld\n", flags, size);
DDE_IPC_init(); /* make sure main shm block allocated */
shm_write_wait(main_block->proc[curr_proc_idx].sem);
/* Try to find fragment big enough for `size' */
/* iterate through all local shm blocks, and try to allocate
the fragment */
h_info= NULL;
for (curr= shm_map ; curr != NULL ; curr= curr->next) {
if (curr->proc_idx == curr_proc_idx) {
h_info= (struct handle_info *)
shm_FragPtrAlloc(curr->ptr, size+sizeof(struct handle_info));
if (h_info!=NULL) {
shmid= curr->shm_id;
break;
}
}
}
if (h_info == NULL) {
block= shm_create_block(0, size+sizeof(struct handle_info), &shmid);
if (block==NULL) {
shm_write_signal(main_block->proc[curr_proc_idx].sem);
return 0;
}
/* put the new block in the linked list */
block->next_shm_id= main_block->proc[curr_proc_idx].shmid;
main_block->proc[curr_proc_idx].shmid= shmid;
h_info= (struct handle_info *)
shm_FragPtrAlloc(block, size+sizeof(struct handle_info));
if (h_info==NULL) {
ERR_(global)("BUG! unallocated fragment\n");
shm_write_signal(main_block->proc[curr_proc_idx].sem);
return 0;
}
} else {
block= curr->ptr;
}
/* Here we have an allocated fragment */
h_info->flags= flags;
h_info->lock_count= 0;
h_info->size= size;
handle= dde_alloc_handle();
if (handle) {
TRACE_(global)("returning handle=0x%4x, ptr=0x%08lx\n",
(int)handle, (long) HINFO2DATAPTR(h_info));
DDE_MEM_INFO(handle).rel= PTR2REL(block, h_info);
DDE_MEM_INFO(handle).shmid= shmid;
}
else
WARN_(global)("failed\n");
shm_write_signal(main_block->proc[curr_proc_idx].sem);
shmdata->handle= handle;
return (char *)HINFO2DATAPTR(h_info);
}
HGLOBAL16 DDE_GlobalFree(HGLOBAL16 h)
{
struct handle_info *h_info;
int handle_index= h & 0x7fff;
struct local_shm_map map;
TRACE_(global)("(0x%04x)\n",h);
if (h==0)
return 0;
h_info= locate_handle(h, &map);
if (h_info == NULL)
return h;
shm_write_wait(main_block->proc[map.proc_idx].sem);
shm_FragPtrFree(map.ptr, (struct shm_fragment *) h_info);
AssignBit( &free_handles, handle_index, 0);
/* FIXME: must free the shm block some day. */
shm_write_signal(main_block->proc[map.proc_idx].sem);
return 0;
}
WORD DDE_SyncHandle(HGLOBAL16 handle, WORD sel)
{
struct handle_info *h_info;
void *local_ptr;
ldt_entry entry;
h_info= locate_handle(handle, NULL);
local_ptr= (void *)GET_SEL_BASE(sel);
if (h_info == NULL)
return 0;
if (local_ptr == (void *) HINFO2DATAPTR(h_info))
return sel;
/* need syncronization ! */
LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
entry.base= (unsigned long) HINFO2DATAPTR(h_info);
LDT_SetEntry( SELECTOR_TO_ENTRY(sel), &entry );
return sel;
}
/*
* DDE_AttachHandle:
* Attach shm memory (The data must not be already attached).
* Parameters:
* handle - the memory to attach.
* segptr - in not null, return SEGPTR to the same block.
* return value:
* 32 bit pointer to the memory.
*/
void *DDE_AttachHandle(HGLOBAL16 handle, SEGPTR *segptr)
{
struct handle_info *h_info;
SHMDATA shmdata;
void *ptr;
HGLOBAL16 hOwner = GetCurrentPDB16();
assert(is_dde_handle(handle));
if (segptr != NULL)
*segptr=0;
TRACE_(global)("(%04x)\n",handle);
h_info=locate_handle(handle, NULL);
if (h_info == NULL)
return NULL;
if ( !(h_info->flags & GMEM_DDESHARE) ) {
ERR_(global)("Corrupted memory handle info\n");
return NULL;
}
TRACE_(global)("h_info=%06lx\n",(long)h_info);
shmdata.handle= handle;
shmdata.shmid= DDE_MEM_INFO(handle).shmid;
ptr= HINFO2DATAPTR(h_info);
/* Allocate the selector(s) */
if (! GLOBAL_CreateBlock( h_info->flags, ptr, h_info->size, hOwner,
FALSE, FALSE, FALSE, &shmdata))
return NULL;
if (segptr != NULL)
*segptr= (SEGPTR)MAKELONG( 0, shmdata.sel);
if (TRACE_ON(dde))
debug_last_handle_size= h_info->size;
TRACE_(global)("DDE_AttachHandle returns ptr=0x%08lx\n", (long)ptr);
return (LPSTR)ptr;
}
void DDE_mem_init()
{
int nr_of_bits;
shm_init();
nr_of_bits= BITS_PER_BYTE * sizeof(main_block->free_handles);
AssembleArray( &free_handles, main_block->free_handles, nr_of_bits);
}
#endif /* CONFIG_IPC */

View File

@ -1,73 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: dde_mem_test.c
* Purpose : test shared DDE memory functionality for DDE
* Usage: Look for assertion failures
***************************************************************************
*/
#include <stdio.h>
#include <assert.h>
#include <win.h>
#include "dde_mem.h"
/* stub */
void ATOM_GlobalInit()
{
printf("ATOM_GlobalInit\n");
}
int main()
{
HWND h1,h2,h3;
int ret;
void *p1,*p2,*p3,*p;
SHMDATA shmdata;
/* alloc h1, h2, h3 */
setbuf(stdout,NULL);
p1=DDE_malloc(GMEM_DDESHARE, 0x6000, &shmdata);
h1= shmdata.handle;
assert(p1 != NULL);
assert(h1 != 0);
p2=DDE_malloc(GMEM_DDESHARE, 0xff00, &shmdata);
h2= shmdata.handle;
assert(p2 != NULL);
assert(h2 != 0);
p3=DDE_malloc(GMEM_DDESHARE, 0x6000, &shmdata);
h3= shmdata.handle;
assert(p3 != 0);
assert(h3 != 0);
/* lock h1, h2, h3 */
p=DDE_AttachHandle(h1,NULL);
assert(p1==p);
p=DDE_AttachHandle(h2,NULL);
assert(p2==p);
p=DDE_AttachHandle(h3,NULL);
assert(p3==p);
ret=DDE_GlobalFree(h1);
assert(ret==0);
/* do some implementation dependant tests */
p=DDE_malloc(GMEM_DDESHARE, 0x6000, &shmdata);
assert(p!=NULL);
assert(shmdata.handle==h1);
p=DDE_AttachHandle(h1,NULL);
assert(p1==p);
/* check freeing */
ret=DDE_GlobalFree(h1);
assert(ret==0);
ret=DDE_GlobalFree(h2);
assert(ret==0);
ret=DDE_GlobalFree(h3);
assert(ret==0);
return 0;
}

View File

@ -1,719 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: dde_proc.c
* Purpose : DDE signals and processes functionality for DDE
***************************************************************************
*/
#ifdef CONFIG_IPC
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#define msgbuf mymsg
#endif
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <sys/msg.h>
#include "windef.h"
#include "win.h"
#include "shm_semaph.h"
#include "shm_main_blk.h"
#include "dde_proc.h"
#include "dde_mem.h"
#include "dde.h"
#include "debugtools.h"
#include "xmalloc.h"
DECLARE_DEBUG_CHANNEL(dde)
DECLARE_DEBUG_CHANNEL(msg)
int curr_proc_idx= -1;
enum stop_wait_op stop_wait_op=CONT;
int had_SIGUSR2 = 0;
sigjmp_buf env_get_ack;
sigjmp_buf env_wait_x;
#define IDX_TO_HWND(idx) (0xfffe - (idx))
#define HWND_TO_IDX(wnd) (0xfffe - (wnd))
#define DDE_WIN_INFO(win) ( main_block->windows[HWND_TO_IDX(win)] )
#define DDE_WIN2PROC(win) ( DDE_WIN_INFO(win).proc_idx )
#define DDE_IsRemoteWindow(win) ( (win)<0xffff && (win)>=(0xffff-DDE_PROCS))
#define DDE_SEND 1
#define DDE_POST 2
#define DDE_ACK 3
#define DDE_MSG_SIZE sizeof(MSG16)
#define FREE_WND (WORD)(-2)
#define DELETED_WND (WORD)(-3)
static char *msg_type[4]={"********", "DDE_SEND", "DDE_POST", "DDE_ACK"};
struct msg_dat {
struct msgbuf dat;
char filler[DDE_MSG_SIZE];
} ;
typedef struct fifo_element {
int value;
struct fifo_element *next;
} fifo_element;
struct fifo {
fifo_element *first; /* first element in the fifo or NULL */
fifo_element *last; /* last element in the fifo or NULL */
};
static struct fifo fifo = {NULL,NULL};
void dde_proc_delete(int proc_idx);
void dde_proc_add_fifo(int val)
{
fifo_element *created;
created= (fifo_element*) xmalloc( sizeof(fifo_element) );
created->value = val;
created->next = NULL;
if (fifo.first==NULL)
fifo.first= created;
else
fifo.last->next= created;
fifo.last = created;
}
/* get an item from the fifo, and return it.
* If fifo is empty, return -1
*/
int dde_proc_shift_fifo()
{
int val;
fifo_element *deleted;
if (fifo.first == NULL)
return -1;
deleted= fifo.first;
val= deleted->value;
fifo.first= deleted->next;
if (fifo.first == NULL)
fifo.last= NULL;
free(deleted);
return val;
}
static void print_dde_message(char *desc, MSG16 *msg);
/* This should be run only when main_block is first allocated. */
void dde_proc_init(dde_proc proc)
{
int proc_num;
for (proc_num=0 ; proc_num<DDE_PROCS ; proc_num++, proc++) {
proc->msg=-1;
proc->sem=-1;
proc->shmid=-1;
proc->pid=-1;
}
}
/* add current process to the list of processes */
void dde_proc_add(dde_proc procs)
{
dde_proc proc;
int proc_idx;
TRACE_(dde)("(..)\n");
shm_write_wait(main_block->sem);
/* find free proc_idx and allocate it */
for (proc_idx=0, proc=procs ; proc_idx<DDE_PROCS ; proc_idx++, proc++)
if (proc->pid==-1)
break; /* found! */
if (proc_idx<DDE_PROCS) { /* got here beacuse a free was found ? */
dde_msg_setup(&proc->msg);
proc->pid=getpid();
curr_proc_idx=proc_idx;
shm_sem_init(&proc->sem);
}
else {
fflush(stdout);
WARN_(dde)("Can't allocate process\n");
}
shm_write_signal(main_block->sem);
}
/* wait for dde - acknowledge message - or timout */
static BOOL get_ack()
{
struct timeval timeout;
int size;
struct msg_dat ack_buff;
/* timeout after exactly one seconf */
timeout.tv_sec = 1;
timeout.tv_usec = 0;
sigsetjmp(env_get_ack, 1);
/* get here after normal execution, or after siglongjmp */
do { /* loop to wait for DDE_ACK */
had_SIGUSR2=0;
stop_wait_op=CONT; /* sensitive code: disallow siglongjmp */
size= msgrcv( main_block->proc[curr_proc_idx].msg , &ack_buff.dat,
1, DDE_ACK, IPC_NOWAIT);
if (size>=0) {
TRACE_(msg)("get_ack: received DDE_ACK message\n");
return TRUE;
}
if (DDE_GetRemoteMessage()) {
had_SIGUSR2=1; /* might have recieved SIGUSR2 */
}
stop_wait_op=STOP_WAIT_ACK; /* allow siglongjmp */
} while (had_SIGUSR2); /* loop if SIGUSR2 was recieved */
/* siglongjmp should be enabled at this moment */
select( 0, NULL, NULL, NULL, &timeout );
stop_wait_op=CONT; /* disallow further siglongjmp */
/* timeout !! (otherwise there would have been a siglongjmp) */
return FALSE;
}
/* Transfer one message to a given process */
static BOOL DDE_DoOneMessage (int proc_idx, int size, struct msgbuf *msgbuf)
{
dde_proc proc= &main_block->proc[ proc_idx ];
if (proc_idx == curr_proc_idx)
return FALSE;
if (kill(proc->pid,0) < 0) {
/* pid does not exist, or not our */
dde_proc_delete(proc_idx);
return FALSE;
}
if (TRACE_ON(dde) || WARN_ON_dde) {
MSG16 *msg=(MSG16*) &msgbuf->mtext;
char *title;
if (msgbuf->mtype==DDE_SEND)
title="sending dde:";
else if (msgbuf->mtype==DDE_POST)
title="posting dde:";
else
title=NULL;
if (title)
print_dde_message(title, msg);
else
WARN_(dde)("Unknown message type=0x%lx\n", msgbuf->mtype);
}
TRACE_(msg)("to proc_idx=%d (pid=%d), queue=%u\n",
proc_idx, proc->pid, (unsigned)proc->msg);
if ( proc->msg != -1) {
TRACE_(msg)("doing...(type=%s)\n", msg_type[msgbuf->mtype]);
size=msgsnd (proc->msg, msgbuf, size, 0);
if (size<0) {
fflush(stdout);
perror("msgsnd");
}
kill(proc->pid,SIGUSR2); /* tell the process there is a message */
TRACE_(msg)("Trying to get acknowledgment from msg queue=%d\n",
proc->msg);
Yield16(); /* force task switch, and */
/* acknowledgment sending */
if (get_ack()) {
return TRUE;
} else {
fflush(stdout);
WARN_(dde)("get_ack: DDE_DoOneMessage: timeout\n");
return FALSE;
}
}
else {
WARN_(msg)("message not sent, target has no message queue\n");
return FALSE;
}
}
/* Do some sort of premitive hash table */
static HWND16 HWND_Local2Remote(HWND16 orig)
{
int dde_wnd_idx;
int deleted_idx= -1;
WND_DATA *tested;
WND_DATA *deleted= NULL;
int i;
dde_wnd_idx= orig % DDE_WINDOWS;
for ( i=0 ; i < DDE_WINDOWS ; i++, dde_wnd_idx++) {
if (dde_wnd_idx >= DDE_WINDOWS)
dde_wnd_idx -= DDE_WINDOWS; /* wrap-around */
tested= &main_block->windows[ dde_wnd_idx ];
if (tested->proc_idx == FREE_WND)
break;
if (deleted == NULL && tested->proc_idx == DELETED_WND) {
deleted= tested;
deleted_idx= dde_wnd_idx;
} else if (tested->wnd == orig && tested->proc_idx == curr_proc_idx) {
return IDX_TO_HWND(dde_wnd_idx);
}
}
if (deleted != NULL) { /* deleted is preferable */
/* free item, allocate it */
deleted->proc_idx= curr_proc_idx;
deleted->wnd = orig;
return IDX_TO_HWND(deleted_idx);
}
if (tested->proc_idx == FREE_WND) {
tested->proc_idx= curr_proc_idx;
tested->wnd = orig;
return IDX_TO_HWND(dde_wnd_idx);
}
WARN_(dde)("Can't map any more windows to DDE windows\n");
return 0;
}
static BOOL DDE_DoMessage( MSG16 *msg, int type )
{
int proc_idx;
MSG16 *remote_message;
struct msg_dat msg_dat;
BOOL success;
if (msg->wParam == 0)
return FALSE;
if (main_block==NULL) {
if (msg->message >= WM_DDE_FIRST && msg->message <= WM_DDE_LAST)
DDE_IPC_init();
else
return FALSE;
}
if (msg->wParam == (HWND16)-1)
return FALSE;
if ( ! DDE_IsRemoteWindow(msg->hwnd) && msg->hwnd!= (HWND16)-1)
return FALSE;
TRACE_(msg)("(hwnd=0x%x,msg=0x%x,..) - %s\n",
(int)msg->hwnd,(int)msg->message,msg_type[type]);
TRACE_(msg)("(hwnd=0x%x,msg=0x%x,..) -- HWND_BROADCAST !\n",
(int)msg->hwnd,(int)msg->message);
remote_message=(void*)&msg_dat.dat.mtext;
memcpy(remote_message, msg, sizeof(*msg));
remote_message->wParam= HWND_Local2Remote(msg->wParam);
if (remote_message->wParam == 0)
return FALSE;
msg_dat.dat.mtype=type;
if (msg->hwnd == (HWND16)-1) {
success= FALSE;
for ( proc_idx=0; proc_idx < DDE_PROCS ; proc_idx++) {
if (proc_idx == curr_proc_idx)
continue;
if (main_block->proc[ proc_idx ].msg != -1)
success|=DDE_DoOneMessage(proc_idx, DDE_MSG_SIZE, &msg_dat.dat);
}
return success;
} else {
return DDE_DoOneMessage(DDE_WIN2PROC(msg->hwnd), DDE_MSG_SIZE,
&msg_dat.dat);
}
}
BOOL DDE_SendMessage( MSG16 *msg)
{
return DDE_DoMessage(msg, DDE_SEND);
}
BOOL DDE_PostMessage( MSG16 *msg)
{
return DDE_DoMessage(msg, DDE_POST);
}
void dde_proc_send_ack(HWND16 wnd, BOOL val) {
int proc,msg;
static struct msgbuf msg_ack={DDE_ACK,{'0'}};
proc=DDE_WIN2PROC(wnd);
msg=main_block->proc[proc].msg;
TRACE_(msg)("sending ACK to wnd=%4x, proc=%d,msg=%d, pid=%d\n",
wnd,proc,msg,main_block->proc[proc].pid);
msg_ack.mtext[0]=val;
msgsnd (msg, &msg_ack, 1, 0);
kill(main_block->proc[proc].pid, SIGUSR2);
}
/* return true (non zero) if had a remote message */
#undef DDE_GetRemoteMessage
int DDE_GetRemoteMessage()
{
static int nesting=0; /* to avoid infinite recursion */
MSG16 *remote_message;
int size;
struct msg_dat msg_dat;
BOOL was_sent; /* sent/received */
BOOL passed;
WND *wndPtr;
if (curr_proc_idx==-1) /* do we have DDE initialized ? */
return 0;
if (nesting>10) {
fflush(stdout);
ERR_(msg)("suspecting infinite recursion, exiting");
return 0;
}
remote_message=(void*)&msg_dat.dat.mtext;
/* test for SendMessage */
size= msgrcv( main_block->proc[curr_proc_idx].msg , &msg_dat.dat,
DDE_MSG_SIZE, DDE_SEND, IPC_NOWAIT);
if (size==DDE_MSG_SIZE) { /* is this a correct message (if any) ?*/
was_sent=TRUE;
TRACE_(msg)("DDE:receive sent message. msg=%04x wPar=%04x"
" lPar=%08lx\n",
remote_message->message, remote_message->wParam,
remote_message->lParam);
} else {
size= msgrcv( main_block->proc[curr_proc_idx].msg , &msg_dat.dat,
DDE_MSG_SIZE, DDE_POST, IPC_NOWAIT);
if (size==DDE_MSG_SIZE) { /* is this a correct message (if any) ?*/
was_sent=FALSE;
TRACE_(msg)("DDE:receive posted message. "
"msg=%04x wPar=%04x lPar=%08lx\n",
remote_message->message, remote_message->wParam,
remote_message->lParam);
}
else
return 0; /* no DDE message found */
}
/* At this point we are sure that there is a DDE message,
* was_sent is TRUE is the message was sent, and false if it was posted
*/
nesting++;
if (TRACE_ON(dde)) {
char *title;
if (was_sent)
title="receive sent dde:";
else
title="receive posted dde:";
print_dde_message(title, remote_message);
}
if (remote_message->hwnd != (HWND16) -1 ) {
HWND16 dde_window= DDE_WIN_INFO(remote_message->hwnd).wnd;
/* we should know exactly where to send the message (locally)*/
if (was_sent) {
TRACE_(dde)("SendMessage(wnd=0x%04x, msg=0x%04x, wPar=0x%04x,"
"lPar=0x%08x\n", dde_window, remote_message->message,
remote_message->wParam, (int)remote_message->lParam);
/* execute the recieved message */
passed= SendMessage16(dde_window, remote_message->message,
remote_message->wParam, remote_message->lParam);
/* Tell the sended, that the message is here */
dde_proc_send_ack(remote_message->wParam, passed);
}
else {
passed= PostMessage16(dde_window, remote_message->message,
remote_message->wParam, remote_message->lParam);
if (passed == FALSE) {
/* Tell the sender, that the message is here, and failed */
dde_proc_send_ack(remote_message->wParam, FALSE);
}
else {
/* ack will be sent later, at the first peek/get message */
dde_proc_add_fifo(remote_message->wParam);
}
}
nesting--;
return 1;
}
/* iterate through all the windows */
for (wndPtr = WIN_FindWndPtr(GetTopWindow(GetDesktopWindow()));
wndPtr != NULL;
WIN_UpdateWndPtr(&wndPtr,wndPtr->next))
{
if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) {
if (was_sent)
SendMessage16( wndPtr->hwndSelf, remote_message->message,
remote_message->wParam, remote_message->lParam );
else
PostMessage16( wndPtr->hwndSelf, remote_message->message,
remote_message->wParam, remote_message->lParam );
} /* if */
} /* for */
/* replay with DDE_ACK after broadcasting in DDE_GetRemoteMessage */
dde_proc_send_ack(remote_message->wParam, TRUE);
nesting--;
return 1;
}
int dde_reschedule()
{
int ack_wnd;
ack_wnd= dde_proc_shift_fifo();
if (ack_wnd != -1) {
dde_proc_send_ack(ack_wnd, TRUE);
usleep(10000); /* force unix task switch */
return 1;
}
return 0;
}
void dde_msg_setup(int *msg_ptr)
{
*msg_ptr= msgget (IPC_PRIVATE, IPC_CREAT | 0700);
if (*msg_ptr==-1)
perror("dde_msg_setup fails to get message queue");
}
/* do we have dde handling in the window ?
* If we have, atom usage will make this instance of wine set up
* it's IPC stuff.
*/
void DDE_TestDDE(HWND16 hwnd)
{
static in_test = 0;
if (in_test++) return;
if (main_block != NULL) {
in_test--;
return;
}
TRACE_(msg)("(0x%04x)\n", hwnd);
if (hwnd==0)
hwnd=-1;
/* just send a message to see how things are going */
SendMessage16( hwnd, WM_DDE_INITIATE, 0, 0);
in_test--;
}
void dde_proc_delete(int proc_idx)
{
dde_proc_done(&main_block->proc[proc_idx]);
}
void stop_wait(int a)
{
had_SIGUSR2=1;
switch(stop_wait_op) {
case STOP_WAIT_ACK:
siglongjmp(env_get_ack,1);
break; /* never reached */
case STOP_WAIT_X:
siglongjmp(env_wait_x,1);
break; /* never reached */
case CONT:
/* do nothing */
}
}
static void print_dde_message(char *desc, MSG16 *msg)
{
/* extern const char *MessageTypeNames[];*/
extern int debug_last_handle_size;
WORD wStatus,hWord;
void *ptr;
DDEACK *ddeack;
DDEADVISE *ddeadvise;
DDEDATA *ddedata;
DDEPOKE *ddepoke;
dbg_decl_str(dde, 2048);
if (is_dde_handle(msg->lParam & 0xffff) )
ptr=DDE_AttachHandle(msg->lParam&0xffff, NULL);
else
ptr =NULL;
wStatus=LOWORD(msg->lParam);
hWord=HIWORD(msg->lParam);
dsprintf(dde,"%s", desc);
dsprintf(dde,"%04x %04x==%s %04x %08lx ",
msg->hwnd, msg->message,"",/*MessageTypeNames[msg->message],*/
msg->wParam, msg->lParam);
switch(msg->message) {
case WM_DDE_INITIATE:
case WM_DDE_REQUEST:
case WM_DDE_EXECUTE:
case WM_DDE_TERMINATE:
/* nothing to do */
break;
case WM_DDE_ADVISE:
/* DDEADVISE: hOptions in WM_DDE_ADVISE message */
if (ptr) {
ddeadvise=ptr;
dsprintf(dde,"fDeferUpd=%d,fAckReq=%d,cfFormat=0x%x",
ddeadvise->fDeferUpd, ddeadvise->fAckReq,
ddeadvise->cfFormat);
} else
dsprintf(dde,"NO-DATA");
dsprintf(dde," atom=0x%x",hWord);
break;
case WM_DDE_UNADVISE:
dsprintf(dde,"format=0x%x, atom=0x%x",wStatus,hWord);
break;
case WM_DDE_ACK:
ddeack=(DDEACK*)&wStatus;
dsprintf(dde,"bAppReturnCode=%d,fBusy=%d,fAck=%d",
ddeack->bAppReturnCode, ddeack->fBusy, ddeack->fAck);
if (ddeack->fAck)
dsprintf(dde,"(True)");
else
dsprintf(dde,"(False)");
break;
case WM_DDE_DATA:
if (ptr) {
ddedata=ptr;
dsprintf(dde,"fResponse=%d,fRelease=%d,"
"fAckReq=%d,cfFormat=0x%x,value=\"%.*s\"",
ddedata->fResponse, ddedata->fRelease,
ddedata->fAckReq, ddedata->cfFormat,
debug_last_handle_size- (int)sizeof(*ddedata)+1,
ddedata->Value);
} else
dsprintf(dde,"NO-DATA");
dsprintf(dde," atom=0x%04x",hWord);
break;
case WM_DDE_POKE:
if (ptr) {
ddepoke=ptr;
dsprintf(dde,"fRelease=%d,cfFormat=0x%x,value[0]='%c'",
ddepoke->fRelease, ddepoke->cfFormat, ddepoke->Value[0]);
} else
dsprintf(dde,"NO-DATA");
dsprintf(dde," atom=0x%04x",hWord);
break;
}
TRACE_(dde)("%s\n", dbg_str(dde));
}
void dde_proc_done(dde_proc proc)
{
if (proc->msg != -1)
msgctl(proc->msg, IPC_RMID, NULL);
proc->msg=-1;
proc->pid=-1;
shm_delete_chain(&proc->shmid);
shm_sem_done(&proc->sem);
}
/* delete entry, if old junk */
void dde_proc_refresh(dde_proc proc)
{
if (proc->pid == -1)
return;
if (kill(proc->pid, 0) != -1)
return;
/* get here if entry non empty, and the process does not exist */
dde_proc_done(proc);
}
void dde_wnd_setup()
{
int i;
for (i=0 ; i < DDE_WINDOWS ; i++)
main_block->windows[i].proc_idx = FREE_WND;
}
static BOOL DDE_ProcHasWindows(int proc_idx)
{
WND_DATA *tested;
int i;
for ( i=0 ; i < DDE_WINDOWS ; i++) {
tested= &main_block->windows[ i ];
if (tested->proc_idx == proc_idx)
return TRUE;
}
return FALSE;
}
/* Look for hwnd in the hash table of DDE windows,
* Delete it from there. If there are no more windows for this
* process, remove the process from the DDE data-structure.
* If there are no more processes - delete the whole DDE struff.
*
* This is inefficient, but who cares for the efficiency of this rare
* operation...
*/
void DDE_DestroyWindow(HWND16 hwnd)
{
int dde_wnd_idx;
WND_DATA *tested;
int i;
if (main_block == NULL)
return;
dde_wnd_idx= hwnd % DDE_WINDOWS;
for ( i=0 ; i < DDE_WINDOWS ; i++, dde_wnd_idx++) {
if (dde_wnd_idx >= DDE_WINDOWS)
dde_wnd_idx -= DDE_WINDOWS; /* wrap-around */
tested= &main_block->windows[ dde_wnd_idx ];
if (tested->proc_idx == FREE_WND)
return; /* No window will get deleted here */
if (tested->wnd == hwnd && tested->proc_idx == curr_proc_idx) {
dde_reschedule();
tested->proc_idx= DELETED_WND;
if (DDE_ProcHasWindows( curr_proc_idx ))
return;
while (dde_reschedule()) /* make sure there are no other */
/* processes waiting for acknowledgment */
;
dde_proc_delete( curr_proc_idx );
if (DDE_no_of_attached() == 1)
shm_delete_all(-1);
else {
shmdt( (void *) main_block);
main_block= NULL;
}
return;
}
}
}
#endif /* CONFIG_IPC */

View File

@ -1,117 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: dde_proc.c
* Purpose : test DDE signals and processes functionality for DDE
* Usage: run two independant processes, one with an argument another
* without (with the argument is the server).
***************************************************************************
*/
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include <sys/syscall.h>
#include <sys/param.h>
#else
#include <syscall.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <win.h>
#include "dde.h"
#include "dde_proc.h"
#include "shm_main_blk.h"
#if !defined(BSD4_4) || defined(linux) || defined(__FreeBSD__)
char * cstack[4096];
#endif
#ifdef linux
extern void ___sig_restore();
extern void ___masksig_restore();
/* Similar to the sigaction function in libc, except it leaves alone the
restorer field */
static int
wine_sigaction(int sig,struct sigaction * new, struct sigaction * old)
{
__asm__("int $0x80":"=a" (sig)
:"0" (SYS_sigaction),"b" (sig),"c" (new),"d" (old));
if (sig>=0)
return 0;
errno = -sig;
return -1;
}
#endif
struct sigaction usr2_act;
void init_signals()
{
#ifdef linux
usr2_act.sa_handler = (__sighandler_t) stop_wait;
usr2_act.sa_flags = 0;
usr2_act.sa_restorer =
(void (*)()) (((unsigned int)(cstack) + sizeof(cstack) - 4) & ~3);
wine_sigaction(SIGUSR2,&usr2_act,NULL);
#endif
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
usr2_act.sa_hadnler = (void (*)) stop_wait;
usr2_act.sa_flags = SA_ONSTACK;
usr2_act.sa_mask = sig_mask;
usr2_act.sa_restorer =
(void (*)()) (((unsigned int)(cstack) + sizeof(cstack) - 4) & ~3);
if (sigaction(SIGUSR2,&usr2_act,NULL) <0) {
perror("sigaction: SIGUSR2");
exit(1);
}
#endif
}
void ATOM_GlobalInit()
{
printf("ATOM_GlobalInit\n");
}
void idle_loop()
{
int timeout;
for(timeout=500; timeout ; timeout--) {
if (DDE_GetRemoteMessage())
exit(0); ;
usleep(1000);
}
exit(-1);
}
void client()
{
MSG msg;
msg.hwnd=(HWND)-1;
msg.message= WM_DDE_INITIATE;
msg.wParam= 3;
msg.lParam= 4;
if (!DDE_SendMessage(&msg))
exit(-1);
idle_loop();
}
void server()
{
DDE_IPC_init();
idle_loop();
}
int main(int argc, char *argv[])
{
printf("Kill when done one message\n");
init_signals();
if (argc>1)
server();
else
client();
return 0;
}

View File

@ -1,683 +0,0 @@
/***************************************************************************
* Copyright 1995 Michael Veksler. mveksler@vnet.ibm.com
***************************************************************************
* File: generic_hash.c
* Purpose : dynamically growing hash, may use shared or local memory.
***************************************************************************
*/
#ifdef CONFIG_IPC
#include <sys/types.h>
#include <stdlib.h>
#include <assert.h>
#include "generic_hash.h"
#define ROUND_UP4(num) (( (num)+3) & ~3)
#define FREE_ENTRY 0
#define DELETED_ENTRY ((DWORD)-1)
#define NO_OF_PRIMES 512
#define GET_ITEM(items,size,i)\
(*(HASH_ITEM*) \
( ((char *)(items))+ \
(i)*(size)) )
static HASH_ITEM *locate_entry(HASH_CONTAINER* hash, DWORD key,
HASH_VAL *seeked_data, BOOL skip_deleted);
static void copy_hash_items(HASH_CONTAINER *hash, HASH_ITEM *old_items,
int old_n_items);
static BOOL arrays_initialized = FALSE;
static int primes[NO_OF_PRIMES];
static int best_primes[NO_OF_PRIMES];
static int no_of_primes;
static int no_of_best_primes;
static int max_num;
/* binary search for `num' in the `primes' array */
static BOOL prime_binary_search_found(int num)
{
int min_idx, max_idx, idx;
min_idx=0;
max_idx=no_of_primes-1;
while (min_idx <= max_idx) {
idx = (max_idx + min_idx) >> 1;
if (num == primes[idx])
return TRUE;
if (num < primes[idx])
max_idx = idx-1;
else
min_idx = idx+1;
}
return FALSE;
}
static BOOL is_prime(int num)
{
int i;
if ((num & 0x1) == 0) /* can be divided by 2 */
if (num == 2)
return TRUE;
else
return FALSE;
if (num <= primes[no_of_primes-1])
return prime_binary_search_found(num);
for (i=0 ; i < no_of_primes ; i++) {
if (num % primes[i] == 0)
return FALSE;
if (num < primes[i] * primes[i])
return TRUE;
}
return TRUE;
}
static void setup_primes()
{
int num;
primes[0]=2;
primes[1]=3;
no_of_primes=2;
/* count in modulo 6 to avoid numbers that divide by 2 or 3 */
for (num=5 ; ; num+=6) {
if (is_prime(num)) {
primes[no_of_primes++]=num;
if (no_of_primes >= NO_OF_PRIMES)
break;
}
if (is_prime(num+2)) {
primes[no_of_primes++]=num+2;
if (no_of_primes >= NO_OF_PRIMES)
break;
}
}
max_num= primes[no_of_primes-1] * primes[no_of_primes-1];
}
/* Find primes which are far "enough" from powers of two */
void setup_best_primes()
{
int i;
int num;
int pow2before, pow2after;
int min_range, max_range;
min_range=3;
max_range=3;
pow2before= 2;
pow2after= 4;
no_of_best_primes= 0;
for (i=0 ; i < no_of_primes ; i++){
num= primes[i];
if (num > pow2after) {
pow2before= pow2after;
pow2after <<=1;
min_range= pow2before+ (pow2before >> 3);
max_range= pow2after- (pow2before >> 2);
}
if (num > min_range && num < max_range)
best_primes[no_of_best_primes++]=num;
}
}
/* binary search for `num' in the `best_primes' array,
* Return smallest best_prime >= num.
*/
static int best_prime_binary_search(int num)
{
int min_idx, max_idx, idx;
min_idx=0;
max_idx=no_of_best_primes-1;
while (1) {
idx = (max_idx + min_idx) >> 1;
if (num == best_primes[idx])
return num;
if (num < best_primes[idx]) {
max_idx = idx-1;
if (max_idx <= min_idx)
return best_primes[idx];
}
else {
min_idx = idx+1;
if (min_idx >= max_idx)
return best_primes[max_idx];
}
}
}
/* Find the best prime, near `num' (which can be any number) */
static int best_prime(int num)
{
int log2;
int pow2less, pow2more;
int min_range, max_range;
if (num < 11)
return 11;
if (num <= best_primes[no_of_best_primes-1])
return best_prime_binary_search(num);
assert( num < max_num );
for (log2=0 ; num >> log2 ; log2++)
;
pow2less= 1 << log2;
pow2more= 1 << (log2+1);
min_range= pow2less + (pow2less >> 3);
max_range= pow2more - (pow2more >> 3);
if (num < min_range)
num= min_range;
num |= 1; /* make sure num can't be divided by 2 */
while (1) {
if (num >= max_range) {
pow2less<<= 1;
pow2more<<= 1;
min_range= pow2less + (pow2less >> 3);
max_range= pow2more - (pow2more >> 3);
num= min_range | 1; /* make sure num can't be divided by 2 */
}
/* num should be here in the range: (min_range, max_range) */
if (is_prime(num))
return num;
num+=2;
}
}
/* FIXME: This can be done before compiling. (uning a script)*/
static void setup_arrays()
{
setup_primes();
setup_best_primes();
}
/* Discard all DELETED_ENTRYs moving the data to it's correct location.
* Done without a temporary buffer.
* May require some efficiency improvements ( currently it's o(N^2)
* or is it o(N^3) in the worst case ? In the avarege it seems to be
* something like o(N log (N)))
*/
static void static_collect_garbge(HASH_CONTAINER *hash)
{
int i;
BOOL change;
HASH_ITEM *items;
HASH_ITEM *located;
HASH_ITEM *item;
int key;
items= hash->items;
do {
change= FALSE;
for (i=hash->shared->total_items-1 ; i >= 0 ; i--) {
item= &GET_ITEM(items,hash->bytes_per_item,i);
key= item->key;
if (key != DELETED_ENTRY && key != FREE_ENTRY) {
/* try to place the entry in a deleted location */
located= locate_entry(hash, key, &item->data,
0 /* no skip_deleted */);
if (located->key == DELETED_ENTRY) {
change= TRUE;
memcpy(&located, &item,
hash->bytes_per_item);
item->key= DELETED_ENTRY;
}
}
}
} while (change);
/* No change means that there is no need to go through a DELETED_ENTRY
* in order to reach an item, so DELETED_ENTRY looses it's special
* meaning, and it is the same as FREE_ENTRY.
*/
for (i=hash->shared->total_items-1 ; i >= 0 ; i--)
if (GET_ITEM(items,hash->bytes_per_item,i).key == DELETED_ENTRY)
GET_ITEM(items,hash->bytes_per_item,i).key = FREE_ENTRY;
hash->shared->deleted_items=0;
}
static void collect_garbge(HASH_CONTAINER *hash)
{
HASH_SHARED *shared= hash->shared;
HASH_ITEM *temp_items;
int size;
size= shared->total_items * hash->bytes_per_item;
temp_items= (HASH_ITEM*)malloc(size);
if (temp_items==NULL) {
static_collect_garbge(hash);
} else {
memcpy(temp_items, hash->items, size);
copy_hash_items(hash, temp_items, shared->total_items);
}
}
static void copy_hash_items(HASH_CONTAINER *hash, HASH_ITEM *old_items,
int old_n_items)
{
HASH_SHARED *shared= hash->shared;
HASH_ITEM *item;
int i;
shared->deleted_items = 0;
shared->free_items= shared->total_items;
/* make all items free */
for (i= shared->total_items-1 ; i>=0 ; i--)
GET_ITEM(hash->items, hash->bytes_per_item, i).key = FREE_ENTRY;
/* copy items */
for (i=0 ; i <= old_n_items; i++) {
item= &GET_ITEM(old_items, hash->bytes_per_item,i);
if (item->key != FREE_ENTRY && item->key != DELETED_ENTRY)
hash_add_item(hash, item->key, &item->data);
}
}
static void reorder_hash(HASH_CONTAINER *hash)
{
HASH_SHARED *shared= hash->shared;
HASH_ITEM *items, *old_items;
HASH_PTR shared_items, old_shared_items;
int n_items, old_n_items;
int size;
if (shared->deleted_items > hash->min_free_items) {
collect_garbge(hash);
return;
}
n_items= best_prime(shared->total_items * HASH_REALLOC_JUMPS);
size= n_items *
(sizeof(items[0]) - sizeof(items[0].data) + hash->bytes_per_item);
shared_items= hash->allocate_mem(size);
items= hash->access_mem(shared_items);
if (items == NULL) {
collect_garbge(hash);
return;
}
old_shared_items = shared->items;
old_n_items= shared->total_items;
old_items= hash->items;
/* setup a new clean hash based on the parameters of the original one */
hash->items= items;
shared->total_items = n_items;
shared->items= shared_items;
set_hash_parameters(hash, hash->maximum_load);
copy_hash_items(hash, old_items, old_n_items);
hash->free_mem(old_shared_items);
hash->last_ptr_update= ++shared->ptr_updates;
}
/* low level: attach hash existing hash items, no checks are performed
* No complex calculations done.
*/
static HASH_CONTAINER *attach_no_check(HASH_ITEM *items, int bytes_per_datum)
{
HASH_CONTAINER *hash;
int bytes_per_item;
HASH_ITEM dummy_item;
hash= (HASH_CONTAINER*) malloc(sizeof(HASH_CONTAINER) );
if (hash == NULL)
return NULL;
bytes_per_item= bytes_per_datum+
sizeof(dummy_item)-sizeof(dummy_item.data);
hash->bytes_per_item= ROUND_UP4(bytes_per_item);
hash->items= items;
hash->is_correct_item= NULL;
hash->allocate_mem= HASH_MEM_ALLOC;
hash->access_mem= HASH_MEM_ACCESS;
hash->free_mem= HASH_MEM_FREE;
set_hash_parameters(hash, HASH_LOAD);
return hash;
}
/* Attach existing & running remote (i.e. shared) hash.
* Attach the items using the data stored in "shared"
*/
HASH_CONTAINER *attach_remote_hash(HASH_SHARED *shared, int bytes_per_datum,
HASH_ITEM *(*access_mem)(HASH_PTR))
{
HASH_CONTAINER *hash;
HASH_ITEM *items;
assert(access_mem != NULL);
if (! arrays_initialized)
setup_arrays();
items=access_mem(shared->items);
hash= attach_no_check(items, bytes_per_datum);
if (hash == NULL)
return NULL;
hash->shared_was_malloced = FALSE;
hash->shared= shared;
return (hash);
}
HASH_CONTAINER *create_remote_hash(HASH_SHARED *shared,
int bytes_per_datum,
int total_items,
HASH_PTR (*allocate_mem)(int size),
HASH_ITEM *(*access_mem)(HASH_PTR))
{
HASH_CONTAINER *hash;
int size;
int i;
assert(total_items >= 1);
assert(bytes_per_datum >=1);
assert(access_mem != NULL);
assert(allocate_mem != NULL);
assert(shared != NULL);
if (! arrays_initialized)
setup_arrays();
if (total_items < MIN_HASH)
total_items= MIN_HASH;
else
total_items= best_prime(total_items);
hash= attach_no_check(NULL, bytes_per_datum);
if (hash==NULL) {
free(hash);
return NULL;
}
shared->total_items= total_items;
hash->shared= shared;
hash->shared_was_malloced = FALSE;
size= total_items * hash->bytes_per_item;
shared->items = allocate_mem(size);
hash->items= access_mem(shared->items);
if (hash->items == NULL ) {
free(hash);
return NULL;
}
shared->items.ptr= hash->items;
/* make all items free */
for (i=0 ; i < total_items ; i++)
GET_ITEM(hash->items,hash->bytes_per_item,i).key = FREE_ENTRY;
shared->deleted_items= 0;
shared->free_items= total_items;
shared->ptr_updates= 0;
return hash;
}
/* hash constructor: create brand new hash */
HASH_CONTAINER *create_hash(int bytes_per_datum, int total_items)
{
HASH_CONTAINER *hash;
HASH_SHARED *shared;
shared= (HASH_SHARED*)malloc(sizeof(HASH_SHARED));
if (shared == NULL)
return NULL;
hash= create_remote_hash(shared, bytes_per_datum, total_items,
HASH_MEM_ALLOC, HASH_MEM_ACCESS);
if (hash == NULL) {
free(shared);
return NULL;
}
hash->shared_was_malloced = TRUE;
return hash;
}
/* set the extra handlers to non default values */
void set_hash_handlers(HASH_CONTAINER *hash,
HASH_ITEM_TEST *is_correct_item,
HASH_PTR (*allocate_mem)(int size),
void (*free_mem)(HASH_PTR),
HASH_ITEM *(*access_mem)(HASH_PTR))
{
assert(hash);
assert(allocate_mem);
assert(free_mem);
hash->free_mem = free_mem;
hash->allocate_mem = allocate_mem;
hash->access_mem = access_mem;
hash->is_correct_item = is_correct_item;
}
/* set extra parameters */
void set_hash_parameters(HASH_CONTAINER *hash, int load)
{
assert(hash);
assert(load>30); /* no sence to realloc with less than */
/* 50% load, limiting to 30% to be on */
/* the safe size */
assert(load<=100);
hash->maximum_load= load;
hash->min_free_items= (1.0 - load/100.0) * hash->shared->total_items + 1 ;
}
/* hash destructor: destroy anything related to the hash */
void destroy_hash(HASH_CONTAINER *hash)
{
assert(hash);
hash->free_mem(hash->shared->items);
if (hash->shared_was_malloced)
free(hash->shared);
free(hash);
}
/* hash destructor: just detach hash, without destroing it (makes */
/* sence in shared memory environment) */
void detach_hash(HASH_CONTAINER *hash)
{
assert(hash);
free(hash);
}
/********** Hash usage *************/
static inline BOOL
correct_entry(HASH_ITEM *item, int key, HASH_VAL *seeked_data,
HASH_ITEM_TEST *is_correct_item, BOOL skip_deleted)
{
switch(item->key) {
case FREE_ENTRY:
return TRUE;
case DELETED_ENTRY:
return skip_deleted ? FALSE : TRUE;
default:
if (item->key != key)
return FALSE;
if (is_correct_item != NULL)
return is_correct_item(&item->data, seeked_data);
else
return TRUE;
}
}
/* The algorithm of the hash (one of the 2 standard hash implementations):
* Iterate through the hash table until
* 1. The entry has been found.
* 2. A FREE entry has been found.
* 3. For insert operations only- A DELETED entry has been found.
* The difference between DELETED and FREE entires is that
* DELETED entry was one occupied, while FREE was never allocated.
* The idea behind this structure to keep other entries reachable.
*/
static HASH_ITEM *locate_entry(HASH_CONTAINER* hash, DWORD key,
HASH_VAL *seeked_data, BOOL skip_deleted)
{
DWORD hash_idx, hash_leaps;
HASH_ITEM *item;
int i;
int total_items;
assert(hash);
total_items= hash->shared->total_items;
hash_idx= key % total_items;
item= &GET_ITEM(hash->items, hash->bytes_per_item, hash_idx);
if ( correct_entry( item, key, seeked_data,
hash->is_correct_item, skip_deleted) )
return item;
/* get the WORDs in different order in this DWORD to avoid clustering */
hash_leaps=((DWORD)MAKELONG(HIWORD(key), LOWORD(key))
% (total_items-1)) +1;
/* interate through the hash table using hash_leaps */
for (i= total_items ; i ; i--) {
hash_idx+= hash_leaps;
if (hash_idx > total_items)
hash_idx -= total_items;
item= &GET_ITEM(hash->items,hash->bytes_per_item, hash_idx);
if ( correct_entry( item, key, seeked_data,
hash->is_correct_item, skip_deleted) )
return item;
}
return NULL;
}
static inline void sync_shared_hash(HASH_CONTAINER *hash)
{
HASH_SHARED *shared= hash->shared;
if (shared->ptr_updates == hash->last_ptr_update)
return;
assert(shared->ptr_updates >= hash->last_ptr_update);
hash->last_ptr_update= shared->ptr_updates;
hash->min_free_items= (1.0 - hash->maximum_load/100.0) *
shared->total_items + 1 ;
hash->items= hash->access_mem(shared->items);
}
HASH_VAL *hash_locate_item(HASH_CONTAINER* hash,
int key, HASH_VAL *seeked_data)
{
HASH_ITEM *item;
assert(hash != NULL);
sync_shared_hash(hash);
item= locate_entry(hash, key, seeked_data, 1 /* skip_deleted */);
if (item == NULL)
return NULL;
if (item->key == FREE_ENTRY )
return NULL;
return &item->data;
}
BOOL hash_add_item(HASH_CONTAINER* hash, int key, HASH_VAL *data)
{
HASH_SHARED *shared;
HASH_ITEM *item;
assert(hash != NULL);
sync_shared_hash(hash);
shared= hash->shared;
item=locate_entry(hash, key, data, 0 /* no skip_deleted */);
assert(item != NULL);
if (item->key == key)
return FALSE;
if (item->key == FREE_ENTRY)
shared->free_items--;
else
shared->deleted_items--;
item->key= key;
memcpy(&item->data, data, hash->bytes_per_item-sizeof(key));
if (shared->free_items < hash->min_free_items ||
shared->deleted_items > hash->min_free_items)
reorder_hash(hash);
return TRUE;
}
BOOL hash_delete_item(HASH_CONTAINER* hash, int key, HASH_VAL *seeked_data)
{
HASH_ITEM *item;
assert(hash != NULL);
sync_shared_hash(hash);
item=locate_entry(hash, key, seeked_data, 1 /* skip_deleted */);
if (item == NULL)
return FALSE;
if (item->key == FREE_ENTRY)
return FALSE;
item->key = DELETED_ENTRY;
hash->shared->deleted_items++;
return TRUE;
}
void *ret_null()
{
return NULL;
}
HASH_ITEM *access_local_hash(HASH_PTR ptr)
{
return ptr.ptr;
}
#endif /* CONFIG_IPC */

View File

@ -1,142 +0,0 @@
/***************************************************************************
* Copyright 1995 Michael Veksler. mveksler@vnet.ibm.com
***************************************************************************
* File: generic_hash.h
* Purpose : dynamically growing hash, may use shared or local memory.
***************************************************************************
*/
#ifndef _GENERIC_HASH_H_
#define _GENERIC_HASH_H_
#include "windef.h"
#include "shm_block.h"
#include "win.h"
/* default hash values */
#define HASH_LOAD 70
#define HASH_MEM_ALLOC (HASH_PTR (*)(int size)) malloc
#define HASH_MEM_FREE (void (*)(HASH_PTR)) free
#define HASH_MEM_ACCESS access_local_hash
#define HASH_REALLOC_JUMPS 1.5 /* Relative size of the new memory */
#define MIN_HASH 13
typedef union {
char string[1];
WORD words[1];
DWORD dwords[1];
char *ptr;
SEGPTR segptr;
} HASH_VAL;
typedef struct hash_item_struct {
DWORD key;
HASH_VAL data;
} HASH_ITEM;
/* point to the hash structure */
typedef union {
HASH_ITEM* ptr; /* Local pointer */
REL_PTR rel; /* IPC relative address */
SEGPTR segptr; /* Universal (can be IPC or local) */
} HASH_PTR;
typedef struct hash_share_struct {
int total_items; /* total number of items (array size) */
int free_items; /* number of free items (excluding deleted) */
int deleted_items; /* number of deleted items */
int ptr_updates; /* Number of updates to `items' pointer */
/* (of items) - used for intecepting */
/* changes to the pointer. */
HASH_PTR items; /* pointer to the items */
} HASH_SHARED;
typedef BOOL HASH_ITEM_TEST(HASH_VAL *value, HASH_VAL *seeked_data);
/* NOTE:
* 1. Keys 0 and -1 are reserved.
* 2. none of these items should be accessed directly, use existing
* functions. If they are not enough, add a new function.
*/
typedef struct hash_container_struct {
int bytes_per_item;
int maximum_load; /* in percents (0..100) default is 70 */
int min_free_items; /* minimum free items before reallocating
(Function of maximum_load) */
int last_ptr_update; /* to be compared with shared.ptr_updates */
BOOL shared_was_malloced; /* Need that to know how to destroy hash */
/* This is an optional handler.
* If not NULL, this function is used for distinguishing between
* different data with the same key (key field holds integer and
* is too short for long keys like strings).
*/
HASH_ITEM_TEST *is_correct_item;
/* Handlers used for reallocating memory
* [by allocating new data and then freeing old data]
*/
HASH_PTR (*allocate_mem)(int size);
void (*free_mem)(HASH_PTR);
/* Translator from HASH_PTR construct to a regular pointer.
use HASH_MEM_ACCESS, if no translation is needed */
HASH_ITEM *(*access_mem)(HASH_PTR);
HASH_ITEM *items;
HASH_SHARED *shared; /* Things to be on shared memory. */
} HASH_CONTAINER;
/********** Hash maintenance functions ***********/
/* Attach existing & running remote (i.e. shared) hash.
* Attach the items using the data stored in "shared"
*/
HASH_CONTAINER *attach_remote_hash(HASH_SHARED *shared, int bytes_per_datum,
HASH_ITEM *(*access_mem)(HASH_PTR));
HASH_CONTAINER *create_remote_hash(HASH_SHARED *shared,
int bytes_per_datum,
int total_items,
HASH_PTR (*allocate_mem)(int size),
HASH_ITEM *(*access_mem)(HASH_PTR));
/* hash constructor: create brand new hash (not on shared memory) */
HASH_CONTAINER *create_hash(int bytes_per_datum, int total_items);
/* set the extra handlers to non default values */
void set_hash_handlers(HASH_CONTAINER *hash,
HASH_ITEM_TEST *is_correct_item,
HASH_PTR (*allocate_mem)(int size),
void (*free_mem)(HASH_PTR),
HASH_ITEM *(*access_mem)(HASH_PTR));
/* set extra parameters */
void set_hash_parameters(HASH_CONTAINER *hash, int load);
/* hash destructors */
void destroy_hash(HASH_CONTAINER *hash);
void detach_hash(HASH_CONTAINER *hash);
/********** Hash usage *************/
/* All following functions have the same format:
* hash- the hash structure to use
* key- used as primary means to get to the entry.
* data- 1. a secondary key (used only if `is_correct_item' is set).
* 2. data to store. (for hash_add_item).
*/
HASH_VAL *hash_locate_item(HASH_CONTAINER* hash,int key, HASH_VAL* seeked_data);
BOOL hash_add_item(HASH_CONTAINER* hash, int key, HASH_VAL* data);
BOOL hash_delete_item(HASH_CONTAINER* hash, int key, HASH_VAL* seeked_data);
void *ret_null(); /* function returning null (used for */
/* disabling memory reallocation) */
/* access function used by local (non IPC) memory */
HASH_ITEM *access_local_hash(HASH_PTR ptr);
#endif /* _GENERIC_HASH_H_ */

View File

@ -1,117 +0,0 @@
/***************************************************************************
* Copyright 1995 Michael Veksler. mveksler@vnet.ibm.com
***************************************************************************
* File: hash_test.c
* Purpose : test generic_hash correctness.
* NOTE:
* This code covers only about 80% of generic_hash code.
* There might be bugs in the remaining 20% - although most
* of the functionality is tested with wine linckage.
* For complete testing a little more work should be done.
***************************************************************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "generic_hash.h"
#define SIZE 200
typedef struct { int a,b;} DATA ;
DATA data[SIZE];
int keys[SIZE];
int peeks=0;
HASH_CONTAINER *hash1;
HASH_CONTAINER *hash2; /* actual data is shared with hash1 */
/* test insertion using keys[] and data[] inserting using hash1 and */
/* hash2 periodically, test hash after every 2 insertions */
void test_insert()
{
int i,j;
HASH_VAL *item;
printf("testing insertion \n");
for (i=0 ; i < SIZE-1 ; i+=2) {
assert(hash_add_item(hash1, keys[i], (HASH_VAL *)&data[i]));
assert(hash_add_item(hash2, keys[i+1], (HASH_VAL *)&data[i+1]));
for (j=0 ; j <= i+1 ; j++) {
item= hash_locate_item(hash1, keys[j], (HASH_VAL *)&data[j]);
if (item == NULL) {
printf("NULL item: i=%d,j=%d\n",i,j);
continue;
}
peeks++;
if (memcmp(item,&data[j],sizeof(DATA))!=0) {
printf("i=%d,j=%d\n",i,j);
printf("saved=(%d,%d), orig=(%d,%d)\n",
((DATA*)item)->a, ((DATA*)item)->b,
data[j].a, data[j].b);
}
}
}
}
/* test deletion using keys[] and data[] deleting using hash1 and */
/* hash2 periodicly, test hash after every 2 deletions */
void test_delete()
{
int i,j;
HASH_VAL *item;
printf("testing deletion\n");
for (i=0 ; i < SIZE-1 ; i+=2) {
assert(hash_delete_item(hash2, keys[i], NULL));
assert(hash_delete_item(hash1, keys[i+1], NULL));
for (j=0 ; j < SIZE ; j++) {
item= hash_locate_item(hash2, keys[j], (HASH_VAL *)&data[j]);
if (item == NULL) {
if ( j > i+1)
printf("NULL item: i=%d,j=%d\n",i,j);
continue;
}
if (item != NULL && j <= i+1) {
printf("Non NULL item: i=%d,j=%d\n",i,j);
continue;
}
if (memcmp(item,&data[j],sizeof(DATA))!=0) {
printf("i=%d,j=%d\n",i,j);
printf("saved=(%d,%d), orig=(%d,%d)\n",
((DATA*)item)->a, ((DATA*)item)->b,
data[j].a, data[j].b);
}
}
}
}
int main()
{
int i;
hash1= create_hash(sizeof(DATA), 1);
assert(hash1);
hash2= attach_remote_hash(hash1->shared, sizeof(DATA), HASH_MEM_ACCESS);
assert(hash2);
for (i=0 ; i< SIZE ; i++) {
data[i].a= rand();
data[i].b= rand();
keys[i]= rand();
}
test_insert();
detach_hash(hash1);
free(hash1);
hash1= attach_remote_hash(hash2->shared, sizeof(DATA), HASH_MEM_ACCESS);
test_delete();
test_insert();
detach_hash(hash1);
destroy_hash(hash2);
printf("peeks=%d\n", peeks);
return 0;
}

View File

@ -1,49 +0,0 @@
#!/bin/sh
bit_array_test
bit_array=$?
dde_mem_test
mem=$?
hash_test
hash=$?
shm_semaph_test
semaph=$?
dde_atom_test
atom=$?
dde_proc_test 1 > proc_server &
sleep 1
dde_proc_test > proc_client
fgrep "DDE:receive sent message. msg=03e0 wPar=fffb lPar=00000004" proc_server &&
fgrep "DDE_GetRemoteMessage: sending ACK to wnd=fffb, proc=1" proc_server &&
fgrep "get_ack: received DDE_ACK message" proc_client
proc=$?
rm proc_client proc_server
shm_fragment_test | diff TEST_FRAGMENT.std -
fragment=$?
echo ====================================================================
echo Test results:
echo -n "bit_array "
if [ $bit_array -eq 0 ] ; then echo OK ; else echo "** ERROR **" ; fi
echo -n "dde_mem "
if [ $mem -eq 0 ] ; then echo OK ; else echo "** ERROR **" ; fi
echo -n "hash "
if [ $hash -eq 0 ] ; then echo OK ; else echo "** ERROR **" ; fi
echo -n "shm_semaph "
if [ $semaph -eq 0 ] ; then echo OK ; else echo "** ERROR **" ; fi
echo -n "dde_proc "
if [ $proc -eq 0 ] ; then echo OK ; else echo "** ERROR **" ; fi
echo -n "shm_fragment "
if [ $fragment -eq 0 ] ; then echo OK ; else echo "** ERROR **" ; fi

View File

@ -1,194 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: shm_block.c
* Purpose: Treat a shared memory block.
***************************************************************************
*/
#ifdef CONFIG_IPC
#include <sys/types.h>
#include <sys/sem.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include "debugtools.h"
#include "global.h"
#include "selectors.h"
#include "shm_fragment.h"
#include "shm_block.h"
#include "shm_semaph.h"
#include "dde_proc.h"
#include "xmalloc.h"
DEFAULT_DEBUG_CHANNEL(shm)
/* How each shmid is maped to local pointer */
/* Only attached shm blocks are in this construct */
struct local_shm_map *shm_map=NULL;
/* setup a new shm block (construct a shm block object).
* block: The pointer to the memory block (local mapping)
* first: The first data byte (excluding header stuff),
* if 0 (zero) Use the default.
* size: The size of the memory block.
*/
void shm_setup_block(struct shm_block *block, int first, int size)
{
TRACE("Setting up shm block at 0x%08x\n",(int )block);
/* setup block internal data structure */
if (first <= 0) {
first=sizeof(*block);
/* round up - so everything starts on cache line boundary
* (assume cache line=32 bytes, may be bigger/smaller for
* different processors and different L2 caches .)
*/
first=(first+0x1f) & ~0x1f;
}
block->free=size-first;
block->next_shm_id=-1; /* IPC shm ID (for initial linking) */
block->proc_idx= curr_proc_idx;
/* block->size is initialized in shm_FragmentInit */
shm_FragmentInit(block, first, size); /* first item in the free list */
TRACE("block was set up at 0x%08x, size=0x%04xKB, 1st usable=%02x\n",
(int )block,size/1024,first);
}
/* shm_attach_block: attach existing shm block, setup selectors
* shm_id - id of the block to attach.
* proc_idx - if not -1, puts this data into local mapping
* map - localy mapped info about this block.
*/
/* NOTE: there is no check if this block is already attached.
* Attaching the same block more than once - is possible
* In case of doubt use shm_locate_block.
*/
struct shm_block *shm_attach_block(int shm_id, int proc_idx,
struct local_shm_map *map)
{
struct shm_block *block;
struct shmid_ds ds;
struct local_shm_map *this;
shmctl(shm_id, IPC_STAT, &ds );
block=(struct shm_block*)shmat(shm_id, NULL, 0);
if (block==NULL || block == (struct shm_block*) -1) return NULL;
this=(struct local_shm_map *)xmalloc(sizeof(*this));
this->next= shm_map;
shm_map = this;
this->shm_id= shm_id;
this->ptr = block;
if (proc_idx < 0)
this->proc_idx=block->proc_idx;
else
this->proc_idx=proc_idx;
if (map != NULL) {
memcpy(map, this, sizeof(map));
map->next= NULL; /* don't pass private info */
}
return block;
}
struct shm_block *shm_create_block(int first, int size, int *shm_id)
{
struct shm_block *block;
if (size==0)
size=SHM_MINBLOCK;
else
/* round up size to a multiple of SHM_MINBLOCK */
size= (size+SHM_MINBLOCK-1) & ~(SHM_MINBLOCK-1);
*shm_id= shmget ( IPC_PRIVATE, size ,0700);
if (*shm_id==-1)
return NULL;
block=shm_attach_block(*shm_id, curr_proc_idx, NULL);
if (block!=NULL)
shm_setup_block(block, first, size);
return block;
}
/*
** Locate attached block. (return it, or NULL on failure)
** shm_id is the block we look for.
** *map - will get all the info related to this local map + proc_idx
** (may be NULL)
** *seg - will get the segment this block is attached to.
*/
struct shm_block *shm_locate_attached_block(int shm_id,
struct local_shm_map *map)
{
struct local_shm_map *curr;
for (curr= shm_map ; curr != NULL ; curr= curr->next) {
if (curr->shm_id == shm_id) {
if (map) {
memcpy(map, curr, sizeof(*curr) );
map->next = NULL; /* this is private info ! */
}
return curr->ptr;
}
}
/* block not found ! */
return 0;
}
/* shm_locate_block: see shm_attach_block.
In addition to shm_attach_block, make sure this
block is not already attached.
*/
struct shm_block *shm_locate_block(int shm_id, struct local_shm_map *map)
{
struct shm_block *ret;
ret= shm_locate_attached_block(shm_id, map);
if (ret!=NULL)
return ret;
/* block not found ! , try to attach */
return shm_attach_block(shm_id, -1, map);
}
static void forget_attached(int shmid)
{
struct local_shm_map *curr, **point_to_curr;
for (curr= shm_map, point_to_curr= &shm_map ;
curr != NULL ;
curr= curr->next, point_to_curr= &curr->next ) {
if (curr->shm_id == shmid) {
*point_to_curr= curr->next;
return;
}
}
}
/* delete chain of shm blocks (pointing to each other)
* Do it in reverse order. (This is what the recursion is for)
*/
void shm_delete_chain(int *shmid)
{
struct shm_block *block;
if (*shmid == -1)
return;
block= shm_locate_block(*shmid, NULL);
forget_attached( *shmid );
if (block == NULL)
return;
shm_delete_chain(&block->next_shm_id);
shmctl(*shmid, IPC_RMID, NULL);
*shmid=-1;
shmdt((char *)block);
}
#endif /* CONFIG_IPC */

View File

@ -1,181 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: shm_fragment.c
* Purpose: Data fragments and free list items. Allocate and free blocks.
***************************************************************************
*/
#ifdef CONFIG_IPC
#include <stdio.h> /* for debugging only */
#include "debugtools.h" /* for "stddeb" */
#include "shm_fragment.h"
#include "shm_block.h"
/******************************************************************************
*
* Free list: all fragments are ordered according to memory location.
* new fragments are inserted in this way.
*
******************************************************************************
*/
#define FRAG_PTR(block,ofs) ((struct shm_fragment *) ((char *) block + ofs) )
#define NEXT_FRAG(block,ofs) ( FRAG_PTR(block,ofs)->info.next )
/* setup first item in the free list */
void shm_FragmentInit(struct shm_block *block,int first, int size)
{
struct shm_fragment *fragment;
/* round up to nearest 16 byte boundary */
first=(first+15)& ~15;
block->free_list=first;
/* make all the block (exluding the header) free */
fragment= FRAG_PTR(block, first);
block->free= fragment->size= size-first;
fragment->info.next=0;
}
void shm_FragPtrFree(struct shm_block *block, void *ptr)
{
/* ptr points to fragment->info.data, find pointer to fragment,
* find the offset of this pointer in block.
*/
if (ptr)
shm_FragmentFree(block, PTR2REL(block, ptr));
}
void shm_FragmentFree(struct shm_block *block, int fragment_ofs)
{
struct shm_fragment *fragment=NULL;
int prev;
int next;
fragment_ofs-=(int )&fragment->info.data;
fragment= FRAG_PTR(block, fragment_ofs);
block->free+=fragment->size;
/* scan free list to find candidates for merging with fragment */
for (prev=0, next=block->free_list;
(next!=0) && (fragment_ofs > next) ;
prev=next, next=NEXT_FRAG(block,next) )
;
/* insert fragment between, prev and next
* prev==0: fragment will be the first item in free list
* next==0: fragment will be the last item in free list
*/
/* update fragment (point to next, or merge with next) */
if ( fragment_ofs+fragment->size == next ) {
/* merge with the next free block */
fragment->size+= FRAG_PTR(block,next)->size;
fragment->info.next=FRAG_PTR(block,next)->info.next;
} else
/* fragment should be inserted before the next fragment or end of */
/* list. (not merged) */
fragment->info.next=next;
/* now fragment has all the information about the rest of the list */
/* upate prev fragment (point or merge with fragment) */
if (prev==0) /* first item in free list */
block->free_list=fragment_ofs;
else if ( prev+FRAG_PTR(block,prev)->size == fragment_ofs ) {
/* merge fragment with previous fragment */
FRAG_PTR(block,prev)->size+= fragment->size;
FRAG_PTR(block,prev)->info.next=fragment->info.next;
} else
/* insert fragment after previous fragment */
FRAG_PTR(block,prev)->info.next=fragment_ofs;
}
/* use "first fit" algorithm,
* return: offset to data in fragment.
*/
int shm_FragmentAlloc(struct shm_block *block, int size)
{
int prev;
int candidate;
struct shm_fragment *fragment;
struct shm_fragment *ret_fragment;
if (size <= 0)
return NIL;
/* add size of "fragment->size" */
size+= (char *)&fragment->info.data - (char *)fragment ;
/* round "size" to nearest 16 byte value */
size= (size+15) & ~15;
if (size > block->free)
return NIL;
/* scan free list to find candidates for allocation */
for (prev=0, candidate=block->free_list;
candidate!=0 ;
prev=candidate, candidate= fragment->info.next )
{
fragment=FRAG_PTR(block,candidate);
if (fragment->size >= size)
break;
}
if (candidate == 0)
return NIL;
block->free-=size;
if (fragment->size == size) {
if (prev == 0)
block->free_list= fragment->info.next;
else
FRAG_PTR(block,prev)->info.next= fragment->info.next;
return PTR2REL(block, &fragment->info.data);
}
/* fragment->size > size */
/* Split fragment in two, return one part, put the other in free list. */
/* The part that starts at the old location - will stay in the free list. */
fragment->size -= size;
ret_fragment=FRAG_PTR(block, candidate + fragment->size);
ret_fragment->size= size;
return PTR2REL(block, ret_fragment->info.data);
}
/* like shm_FragmentAlloc, returns pointer instead of offset */
char *shm_FragPtrAlloc(struct shm_block *block, int size)
{
int ofs;
ofs= shm_FragmentAlloc(block,size);
if (ofs == NIL)
return NULL;
else
return (char *) REL2PTR(block, ofs);
}
/* This is used for debugging only */
void shm_print_free_list(struct shm_block *block)
{
struct shm_fragment *fragment;
int item;
item=block->free_list;
if (item==0) {
DUMP("no free fragments");
} else {
for (; item ; item=fragment->info.next) {
fragment=FRAG_PTR(block,item);
DUMP("{0x%04x,0x%04x} ",item,fragment->size);
}
}
DUMP(" [total free=%04x]\n",block->free);
fflush(stddeb);
}
#endif /* CONFIG_IPC */

View File

@ -1,99 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: shm_fragment_test.c
* Purpose: Test data fragments and free list items. Allocate and free blocks.
***************************************************************************
*/
#include <assert.h>
#include <stdio.h>
#define DEBUG_DEFINE_VARIABLES /* just avoid dumb errors */
#include "debugtools.h" /* for "stddeb" */
#include <stdlib.h>
#include <string.h>
#include "shm_block.h"
#include "shm_fragment.h"
#include "xmalloc.h"
#define DO_FREE(id) (-id)
#define LIST_LENGTH 20
int main()
{
struct shm_block *block;
char *ret;
int size;
int i;
/* important: The test will work only for the current implementation of */
/* allocation, if the implementation will change, the list should also */
/* cahnge. */
static int sizes[LIST_LENGTH]={
SHM_MINBLOCK, /* 0: should fail */
0x3fe0-4, /* 1: */
0x4000-4, /* 2: */
0x4000-4, /* 3: */
0x4000-4+1, /* 4: should fail */
0x4000-4, /* 5: */
/* allocated(5,3,2,1) free() */
-5, /* 6: */
0x1c00-4, /* 7: */
0x1400-4, /* 8: */
0x1000-4, /* 9: */
/* allocated(9,8,7,3,2,1) free() */
-9, /* 10: */
-3, /* 11: */
-1, /* 12: */
/* allocated(8,7,2) free(9,3,1) */
0x1000-4, /* 13: */
-13, /* 14: */
0x1000+1-4, /* 15: */
/* allocated(8,7,15,2) free(9,[3-15],1) */
-2, /* 16: */
/* allocated(8,7,15) free(9,[3-15],1+2) */
-8, /* 17: */
-7, /* 18: */
-15 /* 19: */
};
static char *ptr[LIST_LENGTH];
block=xmalloc(SHM_MINBLOCK);
/* setup first item in the free list */
shm_FragmentInit(block, sizeof(*block), SHM_MINBLOCK);
fprintf(stddeb,"After shm_FragmentInit\n");
shm_print_free_list(block);
for(i=0 ; i < LIST_LENGTH; i++) {
size=sizes[i];
if (size>0) { /* allocate */
ret=shm_FragPtrAlloc(block, size);
ptr[i]=ret;
fprintf(stddeb,
"%d: After shm_FragmentAlloc(block, 0x%06x) == ",
i, size);
if (ret==NULL)
fprintf(stddeb, "NULL\n");
else {
fprintf(stddeb, "0x%06x\n", (int)ret-(int)block);
memset( ret,0, size ); /* test boundaries */
}
} else { /* free */
/* free shm fragment */
ret=ptr[-sizes[i]];
fprintf(stddeb, "%d: Doing shm_FragmentFree(block, ", i);
if (ret==NULL)
fprintf(stddeb, "NULL)\n");
else
fprintf(stddeb, "0x%06x)\n", (int)ret-(int)block);
fflush(stddeb);
shm_FragPtrFree(block, ret);
}
shm_print_free_list(block);
}
return 0;
}

View File

@ -1,271 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: shm_main_blk.c
* Purpose: Main Wine's shared memory block
***************************************************************************
*/
#ifdef CONFIG_IPC
#include <sys/types.h>
#include <sys/sem.h>
#include <time.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include "debugtools.h"
#include "shm_fragment.h"
#include "shm_block.h"
#include "shm_main_blk.h"
#include "shm_semaph.h"
DEFAULT_DEBUG_CHANNEL(shm)
#define WineKey ( 'W'+((int)'i'<<8)+((int)'n'<<16)+((int)'e'<<24) )
#define SHM_KEY_RANGE 8
/* main block (set during initialization) */
struct shm_main_block *main_block=NULL;
static char *shm_header="Wine - Windows emulator DDE mechanism";
static int main_shm_id;
static void shm_main_refresh();
/* for debugging only */
static void print_perm(struct ipc_perm *perm)
{
printf("Permission:\n");
/* FIXME: not portable
printf("\tKey=%d, mode=%03o, sequence #=%d\n",
(int)perm->key,perm->mode, perm->seq);
*/
printf("\towner: uid=%d, gid=%d ;" ,perm->uid, perm->gid);
printf(" creator: uid=%d, gid=%d\n",perm->cuid,perm->cgid);
}
/* for debugging only */
/* print_shm_info: print shared memory descriptor info */
static void print_shm_info(int shm_id)
{
struct shmid_ds ds;
shmctl(shm_id, IPC_STAT, &ds );
printf("shm_id=%d, Size=0x%08x , Number of attaches=%d\n",
shm_id, ds.shm_segsz, (int)ds.shm_nattch);
if (ds.shm_atime)
printf("Last attach=%s",ctime(&ds.shm_atime));
if (ds.shm_dtime)
printf("Last detach=%s",ctime(&ds.shm_dtime));
printf("Last change=%s",ctime(&ds.shm_ctime));
printf("pid: creator=%d, last operator=%d\n",
(int)ds.shm_cpid,(int)ds.shm_lpid);
print_perm( &ds.shm_perm);
}
int proc_exist(pid_t pid)
{
if ( kill(pid,0) == 0) /* dummy signal to test existence */
return 1;
else if (errno==ESRCH) /* "no such process" */
return 0;
else
return 1;
}
/* setup a new main shm block (only construct a shm block object). */
static void shm_setup_main_block()
{
TRACE("creating data structure\n");
main_block->build_lock=1;
strcpy(main_block->magic, shm_header);
shm_setup_block(&main_block->block,sizeof(*main_block),SHM_MINBLOCK);
dde_proc_init(main_block->proc);
ATOM_GlobalInit();
shm_sem_init(&main_block->sem);
/* main block set and data structure is stable now */
main_block->build_lock=0;
}
/* Delete everything related to main_block */
void shm_delete_all(int shmid)
{
int proc_idx;
if (shmid == -1)
shmid= main_shm_id;
shmctl( shmid, IPC_RMID, NULL);
for (proc_idx= 0 ; proc_idx < DDE_PROCS ; proc_idx++)
dde_proc_done( &main_block->proc[proc_idx] );
shm_sem_done(&main_block->sem);
shmdt( (void *) main_block);
main_block= NULL;
}
int DDE_no_of_attached()
{
struct shmid_ds shm_info;
if (shmctl(main_shm_id, IPC_STAT, &shm_info) == -1)
return -1;
return shm_info.shm_nattch;
}
/*
** Test if shm_id is MainBlock and attach it (if it is),
** Return 1 if ok, 0 otherwise.
*/
static int attach_MainBlock(int shm_id)
{
struct shmid_ds shm_info;
if (shmctl(shm_id, IPC_STAT, &shm_info) == -1)
return 0;
/* Make sure we don't work on somebody else's block */
if (shm_info.shm_perm.cuid != getuid()) { /* creator is not me */
WARN("Creator is not me!\n");
return 0;
}
TRACE("shared memory exist, attaching anywhere\n");
main_block=(struct shm_main_block *)shmat(shm_id, 0, 0);
if ( (int)main_block==-1) {
WARN("Attach failed\n");
return 0;
}
if (strcmp(main_block->magic, shm_header) != 0) {
TRACE("Detaching, wrong magic\n");
shmdt((void *)main_block);
return 0;
}
if (TRACE_ON(shm))
print_shm_info(shm_id);
/* Is it an old unused block ? */
if (shm_info.shm_nattch == 0) {
TRACE("No attaches, deleting old data\n");
shm_delete_all(shm_id);
return 0;
}
/* Wait for data structure to stabilize */
while (main_block->build_lock)
usleep(10000);
main_shm_id= shm_id;
shm_main_refresh();
return 1;
}
/* (Function used by the constructor)
* Try to get existing shared memory with key="Wine", size=SHM_MINBLOCK
* complete user permission.
* If such block is found - return true (1), else return false (0)
*/
static int shm_locate_MainBlock(key_t shm_key)
{
int shm_id; /* Descriptor to this shared memory */
int i;
TRACE("trying to attach, key=0x%x\n",
shm_key);
for (i=0 ; i < SHM_KEY_RANGE ; i++) {
TRACE("iteration=%d\n", i);
shm_id= shmget ( shm_key+i, SHM_MINBLOCK ,0700);
if (shm_id != -1) {
if ( attach_MainBlock(shm_id) ) {
return 1; /* success! */
}
} else {
switch(errno) {
#ifdef EIDRM
case EIDRM: /* segment destroyed */
#endif
case EACCES: /* no user permision */
break;
case ENOMEM: /* no free memory */
case ENOENT: /* this key does not exist */
default :
WARN("shmget failed, errno=%d, %s\n",
errno, strerror(errno) );
return 0; /* Failed */
}
} /* if .. else */
} /* for */
return 0;
}
/* (Function used by the constructor)
* Try to allocate new shared memory with key="Wine", size=SHM_MINBLOCK
* with complete user permission.
* If allocation succeeds - return true (1), else return false (0)
*/
static int shm_create_MainBlock(key_t MainShmKey)
{
int shm_id;
int flags= 0700 | IPC_CREAT | IPC_EXCL;
int i;
TRACE("creating shared memory\n");
/* try to allocate shared memory with key="Wine", size=SHM_MINBLOCK, */
/* complete user permission */
for (i=0 ; i < SHM_KEY_RANGE ; i++) {
shm_id= shmget ( (key_t) MainShmKey, SHM_MINBLOCK, flags);
if (shm_id != -1)
break;
}
if (shm_id == -1) {
WARN("failed to create shared memory\n");
return 0;
}
TRACE("shared memory created, attaching\n");
main_block=(struct shm_main_block*) shmat(shm_id, 0,0);
if (TRACE_ON(shm))
print_shm_info(shm_id);
main_shm_id= shm_id;
shm_setup_main_block();
dde_wnd_setup();
return 1;
}
/* link to the dde shared memory block */
/* RETURN: 0 on success, non zero on failure */
int shm_init(void)
{
if ( !shm_locate_MainBlock(WineKey)
&& !shm_create_MainBlock(WineKey)) {
ERR("Failed to init main shm block\n");
exit(1);
}
dde_proc_add(main_block->proc);
return 0;
}
static void shm_main_refresh()
{
int proc_idx;
for (proc_idx= 0 ; proc_idx < DDE_PROCS ; proc_idx++)
dde_proc_refresh( &main_block->proc[proc_idx] );
}
#endif /* CONFIG_IPC */

View File

@ -1,139 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: shm_semaph.c
* Purpose: Handle semaphores for shared memory operations.
***************************************************************************
*/
#ifdef CONFIG_IPC
#include <assert.h>
#include <unistd.h>
#include <sys/sem.h>
#include <errno.h>
#include "debugtools.h"
#include "shm_semaph.h"
DEFAULT_DEBUG_CHANNEL(sem)
#define SEM_READ 0
#define SEM_WRITE 1
/* IMPORTANT: Make sure that killed process will not lock everything.
* If possible, restrict usage of these functions.
*/
void shm_read_wait(shm_sem semid)
{
struct sembuf sop[2];
int ret;
TRACE("(%d)\n",semid);
sop[0].sem_num=SEM_READ;
sop[0].sem_op=1; /* add this read instance */
sop[0].sem_flg=SEM_UNDO; /* undo in case process dies */
sop[1].sem_num=SEM_WRITE;
sop[1].sem_op=0; /* wait until no writing instance exists */
sop[1].sem_flg=SEM_UNDO;
do {
ret=semop (semid,sop , 2);
} while (ret<0 && errno==EINTR); /* interrupted system call? */
if (ret<0)
WARN("(semid=%d,errno=%d): Failed semaphore lock for read\n",
semid, errno);
}
void shm_write_wait(shm_sem semid)
{
struct sembuf sop[3];
int ret;
TRACE("(%d)\n",semid);
sop[0].sem_num=SEM_READ;
sop[0].sem_op=0; /* wait until no reading instance exist */
sop[0].sem_flg=SEM_UNDO;
sop[1].sem_num=SEM_WRITE;
sop[1].sem_op=1; /* writing is in progress - disable read */
sop[1].sem_flg=SEM_UNDO; /* undo if process dies */
sop[2].sem_num=SEM_READ;
sop[2].sem_op=1; /* disable new writes */
sop[2].sem_flg=SEM_UNDO;
do {
ret=semop (semid,sop , 3);
} while (ret<0 && errno==EINTR); /* interrupted system call? */
if (ret<0) /* test for the error */
WARN("(semid=%d,errno=%d): Failed semaphore lock for write\n",
semid, errno);
}
void shm_write_signal(shm_sem semid)
{
struct sembuf sop[2];
int ret;
TRACE("(%d)\n",semid);
sop[0].sem_num=SEM_READ;
sop[0].sem_op=-1;
sop[0].sem_flg=IPC_NOWAIT | SEM_UNDO; /* no reason to wait */
sop[1].sem_num=SEM_WRITE;
sop[1].sem_op=-1;
sop[1].sem_flg=IPC_NOWAIT | SEM_UNDO; /* no reason to wait */
do {
ret=semop (semid,sop , 2);
} while (ret<0 && errno==EINTR); /* interrupted system call? */
if (ret<0) /* test for the error */
WARN("(semid=%d,errno=%d): Failed semaphore unlock for write\n",
semid, errno);
}
void shm_read_signal(shm_sem semid)
{
struct sembuf sop[2];
int ret;
TRACE("(%d)\n",semid);
sop[0].sem_num=SEM_READ;
sop[0].sem_op=-1;
sop[0].sem_flg=IPC_NOWAIT | SEM_UNDO; /* no reason to wait */
do {
ret=semop (semid,sop , 1);
} while (ret<0 && errno==EINTR); /* interrupted system call? */
if (ret<0) /* test for the error */
WARN("(semid=%d,errno=%d): Failed semaphore unlock for read\n",
semid, errno);
}
void shm_sem_init(shm_sem *sptr)
{
shm_sem semid;
union semun arg;
semid=semget (IPC_PRIVATE, 2, 0700 | IPC_CREAT);
arg.val=0;
semctl (semid, 0, SETVAL, arg);
semctl (semid, 1, SETVAL, arg);
*sptr=semid;
}
void shm_sem_done(shm_sem *semptr)
{
union semun arg;
semctl (*semptr, 0, IPC_RMID , arg);
semctl (*semptr, 1, IPC_RMID , arg);
*semptr= -1;
}
#endif /* CONFIG_IPC */

View File

@ -1,127 +0,0 @@
/***************************************************************************
* Copyright 1995, Technion, Israel Institute of Technology
* Electrical Eng, Software Lab.
* Author: Michael Veksler.
***************************************************************************
* File: shm_semaph_test.c
* Purpose: Test semaphores handleingr shared memory operations.
***************************************************************************
*/
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/wait.h>
#include "shm_semaph.h"
#include <sys/shm.h>
#define DEBUG_DEFINE_VARIABLES
#include "debugtools.h"
static volatile int * volatile data;
static int isparent=0;
#define DELAY (rand()%10)
shm_sem sem;
static void read_write(int num)
{
int i,j ;
volatile float dummy=0;
int val;
srand(num+time(NULL));
for (i=0x3fff;i>=0;i--) {
if((i&0x7ff)==0 && isparent)
fprintf(stderr,"0x%06x\r",i);
shm_write_wait(sem);
*data= num;
for (j=DELAY ; j>=0;j--)
dummy*=2;
if (*data!=num) {
fprintf(stderr,"\nbad shm_write_wait(), num=%d\n",num);
shm_write_signal(sem);
return;
}
shm_write_signal(sem);
for (j=DELAY ; j>=0 ;j--)
dummy*=2;
shm_read_wait(sem);
val=*data;
for (j=DELAY; j>=0 ;j--)
dummy*=0.5;
if (*data!=val) {
fprintf(stderr,"\nbad shm_read_wait(), num=%d,val=%d,*data=%d\n",
num,val,*data);
shm_read_signal(sem);
return;
}
shm_read_signal(sem);
}
if (isparent)
fputc('\n',stderr);
}
static void child1()
{
read_write(2);
}
static void child2()
{
read_write(10);
}
static void parent()
{
isparent=1;
read_write(60);
}
int main()
{
int shmid;
int ret1, ret2;
int pid1, pid2;
int stat=0;
shm_sem_init(&sem);
shmid=shmget(IPC_PRIVATE, 0x100, IPC_CREAT | 0700);
data= (int *)shmat ( shmid, NULL, 0);
*data=0;
switch (pid1=fork()) {
case -1:
perror("fork 1");
return 1;
case 0:
fprintf(stderr,"child1\n");
child1();
fprintf(stderr,"child1 done\n");
return 0;
default :
}
switch (pid2=fork()) {
case -1:
perror("fork 2");
stat|=1;
break;
case 0:
fprintf(stderr,"child2\n");
child2();
fprintf(stderr,"child2 done\n");
return 0;
default :
}
fprintf(stderr,"parent\n");
if (pid2>0) { /* if second fork did not fail */
parent();
fprintf(stderr,"parent done, waiting for child2\n");
waitpid(pid2,&ret2,WUNTRACED);
stat|=ret2;
}
fprintf(stderr,"parent done, waiting for child1\n");
waitpid(pid1,&ret1,WUNTRACED);
stat|=ret1;
fprintf(stderr,"all done\n");
shmctl(shmid, IPC_RMID,NULL);
shm_sem_done(&sem);
return stat;
}

View File

@ -1,116 +0,0 @@
#include <stdlib.h>
#include "dde.h"
#include "windef.h"
#include "global.h"
#include <win.h>
#define DEBUG_DEFINE_VARIABLES
#define DEBUG_ALL
#include "debugtools.h"
#define DDE_PROC2WIN(proc_idx) ( (HWND) ~( (proc_idx)+1) )
#define DDE_WIN2PROC(win) ( (int) ~(short) ((win)+1) )
#define DDE_IsRemoteWindow(win) ( (win)<0xffff && (win)>=(0xffff-DDE_PROCS))
char *MessageTypeNames[0x400]={NULL};
char *dummy_store_for_debug_msg_name;
ldt_copy_entry ldt_copy[LDT_SIZE];
int LDT_GetEntry( int entry, ldt_entry *content )
{
return 0;
}
int LDT_SetEntry( int entry, ldt_entry const *content )
{
return 0;
}
void dummy_usage_of_debug_msg_name()
{
dummy_store_for_debug_msg_name=debug_msg_name[0];
}
/* stub */
HWND GetDesktopWindow()
{
printf("GetDesktopWindow\n");
return 0;
}
/* stub */
/* smart stub */
LONG SendMessage(HWND a,WORD b,WORD c,LONG d)
{
MSG msg;
printf("SendMessage(%04x,%04x,%04x,%04lx)\n",a,b,c,d);
if (DDE_IsRemoteWindow(a) || a==(HWND)-1)
return 0;
if (b!=WM_DDE_INITIATE)
return 0;
msg.hwnd=c;
msg.message= WM_DDE_ACK;
msg.lParam= 0;
msg.wParam= 0;
return DDE_SendMessage(&msg);
}
/* stub */
BOOL PostMessage(HWND a,WORD b,WORD c,LONG d)
{
printf("PostMessage(%04x,%04x,%04x,%04lx)\n",a,b,c,d);
return 0;
}
/* stub */
HWND GetTopWindow(HWND a)
{
printf("GetTopWindow(%04x)\n",a);
return 1;
}
/* stub */
WORD FreeSelector16(WORD a)
{
printf("FreeSelector(%04x)\n",a);
return 0;
}
/* stub that partially emulates the true GLOBAL_CreateBlock function */
HGLOBAL16 GLOBAL_CreateBlock( WORD flags, void *ptr, DWORD size,
HGLOBAL16 hOwner, BOOL isCode,
BOOL is32Bit, BOOL isReadOnly,
SHMDATA *shmdata )
{
printf("GLOBAL_CreateBlock(flags=0x%x,ptr=0x%08lx, size=0x%x,hOwner=0x%x\n",
(int)flags, (long)ptr, (int)size, (int)hOwner);
printf("isCode=%d, is32Bit=%d, isReadOnly=%d, \n", isCode, is32Bit,
isReadOnly);
printf("*shmdata={handle=0x%x,sel=0x%x, shmid=%d})\n",
shmdata->handle, shmdata->sel, shmdata->shmid);
return 1;
}
/* stub */
WND *WIN_FindWndPtr(HWND hwnd)
{
static WND win;
printf("WIN_FindWndPtr(%d)\n",hwnd);
if (hwnd==0)
return NULL;
win.next=NULL;
win.dwStyle=WS_POPUP;
return &win;
}
/* stub */
WORD GetCurrentPDB16(void)
{
printf("GetCurrentPDB()\n");
return 0;
}
/* stub */
void Yield(void)
{
}

View File

@ -187,10 +187,6 @@ BOOL SIGNAL_Init(void)
sigemptyset(&async_signal_set);
SIGNAL_SetHandler( SIGCHLD, (void (*)())SIGNAL_child, 1);
#ifdef CONFIG_IPC
sigaddset(&async_signal_set, SIGUSR2);
SIGNAL_SetHandler( SIGUSR2, (void (*)())stop_wait, 1); /* For IPC */
#endif
#ifdef SIGIO
sigaddset(&async_signal_set, SIGIO);
/* SIGNAL_SetHandler( SIGIO, (void (*)())WINSOCK_sigio, 0); */

View File

@ -35,7 +35,6 @@
#include "syslevel.h"
#include "debugtools.h"
#include "dosexe.h"
#include "dde_proc.h"
#include "services.h"
#include "server.h"

View File

@ -26,10 +26,6 @@
#include "user.h"
#include "debugtools.h"
#ifdef CONFIG_IPC
#include "dde_atom.h"
#endif
DEFAULT_DEBUG_CHANNEL(atom)
#define DEFAULT_ATOMTABLE_SIZE 37
@ -545,11 +541,7 @@ UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
ATOM WINAPI GlobalAddAtom16( SEGPTR str )
{
if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
#ifdef CONFIG_IPC
return DDE_GlobalAddAtom( str );
#else
return ATOM_AddAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
#endif
}
@ -595,11 +587,7 @@ ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
ATOM WINAPI GlobalDeleteAtom(
ATOM atom /* [in] Atom to delete */
) {
#ifdef CONFIG_IPC
return DDE_GlobalDeleteAtom( atom );
#else
return ATOM_DeleteAtom( ATOM_GlobalTable, atom );
#endif
}
@ -609,11 +597,7 @@ ATOM WINAPI GlobalDeleteAtom(
ATOM WINAPI GlobalFindAtom16( SEGPTR str )
{
if (!HIWORD(str)) return (ATOM)LOWORD(str); /* Integer atom */
#ifdef CONFIG_IPC
return DDE_GlobalFindAtom( str );
#else
return ATOM_FindAtom( ATOM_GlobalTable, (LPCSTR)PTR_SEG_TO_LIN(str) );
#endif
}
@ -652,11 +636,7 @@ ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
*/
UINT16 WINAPI GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
{
#ifdef CONFIG_IPC
return DDE_GlobalGetAtomName( atom, buffer, count );
#else
return (UINT16)ATOM_GetAtomName( ATOM_GlobalTable, atom, buffer, count );
#endif
}

View File

@ -16,7 +16,6 @@
#include "toolhelp.h"
#include "selectors.h"
#include "miscemu.h"
#include "dde_mem.h"
#include "stackframe.h"
#include "module.h"
#include "debugtools.h"
@ -35,9 +34,6 @@ typedef struct
BYTE pageLockCount; /* Count of GlobalPageLock() calls */
BYTE flags; /* Allocation flags */
BYTE selCount; /* Number of selectors allocated for this block */
#ifdef CONFIG_IPC
int shmid;
#endif
} GLOBALARENA;
/* Flags definitions */
@ -124,22 +120,7 @@ HGLOBAL16 GLOBAL_CreateBlock( WORD flags, const void *ptr, DWORD size,
pArena->base = (DWORD)ptr;
pArena->size = GET_SEL_LIMIT(sel) + 1;
#ifdef CONFIG_IPC
if (flags & GMEM_DDESHARE)
{
pArena->handle = shmdata->handle;
pArena->shmid = shmdata->shmid;
shmdata->sel = sel;
}
else
{
pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
pArena->shmid = 0;
}
#else
pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
#endif
pArena->hOwner = hOwner;
pArena->lockCount = 0;
pArena->pageLockCount = 0;
@ -225,16 +206,8 @@ HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner,
if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
size = (size + 0x1f) & ~0x1f;
/* Allocate the linear memory */
#ifdef CONFIG_IPC
if (flags & GMEM_DDESHARE)
ptr = DDE_malloc(flags, size, &shmdata);
else
#endif /* CONFIG_IPC */
{
ptr = HeapAlloc( SystemHeap, 0, size );
}
/* Allocate the linear memory */
ptr = HeapAlloc( SystemHeap, 0, size );
/* FIXME: free discardable blocks and try again? */
if (!ptr) return 0;
@ -252,50 +225,6 @@ HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner,
return handle;
}
#ifdef CONFIG_IPC
/***********************************************************************
* GLOBAL_FindArena
*
* Find the arena for a given handle
* (when handle is not serial - e.g. DDE)
*/
static GLOBALARENA *GLOBAL_FindArena( HGLOBAL16 handle)
{
int i;
for (i = globalArenaSize-1 ; i>=0 ; i--) {
if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == handle)
return ( &pGlobalArena[i] );
}
return NULL;
}
/***********************************************************************
* DDE_GlobalHandleToSel
*/
WORD DDE_GlobalHandleToSel( HGLOBAL16 handle )
{
GLOBALARENA *pArena;
SEGPTR segptr;
pArena= GLOBAL_FindArena(handle);
if (pArena) {
int ArenaIdx = pArena - pGlobalArena;
/* See if synchronized to the shared memory */
return DDE_SyncHandle(handle, ( ArenaIdx << __AHSHIFT) | 7);
}
/* attach the block */
DDE_AttachHandle(handle, &segptr);
return SELECTOROF( segptr );
}
#endif /* CONFIG_IPC */
/***********************************************************************
* GlobalAlloc16 (KERNEL.15)
* RETURNS
@ -335,14 +264,6 @@ HGLOBAL16 WINAPI GlobalReAlloc16(
handle, size, flags );
if (!handle) return 0;
#ifdef CONFIG_IPC
if (flags & GMEM_DDESHARE || is_dde_handle(handle))
{
FIXME("shared memory reallocating unimplemented\n");
return 0;
}
#endif /* CONFIG_IPC */
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x!\n", handle);
return 0;
@ -456,9 +377,6 @@ HGLOBAL16 WINAPI GlobalFree16(
TRACE("%04x\n", handle );
if (!GLOBAL_FreeBlock( handle )) return handle; /* failed */
#ifdef CONFIG_IPC
if (is_dde_handle(handle)) return DDE_GlobalFree(handle);
#endif /* CONFIG_IPC */
if (ptr) HeapFree( SystemHeap, 0, ptr );
return 0;
}
@ -477,11 +395,6 @@ SEGPTR WINAPI WIN16_GlobalLock16( HGLOBAL16 handle )
{
if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
#ifdef CONFIG_IPC
if (is_dde_handle(handle))
return PTR_SEG_OFF_TO_SEGPTR( DDE_GlobalHandleToSel(handle), 0 );
#endif /* CONFIG_IPC */
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to WIN16_GlobalLock16!\n",handle);
return (SEGPTR)0;
@ -511,9 +424,6 @@ LPVOID WINAPI GlobalLock16(
if (!VALID_HANDLE(handle))
return (LPVOID)0;
GET_ARENA_PTR(handle)->lockCount++;
#ifdef CONFIG_IPC
if (is_dde_handle(handle)) return DDE_AttachHandle(handle, NULL);
#endif
return (LPVOID)GET_ARENA_PTR(handle)->base;
}
@ -893,9 +803,6 @@ HANDLE16 WINAPI FarGetOwner16( HGLOBAL16 handle )
WORD WINAPI GlobalHandleToSel16( HGLOBAL16 handle )
{
if (!handle) return 0;
#ifdef CONFIG_IPC
if (is_dde_handle(handle)) return DDE_GlobalHandleToSel(handle);
#endif
if (!VALID_HANDLE(handle)) {
WARN("Invalid handle 0x%04x passed to GlobalHandleToSel!\n",handle);
return 0;

View File

@ -15,7 +15,6 @@
#include "ddeml.h"
#include "winerror.h"
#include "heap.h"
#include "shm_semaph.h"
#include "debugtools.h"
#include "tchar.h"
#include "winnt.h"

View File

@ -988,11 +988,6 @@ static BOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, DWORD first, DWORD last,
POINT16 pt16;
int iWndsLocks;
#ifdef CONFIG_IPC
DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
DDE_GetRemoteMessage();
#endif /* CONFIG_IPC */
mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
if (first || last)
{
@ -1458,11 +1453,6 @@ BOOL WINAPI PostMessageA( HWND hwnd, UINT message, WPARAM wParam,
msg.pt.x = 0;
msg.pt.y = 0;
#ifdef CONFIG_IPC
if (DDE_PostMessage(&msg))
return TRUE;
#endif /* CONFIG_IPC */
if (hwnd == HWND_BROADCAST)
{
WND *pDesktop = WIN_GetDesktop();
@ -1672,13 +1662,7 @@ LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
LPARAM lParam)
{
LRESULT res;
#ifdef CONFIG_IPC
MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
if (DDE_SendMessage(&DDE_msg)) return TRUE;
#endif /* CONFIG_IPC */
MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, 0, &res);
return res;
}

View File

@ -21,8 +21,6 @@
#include "nonclient.h"
#include "queue.h"
#include "winpos.h"
#include "shm_main_blk.h"
#include "dde_proc.h"
#include "clipboard.h"
#include "winproc.h"
#include "task.h"
@ -440,11 +438,6 @@ static WND* WIN_DestroyWindow( WND* wndPtr )
TRACE_(win)("%04x\n", wndPtr->hwndSelf );
#ifdef CONFIG_IPC
if (main_block)
DDE_DestroyWindow(wndPtr->hwndSelf);
#endif /* CONFIG_IPC */
/* free child windows */
WIN_LockWndPtr(wndPtr->child);
while ((pWnd = wndPtr->child))

View File

@ -19,7 +19,6 @@
#include "callback.h"
#include "clipboard.h"
#include "dce.h"
#include "dde_proc.h"
#include "debugtools.h"
#include "drive.h"
#include "heap.h"