|  | /*************************************************************************** | 
|  | * 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 <stdio.h> | 
|  | #include <stddebug.h> | 
|  | #include <debug.h> | 
|  | #include <assert.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" | 
|  |  | 
|  | #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(HGLOBAL h, struct local_shm_map *map) | 
|  | { | 
|  | struct shm_block *block; | 
|  |  | 
|  | dprintf_global(stddeb,"shm:locate_handle(0x%04x)\n", h); | 
|  |  | 
|  |  | 
|  | if (SampleBit( &free_handles, DDE_MEM_IDX(h)) == 0) { | 
|  | dprintf_global(stddeb, "shm:locate_handle: return NULL\n"); | 
|  | return NULL;		   /* free!!! */ | 
|  | } | 
|  |  | 
|  | block= shm_locate_block(DDE_MEM_INFO(h).shmid, map); | 
|  | if (block == NULL) { | 
|  | /* nothing found */ | 
|  | dprintf_global(stddeb, "shm:locate_handle: return NULL\n"); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return (struct handle_info *) REL2PTR(block, DDE_MEM_INFO(h).rel); | 
|  |  | 
|  | } | 
|  |  | 
|  | /* dde_alloc_handle: allocate shared DDE handle */ | 
|  | static HGLOBAL dde_alloc_handle() | 
|  | { | 
|  | int bit_nr; | 
|  |  | 
|  | bit_nr= AllocateBit( &free_handles); | 
|  |  | 
|  | if (bit_nr != -1) | 
|  | return DDE_MEM_HANDLE(bit_nr); | 
|  |  | 
|  | dprintf_global(stddeb,"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; | 
|  | HGLOBAL handle; | 
|  |  | 
|  | dprintf_global(stddeb,"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) { | 
|  | fprintf(stderr,"DDE_malloc: 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) { | 
|  | dprintf_global(stddeb, | 
|  | "DDE_malloc 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 | 
|  | dprintf_global(stddeb,"DDE_malloc failed\n"); | 
|  |  | 
|  | shm_write_signal(main_block->proc[curr_proc_idx].sem); | 
|  |  | 
|  | shmdata->handle= handle; | 
|  | return (char *)HINFO2DATAPTR(h_info); | 
|  | } | 
|  |  | 
|  | HGLOBAL DDE_GlobalFree(HGLOBAL h) | 
|  | { | 
|  | struct handle_info *h_info; | 
|  | int handle_index= h & 0x7fff; | 
|  | struct local_shm_map map; | 
|  |  | 
|  | dprintf_global(stddeb,"DDE_GlobalFree(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(HGLOBAL 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(HGLOBAL handle, SEGPTR *segptr) | 
|  | { | 
|  | struct handle_info *h_info; | 
|  | SHMDATA shmdata; | 
|  | void *ptr; | 
|  | HGLOBAL hOwner = GetCurrentPDB(); | 
|  |  | 
|  | assert(is_dde_handle(handle)); | 
|  | if (segptr != NULL) | 
|  | *segptr=0; | 
|  |  | 
|  | dprintf_global(stddeb,"DDE_AttachHandle(%04x)\n",handle); | 
|  | h_info=locate_handle(handle, NULL); | 
|  |  | 
|  | if (h_info == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if ( !(h_info->flags & GMEM_DDESHARE) ) { | 
|  | fprintf(stderr,"DDE_AttachHandle: Corrupted memory handle info\n"); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | dprintf_global(stddeb,"DDE_AttachHandle: 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 (debugging_dde) | 
|  | debug_last_handle_size= h_info->size; | 
|  |  | 
|  | dprintf_global(stddeb,"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 */ |