/*{ ** Name: DI_inc_Di_slave_cnt - Autoincrements an element in the ** Di_slave_cnt structure; ** ** Description: ** ** Inputs: ** Number Index into Di_slave_cnt array ** ** Outputs: ** intern_status Internal error indicating reason for failure. ** ** Returns: ** OK ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 30-nov-1992 (rmuth) ** Created. ** */ STATUS DI_inc_Di_slave_cnt( i4 number, STATUS *intern_status) { STATUS status; do { status = gen_Psem(&DI_sc_sem); if ( status != OK ) { *intern_status = DI_LRU_GENPSEM_ERR; break; } ++Di_slave_cnt[ number ]; status = gen_Vsem(&DI_sc_sem); if ( status != OK ) { Di_fatal_err_occurred = TRUE; *intern_status = DI_LRU_GENVSEM_ERR; break; } } while (FALSE); return( status ); }
/****************************************************************************** ** Name: MEsmdestroy() - Destroy a shared memory segment ** ** Description: ** Remove the shared memory segment specified by shared memory identifier ** "key" from the system and destroy any system data structure associated ** with it. ** ** Note: The shared memory pages are not necessarily removed from ** processes which have the segment mapped. It is up to the clients to ** detach the segment via MEfree_pages prior to destroying it. ** ** Protection Note: The caller of this routine must have protection to ** destroy the shared memory segment. Protections are enforced by the ** underlying Operating System. In general, this routine can only be ** guaranteed to work when executed by a user running with the same ** effective privledges as the user who created the shared memory segment. ** ** Inputs: ** user_key identifier which was previosly ** used in a successful MEget_pages() call ** (not necessarily a call in this process) ** ** Outputs: ** err_code System specific error information. ** ** Returns: ** OK ** ME_NO_PERM No permission to destroy shared memory ** segment. ** ME_NO_SUCH_SEGMENT indicated shared memory segment does not ** exist. ** ME_NO_SHARED No shared memory in this CL. ** ME_BAD_ADVICE call was made during ME_USER_ALLOC ** ** Exceptions: ** none ** ** Side Effects: ** none ** ******************************************************************************/ STATUS MEsmdestroy(char *user_key, CL_ERR_DESC *err_code) { LOCATION location; LOCATION temp_loc; char loc_buf[MAX_LOC + 1]; STATUS ret_val = OK; CLEAR_ERR(err_code); /* * Get location of ME files for shared memory segments. */ # ifdef MCT gen_Psem(&NM_loc_sem); # endif /* MCT */ ret_val = NMloc(FILES, PATH, (char *) NULL, &temp_loc); if (!ret_val) { LOcopy(&temp_loc, loc_buf, &location); LOfaddpath(&location, ME_SHMEM_DIR, &location); LOfstfile(user_key, &location); if (LOexist(&location) != OK) ret_val = FAIL; else { ret_val = LOdelete(&location); switch (ret_val) { case OK: case ME_NO_PERM: break;; default: ret_val = ME_NO_SUCH_SEGMENT; break;; } } } # ifdef MCT gen_Vsem(&NM_loc_sem); # endif /* MCT */ return (ret_val); }
/****************************************************************************** ** Name: ** MEtfree.c ** ** Function: ** MEtfree ** ** Arguments: ** i2 tag; ** ** Result: ** Free all blocks of memory on allocated list with ** MEtag value of 'tag'. ** ** Returns STATUS: OK, ME_00_PTR, ME_OUT_OF_RANGE, ME_BD_TAG, ** ME_FREE_FIRST, ME_TR_TFREE, ME_NO_TFREE. ** ** Side Effects: ** None ** History: ** 03-jun-1996 (canor01) ** Internally, store the tag as an i4 instead of an i2. This makes ** for more efficient code on byte-aligned platforms that do fixups. ** 27-may-97 (mcgem01) ** Clean up compiler warnings. ** ******************************************************************************/ STATUS MEtfree(u_i2 tag) { STATUS status; if (tag == 0) return ME_ILLEGAL_USAGE; # ifdef MCT gen_Psem(&ME_stream_sem); # endif /* MCT */ status = IIME_ftFreeTag((i4)tag); # ifdef MCT gen_Vsem(&ME_stream_sem); # endif /* MCT */ return (status); }
/*{ ** Name: DI_dec_Di_slave_cnt - Autodecrement an element in the ** Di_slave_cnt structure; ** ** Description: ** ** Inputs: ** Number Index into Di_slave_cnt array ** ** Outputs: ** intern_status Internal error indicating reason for failure. ** ** Returns: ** OK ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 30-nov-1992 (rmuth) ** Created. ** */ STATUS DI_dec_Di_slave_cnt( i4 number, STATUS *intern_status) { STATUS status; do { status = gen_Psem(&DI_sc_sem); if ( status != OK ) { /* ** This is very bad as we may have corrupted our internal ** DIlru/DIslave structures. But this event can occur ** due to a thread being aborted */ --Di_slave_cnt[ number ]; *intern_status = DI_LRU_GENPSEM_ERR; break; } --Di_slave_cnt[ number ]; status = gen_Vsem(&DI_sc_sem); if ( status != OK ) { Di_fatal_err_occurred = TRUE; *intern_status = DI_LRU_GENVSEM_ERR; break; } } while (FALSE); return( status ); }
/****************************************************************************** ** Name: MEshow_pages() - show system's allocated shared memory segments. ** ** Description: ** This routine is used by clients of the shared memory allocation ** routines to show what shared memory segments are currently allocated ** by the system. ** ** The routine takes a function parameter - 'func' - that will be ** called once for each existing shared memory segment allocated ** by Ingres in the current installation. ** ** The client specified function must have the following call format: **( ** STATUS ** func(arg_list, key, err_code) ** i4 *arg_list; Pointer to argument list. ** char *key; Shared segment key. ** CL_SYS_ERR *err_code; Pointer to operating system ** error codes (if applicable). **) ** ** The following return values from the routine 'func' have special ** meaning to MEshow_pages: ** ** OK (zero) - If zero is returned from 'func' then MEshow_pages ** will continue normally, calling 'func' with the ** next shared memory segment. ** ENDFILE - If ENDFILE is returned from 'func' then MEshow_pages ** will stop processing and return OK to the caller. ** ** If 'func' returns any other value, MEshow_pages will stop processing ** and return that STATUS value to its caller. Additionally, the system ** specific 'err_code' value returned by 'func' will be returned to the ** MEshow_pages caller. ** ** Inputs: ** func Function to call with each shared segment. ** arg_list Optional pointer to argument list to pass ** to function. ** ** Outputs: ** err_code System specific error information. ** ** Returns: ** OK ** ME_NO_PERM No permission to show shared memory segment. ** ME_BAD_PARAM Bad function argument. ** ME_NO_SHARED No shared memory in this CL. ** ** Exceptions: ** none ** ** Side Effects: ** none ** ******************************************************************************/ STATUS //MEshow_pages(STATUS (*func) (PTR, const char *, CL_SYS_ERR *), MEshow_pages(STATUS (*func) (), PTR *arg_list, CL_SYS_ERR *err_code) { LOCATION locptr; LO_DIR_CONTEXT lo_dir; STATUS status; char fname[LO_FILENAME_MAX + 1]; char dev[LO_DEVNAME_MAX + 1]; char path[LO_PATH_MAX + 1]; char fprefix[LO_FPREFIX_MAX + 1]; char fsuffix[LO_FSUFFIX_MAX + 1]; char version[LO_FVERSION_MAX + 1]; /* * Get location ptr to directory to search for memory segment names. */ # ifdef MCT gen_Psem(&NM_loc_sem); # endif /* MCT */ if ((status = NMloc(FILES, PATH, (char *) NULL, &locptr)) == OK) { LOfaddpath(&locptr, ME_SHMEM_DIR, &locptr); } else { # ifdef MCT gen_Vsem(&NM_loc_sem); # endif /* MCT */ return (status); } # ifdef MCT gen_Vsem(&NM_loc_sem); # endif /* MCT */ /* * For each file in the memory location, call the user supplied * function with the filename. Shared memory keys are built from * these filenames. */ status = LOwcard(&locptr, (char *) NULL, (char *) NULL, (char *) NULL, &lo_dir); if (status != OK) { LOwend(&lo_dir); return (ME_NO_SHARED); } while (status == OK) { LOdetail(&locptr, dev, path, fprefix, fsuffix, version); (VOID) STpolycat(3, fprefix, ".", fsuffix, fname); if (~lo_dir.find_buffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { status = (*func) (arg_list, fname, err_code); if (status != OK) { break; } } status = LOwnext(&lo_dir, &locptr); } LOwend(&lo_dir); if (status == ENDFILE) { return (OK); } return (status); }
/***************************************************************************** ** Name: ME_makekey() - Make WIN32 file for mapping ** shared memory from user key. ** ** Description: ** Create a file to identify a shared memory segment. The file's inode ** will be used as a shared memory key. The file's existence will be ** used to track shared segments on the system. ** ** Inputs: ** key character key identifying shared segment. ** ** Outputs: ** return value ** ** Returns: ** HANDLE to opened file, or ** -1 file could not be created. ** ** Exceptions: ** none ** ** Side Effects: ** File created in installation's memory directory. ** *****************************************************************************/ HANDLE ME_makekey(char *user_key) { LOCATION location; LOCATION temp_loc; char loc_buf[MAX_LOC + 1]; char *shmemname; STATUS ret_val; HANDLE handle; /* * Build location to file in MEMORY directory. Get location of ME * files for shared memory segments. */ # ifdef MCT gen_Psem(&NM_loc_sem); # endif /* MCT */ ret_val = NMloc(FILES, PATH, (char *) NULL, &temp_loc); if (ret_val) { # ifdef MCT gen_Vsem(&NM_loc_sem); # endif /* MCT */ return (HANDLE) -1; } LOcopy(&temp_loc, loc_buf, &location); # ifdef MCT gen_Vsem(&NM_loc_sem); # endif /* MCT */ LOfaddpath(&location, ME_SHMEM_DIR, &location); LOfstfile(user_key, &location); /* * Create file to identify the shared segment. This will also allow * MEshow_pages to tell what shared segments have been created. */ LOtos(&location, &shmemname); handle = CreateFile(shmemname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (handle == INVALID_HANDLE_VALUE) { handle = (HANDLE) -1; } return (handle); }
/***************************************************************************** ** Name: MEshared_free() - Free shared memory ** ** Description: ** Free a region of shared memory and return new region for potential ** futher freeing of the break region. ** ** If there is attached shared memory in the region being ** freed then those pages should only be marked free if the whole ** segment can be detached. ** ** There is a small table of attached segments which is scanned. ** ** Inputs: ** addr address of region ** pages number of pages to check ** ** Outputs: ** addr new address of region ** pages new number of pages ** err_code CL_ERR_DESC ** ** Returns: ** OK ** ME_NOT_ALLOCATED ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 07-apr-1997 (canor01) ** When the shared memory is attached to existing memory ** the file handle will be null, so don't try to close it. ** 10-apr-1997 (canor01) ** If the address of the memory to be freed does not fall ** within the shared memory range, return ME_NOT_ALLOCATED. ** *****************************************************************************/ STATUS MEshared_free(PTR *addr, SIZE_TYPE *pages, CL_ERR_DESC *err_code) { STATUS status = OK; register ME_SEG_INFO *seginf; char *lower, *upper, *last; SIZE_TYPE off, len; QUEUE *next_queue; CLEAR_ERR(err_code); lower = (char *) *addr; upper = lower + ME_MPAGESIZE * *pages; last = NULL; gen_Psem(&ME_segpool_sem); seginf = ME_find_seg(lower, upper, &ME_segpool); if ( seginf == NULL ) { /* memory address was not within shared memory range */ gen_Vsem(&ME_segpool_sem); return( ME_NOT_ALLOCATED ); } for ( ; seginf; seginf = ME_find_seg(lower, upper, next_queue)) { next_queue = &seginf->q; if (last && last != seginf->eaddr) { status = ME_NOT_ALLOCATED; break; } last = seginf->addr; off = 0; len = seginf->npages; if (lower > seginf->addr) { off = (lower - seginf->addr) / ME_MPAGESIZE; len -= off; } if (upper < seginf->eaddr) { len -= (seginf->eaddr - upper) / ME_MPAGESIZE; } if (MEalloctst(seginf->allocvec, (i4)off, (i4)len, TRUE)) { status = ME_NOT_ALLOCATED; break; } MEclearpg(seginf->allocvec, (i4)off, (i4)len); if (!MEalloctst(seginf->allocvec, 0, seginf->npages, FALSE)) { /* detach segment */ /* * WARNING::: if the address is NOT the BASE of a * shared memory segment obtained from MapViewOfFile, * we're either gonna fail or puke. Good luck! */ status = UnmapViewOfFile(seginf->addr); if (status == FALSE) { status = GetLastError(); SETCLOS2ERR(err_code, status, ER_mmap); gen_Vsem(&ME_segpool_sem); return (ME_BAD_PARAM); } status = CloseHandle(seginf->mem_handle); if (status == FALSE) { status = GetLastError(); SETCLOS2ERR(err_code, status, ER_close); gen_Vsem(&ME_segpool_sem); return (ME_BAD_PARAM); } /* ** if just attaching to existing memory, ** there will just be a memory handle, but ** the file_handle will be NULL. */ if ( seginf->file_handle ) { FlushFileBuffers(seginf->file_handle); status = CloseHandle(seginf->file_handle); } if (status == FALSE) { status = GetLastError(); SETCLOS2ERR(err_code, status, ER_close); gen_Vsem(&ME_segpool_sem); return (ME_BAD_PARAM); } else { status = OK; } next_queue = ME_rem_seg(seginf); *addr = (PTR) NULL; } } gen_Vsem(&ME_segpool_sem); return status; }
/*{ ** Name: TMget_stamp - Return timestamp. ** ** Description: ** Return a TM timestamp. ** Note, this routine is for the sole use of DMF for ** auditing and rollforward. ** ** Inputs: ** ** Outputs: ** time Pointer to location to return stamp. ** Returns: ** void ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 20-jan-1986 (Derek) ** Created. ** 06-jul-1987 (mmm) ** Initial Jupiter unix cl. ** 28-jul-1988 (daveb) ** Can't call input parameter "time" because that confilcts with the ** "time" system call you need on System V. ** 1-sep-89 (daveb) ** Enhance the uniqueness of the stamp by salting in the low ** 8 bits of the pid. ** 21-jun-93 (mikem) ** Only call getpid() once per process. ** 20-apr-94 (mikem) ** Added use of 2 new #defines (xCL_GETTIMEOFDAY_TIMEONLY and ** xCL_GETTIMEOFDAY_TIME_AND_TZ) in TMget_stamp() to describe 2 ** versions of gettimeofday() available. ** 29-Aug-2002 (hanal04) Bug 108609 INGSRV 1869. ** Explicitly set _daylight, _timezone and _tzname[0] in the ** DLL's global space. tzset() failed to pickup these values ** from the Date & Time application when TZ is not set so ** we must derrive them from GetTimezoneInformation() values. */ void TMget_stamp( TM_STAMP *stamp) { static int pid = 0; static TM_STAMP last_stamp = { 0, 0 }; time_t secs; SYSTEMTIME stime; TIME_ZONE_INFORMATION tz; static bool tz_init = TRUE; if(tz_init) { tz_init = FALSE; GetTimeZoneInformation( &tz ); /* Now setup the values tzset() should set but doesn't */ if(tz.DaylightBias) _daylight = 1; else _daylight = 0; _timezone = tz.Bias * 60; WideCharToMultiByte( CP_OEMCP, 0, tz.StandardName, -1, _tzname[0], sizeof(_tzname[0]), NULL, NULL); } secs = time(NULL); GetSystemTime( &stime ); stamp->tms_sec = (i4)secs; stamp->tms_usec = stime.wMilliseconds * 1000; /* To enhance the uniqueness of the returned value as a stamp, ** salt in the low 8 bits worth of the pid (daveb) */ gen_Psem(&CL_misc_sem); if (!pid) { pid = getpid(); /* B63625 (canor01) ** Since the low-order bits of the pid could potentially ** affect the above calculations, as a medium-term fix ** (suggested by sweeney) left shift the pid by two bits ** before or'ing it in. Really, though, we need two ** functions--one for unique stamp and one for time. */ pid <<= 2; } /* B63625: To further enhance the uniqueness of the returned value ** as a stamp in the case of *very* fast machines, make sure ** returns on consecutive calls are different. (canor01) */ if ( stamp->tms_sec == last_stamp.tms_sec && stamp->tms_usec <= last_stamp.tms_usec ) stamp->tms_usec = ++last_stamp.tms_usec; last_stamp.tms_sec = stamp->tms_sec; last_stamp.tms_usec = stamp->tms_usec; gen_Vsem(&CL_misc_sem); stamp->tms_usec |= (pid & 0xff); }