| /*************************************************************************** | |
| * 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 "debug.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(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 = GetCurrentPDB(); | |
| 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 */ |