int srchnext(fileinfo *pInfo) { /* Search next matching file */ union REGS inreg; union REGS outreg; DEBUG_ENTER(("srchnext(0x%p);\n", pInfo)); /* Make sure the DTA is assigned before calling DOS functions 4E and 4F */ put_dta((char *)pInfo); inreg.h.ah = 0x4f; do { intdos(&inreg, &outreg); if (CF & outreg.x.cflag) { DEBUG_LEAVE(("return %d; // DOS error code\n", outreg.x.ax)); return(outreg.x.ax); } } while ((!strncmp(previousFI.fiFileName, pInfo->fiFileName, sizeof(previousFI))) && REPORT_WORKAROUND(("// Skipped one duplicate entry\n"))); previousFI = *pInfo; /* Save it for the workaround for the VMWare player bug */ DEBUG_LEAVE(("return 0; // Success\n")); return 0; }
DIR *opendir(const char *name) { /* Open a directory */ DIR *pDir = NULL; size_t lName; unsigned attr; char *pszWildCards = "\\*.*"; char *pszCopy; DEBUG_ENTER(("opendir(\"%s\");\n", name)); lName = strlen(name); if (lName == 0) { opendir_noent: errno = ENOENT; opendir_failed: if (!_sys_errlist[ENOTDIR][0]) _sys_errlist[ENOTDIR] = "Not a directory"; /* Workaround for the missing entry in MSVC list */ if (pDir) free(pDir); DEBUG_LEAVE(("return NULL; // errno=%d - %s\n", errno, strerror(errno))); return NULL; } pDir = (DIR *)malloc(sizeof(DIR) + lName + 5); /* + 5 for wildcards suffix */ if (!pDir) goto opendir_failed; /* Work on a copy of the directory name */ pszCopy = (char *)(pDir + 1); strcpy(pszCopy, name); /* First change: Except for the root, Remove the trailing \s, which confuses get_file_attributes() */ while ((lName > 1) && (name[lName-1] == '\\') && (name[lName-2] != ':')) pszCopy[--lName] = '\0'; if (get_file_attributes(pszCopy, &attr)) goto opendir_noent; if (!(attr & _A_SUBDIR)) { errno = ENOTDIR; goto opendir_failed; } if (name[lName-1] == '\\') pszWildCards += 1; /* Avoid duplicating the \ */ strcpy(pszCopy+lName, pszWildCards); pDir->first = 1; DEBUG_LEAVE(("return 0x%p;\n", pDir)); return pDir; }
int srch1st(char *pszFile, uint16_t wAttr, fileinfo *pInfo) { /* Search first matching file */ union REGS inreg; union REGS outreg; struct SREGS sregs; DEBUG_ENTER(("srch1st(\"%s\", 0x%04X, 0x%p);\n", pszFile, wAttr, pInfo)); /* Make sure the DTA is assigned before calling DOS functions 4E and 4F */ put_dta((char *)pInfo); inreg.h.ah = 0x4e; inreg.x.cx = wAttr; inreg.x.dx = OFFSET_OF(pszFile); sregs.ds = SEGMENT_OF(pszFile); intdosx(&inreg, &outreg, &sregs); if (CF & outreg.x.cflag) { DEBUG_LEAVE(("return %d; // DOS error code\n", outreg.x.ax)); return (int)(outreg.x.ax); } previousFI = *pInfo; /* Save it for the workaround for the VMWare player bug */ DEBUG_LEAVE(("return 0; // Success\n")); return 0; }
int fcopy(char *name2, char *name1) { FILE *pfs, *pfd; /* Source & destination file pointers */ int tocopy; /* Number of bytes to copy in one pass */ static char *buffer; /* Pointer on the intermediate copy buffer */ int err; DEBUG_ENTER(("fcopy(\"%s\", \"%s\");\n", name2, name1)); if (!buffer) { buffer = malloc(BUFFERSIZE); /* Allocate memory for copying */ if (!buffer) { DEBUG_LEAVE(("return 1; // Out of memory for copy buffer\n")); return 1; } } pfs = fopen(name1, "rb"); if (!pfs) { DEBUG_LEAVE(("return 2; // Cannot open source file\n")); return 2; } pfd = fopen(name2, "wb"); if (!pfd) { fclose(pfs); DEBUG_LEAVE(("return 3; // Cannot open destination file\n")); return 3; } while ((tocopy = (int)fread(buffer, 1, BUFFERSIZE, pfs))) { if (!fwrite(buffer, tocopy, 1, pfd)) { fclose(pfs); fclose(pfd); DEBUG_LEAVE(("return 3; // Cannot write to destination file\n")); return 3; } } /* Flush buffers into the destination file, */ fflush(pfd); /* and give the same date than the source file */ fclose(pfs); fclose(pfd); /* 2011-05-12 Use an OS-independant method, _after_ closing the files */ err = copydate(name2, name1); DEBUG_LEAVE(("return %d; // Copy successful\n", err)); return err; }
static int xfs_open(struct boot_file_t *file, const char *dev_name, struct partition_t *part, const char *file_name) { char buffer[1024]; DEBUG_ENTER; DEBUG_OPEN; DEBUG_F("Determining offset for partition %d\n", part->part_number); partition_offset = ((u64) part->part_start) * part->blocksize; DEBUG_F("%Lu = %lu * %hu\n", partition_offset, part->part_start, part->blocksize); sprintf(buffer, "%s:0", dev_name); /* 0 is full disk in OF */ DEBUG_F("Trying to open dev_name=%s; filename=%s; partition offset=%Lu\n", buffer, file_name, partition_offset); file->of_device = prom_open(buffer); if (file->of_device == PROM_INVALID_HANDLE || file->of_device == NULL) { DEBUG_F("Can't open device %p\n", file->of_device); DEBUG_LEAVE(FILE_ERR_BADDEV); return FILE_ERR_BADDEV; } DEBUG_F("%p was successfully opened\n", file->of_device); xfs_file = file; if (xfs_mount() != 1) { DEBUG_F("Couldn't open XFS @ %s/%Lu\n", buffer, partition_offset); prom_close(file->of_device); DEBUG_LEAVE(FILE_ERR_BAD_FSYS); DEBUG_SLEEP; return FILE_ERR_BAD_FSYS; } DEBUG_F("Attempting to open %s\n", file_name); strcpy(buffer, file_name); /* xfs_dir modifies argument */ if (!xfs_dir(buffer)) { DEBUG_F("xfs_dir() failed. errnum = %d\n", errnum); prom_close(file->of_device); DEBUG_LEAVE_F(errnum); DEBUG_SLEEP; return errnum; } DEBUG_F("Successfully opened %s\n", file_name); DEBUG_LEAVE(FILE_ERR_OK); return FILE_ERR_OK; }
int gralloc_unregister_buffer(gralloc_module_t const* module, buffer_handle_t handle) { DEBUG_ENTER(); if (private_handle_t::validate(handle) < 0) return -EINVAL; /* * If the buffer has been mapped during a lock operation, it's time * to un-map it. It's an error to be here with a locked buffer. * NOTE: the framebuffer is handled differently and is never unmapped. */ private_handle_t* hnd = (private_handle_t*)handle; LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK, "[unregister] handle %p still locked (state=%08x)", hnd, hnd->lockState); // never unmap buffers that were created in this process if (hnd->pid != getpid()) { if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) { gralloc_unmap(module, handle); } hnd->base = 0; hnd->lockState = 0; hnd->writeOwner = 0; } DEBUG_LEAVE(); return 0; }
int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd) { DEBUG_ENTER(); /* * If the buffer has been mapped during a lock operation, it's time * to un-map it. It's an error to be here with a locked buffer. */ LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK, "[terminate] handle %p still locked (state=%08x)", hnd, hnd->lockState); if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) { // this buffer was mapped, unmap it now if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) { if (hnd->pid != getpid()) { // ... unless it's a "master" pmem buffer, that is a buffer // mapped in the process it's been allocated. // (see gralloc_alloc_buffer()) gralloc_unmap(module, hnd); } } else { gralloc_unmap(module, hnd); } } DEBUG_LEAVE(); return 0; }
static int gralloc_map(gralloc_module_t const* module, buffer_handle_t handle, void** vaddr) { DEBUG_ENTER(); private_handle_t* hnd = (private_handle_t*)handle; if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { size_t size = hnd->size; #if PMEM_HACK size += hnd->offset; #endif void* mappedAddress = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0); if (mappedAddress == MAP_FAILED) { LOGE("Could not mmap handle %p, fd=%d (%s)", handle, hnd->fd, strerror(errno)); hnd->base = 0; return -errno; } hnd->base = intptr_t(mappedAddress) + hnd->offset; //LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p", // hnd->fd, hnd->offset, hnd->size, mappedAddress); } *vaddr = (void*)hnd->base; DEBUG_LEAVE(); return 0; }
int gralloc_register_buffer(gralloc_module_t const* module, buffer_handle_t handle) { DEBUG_ENTER(); if (private_handle_t::validate(handle) < 0) return -EINVAL; // In this implementation, we don't need to do anything here /* NOTE: we need to initialize the buffer as not mapped/not locked * because it shouldn't when this function is called the first time * in a new process. Ideally these flags shouldn't be part of the * handle, but instead maintained in the kernel or at least * out-of-line */ // if this handle was created in this process, then we keep it as is. private_handle_t* hnd = (private_handle_t*)handle; if (hnd->pid != getpid()) { hnd->base = 0; hnd->lockState = 0; hnd->writeOwner = 0; } DEBUG_LEAVE(); return 0; }
_dirent *readdir(DIR *pDir) { /* Read a directory entry. Return pDir, or NULL for EOF or error. */ int iErr; _dirent *pDirent = &pDir->sDirent; fileinfo *pFI = (fileinfo *)(pDirent->d_reserved); /* Address of the fileinfo structure embedded there */ #ifdef _DEBUG char szTime[40]; #endif DEBUG_ENTER(("readdir(0x%p);\n", pDir)); if (pDir->first) { /* First search */ iErr = srch1st((char *)(pDir+1), 0x3F, pFI); pDir->first = 0; } else { iErr = srchnext(pFI); } if (!iErr) { pDirent->d_type = DT_REG; /* A normal file by default */ if (pDirent->d_attribs & _A_SUBDIR) pDirent->d_type = DT_DIR; /* Subdirectory */ if (pDirent->d_attribs & _A_VOLID) pDirent->d_type = DT_VOLID; /* Volume ID file */ DEBUG_LEAVE(("return 0x%p; // %s %02X %10ld %s\n", pDirent, Filetime2String(pDirent->d_date, pDirent->d_time, szTime, sizeof(szTime)), pDirent->d_attribs, pDirent->d_filesize, pDirent->d_name)); return &pDir->sDirent; } switch (iErr) { /* Correct a few errors that do not map well to C library errors */ case ESRCH: iErr = ENOTDIR; break; case EXDEV: iErr = 0; break; /* End of files is NOT an error */ } if (iErr) { errno = iErr; /* MS-DOS' errno.h maps C-library errnos to DOS' errors */ DEBUG_LEAVE(("return NULL; // errno=%d - %s\n", errno, strerror(errno))); } else { DEBUG_LEAVE(("return NULL; // End of directory\n")); } return NULL; }
int gralloc_unlock(gralloc_module_t const* module, buffer_handle_t handle) { DEBUG_ENTER(); if (private_handle_t::validate(handle) < 0) return -EINVAL; private_handle_t* hnd = (private_handle_t*)handle; int32_t current_value, new_value; if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) { struct pmem_region region; int err; region.offset = hnd->offset; region.len = hnd->size; err = ioctl(hnd->fd, PMEM_CACHE_FLUSH, ®ion); // LOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x)\n", // hnd, hnd->offset, hnd->size); hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH; } do { current_value = hnd->lockState; new_value = current_value; if (current_value & private_handle_t::LOCK_STATE_WRITE) { // locked for write if (hnd->writeOwner == gettid()) { hnd->writeOwner = 0; new_value &= ~private_handle_t::LOCK_STATE_WRITE; } } if ((new_value & private_handle_t::LOCK_STATE_READ_MASK) == 0) { LOGE("handle %p not locked", handle); return -EINVAL; } new_value--; } while (android_atomic_cmpxchg(current_value, new_value, (volatile int32_t*)&hnd->lockState)); DEBUG_LEAVE(); return 0; }
/* Read in the node at the current path and depth into the node cache. * You must set INFO->blocks[depth] before. */ static char * read_tree_node( __u32 blockNr, __u16 depth ) { char *cache = CACHE(depth); int num_cached = INFO->cached_slots; errnum = 0; if ( depth < num_cached ) { /* This is the cached part of the path. Check if same block is needed. */ if ( blockNr == INFO->blocks[depth] ) return cache; } else cache = CACHE(num_cached); DEBUG_F( " next read_in: block=%u (depth=%u)\n", blockNr, depth ); if ( !block_read( blockNr, 0, INFO->blocksize, cache ) ) { DEBUG_F( "block_read failed\n" ); return 0; } DEBUG_F( "FOUND: blk_level=%u, blk_nr_item=%u, blk_free_space=%u\n", blkh_level(BLOCKHEAD(cache)), blkh_nr_item(BLOCKHEAD(cache)), le16_to_cpu(BLOCKHEAD(cache)->blk_free_space) ); /* Make sure it has the right node level */ if ( blkh_level(BLOCKHEAD(cache)) != depth ) { DEBUG_F( "depth = %u != %u\n", blkh_level(BLOCKHEAD(cache)), depth ); DEBUG_LEAVE(FILE_ERR_BAD_FSYS); errnum = FILE_ERR_BAD_FSYS; return 0; } INFO->blocks[depth] = blockNr; return cache; }
static int gralloc_unmap(gralloc_module_t const* module, buffer_handle_t handle) { DEBUG_ENTER(); private_handle_t* hnd = (private_handle_t*)handle; if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { void* base = (void*)hnd->base; size_t size = hnd->size; #if PMEM_HACK base = (void*)(intptr_t(base) - hnd->offset); size += hnd->offset; #endif //LOGD("unmapping from %p, size=%d", base, size); if (munmap(base, size) < 0) { LOGE("Could not unmap %s", strerror(errno)); } } hnd->base = 0; DEBUG_LEAVE(); return 0; }
static CMPIStatus ResourceCloneInvokeMethod(CMPIMethodMI * mi, CMPIContext * ctx, CMPIResult * rslt, CMPIObjectPath * ref, const char * method_name, CMPIArgs * in, CMPIArgs * out) { CMPIString * classname = NULL; CMPIStatus rc = {CMPI_RC_OK, NULL}; int ret = 0; PROVIDER_INIT_LOGGER(); DEBUG_ENTER(); classname = CMGetClassName(ref, &rc); if(strcasecmp(CMGetCharPtr(classname), ClassName) == 0 && strcasecmp(METHOD_ADD_RESOURCE, method_name) == 0 ){ ret = resource_add_subrsc(Broker, ClassName, ctx, rslt, ref, TID_RES_CLONE, in, out, &rc); } CMReturnData(rslt, &ret, CMPI_uint32); CMReturnDone(rslt); DEBUG_LEAVE(); CMReturn(CMPI_RC_OK); }
/* preconditions: reiserfs_read_super already executed, therefore * INFO block is valid * returns: 0 if error (errnum is set), * nonzero iff we were able to find the key successfully. * postconditions: on a nonzero return, the current_ih and * current_item fields describe the key that equals the * searched key. INFO->next_key contains the next key after * the searched key. * side effects: messes around with the cache. */ static int search_stat( __u32 dir_id, __u32 objectid ) { char *cache; int depth; int nr_item; int i; struct item_head *ih; errnum = 0; DEBUG_F( "search_stat:\n key %u:%u:0:0\n", le32_to_cpu(dir_id), le32_to_cpu(objectid) ); depth = INFO->tree_depth; cache = ROOT; DEBUG_F( "depth = %d\n", depth ); while ( depth > BLKH_LEVEL_LEAF ) { struct key *key; nr_item = blkh_nr_item(BLOCKHEAD( cache )); key = KEY( cache ); for ( i = 0; i < nr_item; i++ ) { if (le32_to_cpu(key->k_dir_id) > le32_to_cpu(dir_id) || (key->k_dir_id == dir_id && (le32_to_cpu(key->k_objectid) > le32_to_cpu(objectid) || (key->k_objectid == objectid && (key->u.k_offset_v1.k_offset | key->u.k_offset_v1.k_uniqueness) > 0)))) break; key++; } DEBUG_F( " depth=%d, i=%d/%d\n", depth, i, nr_item ); INFO->next_key_nr[depth] = ( i == nr_item ) ? 0 : i + 1; cache = read_tree_node( dc_block_number(&(DC(cache)[i])), --depth ); if ( !cache ) return 0; } /* cache == LEAF */ nr_item = blkh_nr_item(BLOCKHEAD(LEAF)); ih = ITEMHEAD; DEBUG_F( "nr_item = %d\n", nr_item ); for ( i = 0; i < nr_item; i++ ) { if ( ih->ih_key.k_dir_id == dir_id && ih->ih_key.k_objectid == objectid && ih->ih_key.u.k_offset_v1.k_offset == 0 && ih->ih_key.u.k_offset_v1.k_uniqueness == 0 ) { DEBUG_F( " depth=%d, i=%d/%d\n", depth, i, nr_item ); INFO->current_ih = ih; INFO->current_item = &LEAF[ih_location(ih)]; return 1; } ih++; } DEBUG_LEAVE(FILE_ERR_BAD_FSYS); errnum = FILE_ERR_BAD_FSYS; return 0; }
int gralloc_lock(gralloc_module_t const* module, buffer_handle_t handle, int usage, int l, int t, int w, int h, void** vaddr) { DEBUG_ENTER(); if (private_handle_t::validate(handle) < 0) return -EINVAL; int err = 0; private_handle_t* hnd = (private_handle_t*)handle; int32_t current_value, new_value; int retry; do { current_value = hnd->lockState; new_value = current_value; if (current_value & private_handle_t::LOCK_STATE_WRITE) { // already locked for write LOGE("handle %p already locked for write", handle); return -EBUSY; } else if (current_value & private_handle_t::LOCK_STATE_READ_MASK) { // already locked for read if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) { LOGE("handle %p already locked for read", handle); return -EBUSY; } else { // this is not an error //LOGD("%p already locked for read... count = %d", // handle, (current_value & ~(1<<31))); } } // not currently locked if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) { // locking for write new_value |= private_handle_t::LOCK_STATE_WRITE; } new_value++; retry = android_atomic_cmpxchg(current_value, new_value, (volatile int32_t*)&hnd->lockState); } while (retry); if (new_value & private_handle_t::LOCK_STATE_WRITE) { // locking for write, store the tid hnd->writeOwner = gettid(); } // if requesting sw write for non-framebuffer handles, flag for // flushing at unlock if ((usage & GRALLOC_USAGE_SW_WRITE_MASK) && !(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH; } if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) { if (!(current_value & private_handle_t::LOCK_STATE_MAPPED)) { // we need to map for real pthread_mutex_t* const lock = &sMapLock; pthread_mutex_lock(lock); if (!(hnd->lockState & private_handle_t::LOCK_STATE_MAPPED)) { err = gralloc_map(module, handle, vaddr); if (err == 0) { android_atomic_or(private_handle_t::LOCK_STATE_MAPPED, (volatile int32_t*)&(hnd->lockState)); } } pthread_mutex_unlock(lock); } *vaddr = (void*)hnd->base; } DEBUG_LEAVE(); return err; }
static int reiserfs_open( struct boot_file_t *file, const char *dev_name, struct partition_t *part, const char *file_name ) { static char buffer[1024]; DEBUG_ENTER; DEBUG_OPEN; memset( INFO, 0, sizeof(struct reiserfs_state) ); INFO->file = file; if (part) { DEBUG_F( "Determining offset for partition %d\n", part->part_number ); INFO->partition_offset = ((uint64_t)part->part_start) * part->blocksize; DEBUG_F( "%Lu = %lu * %hu\n", INFO->partition_offset, part->part_start, part->blocksize ); } else INFO->partition_offset = 0; strncpy(buffer, dev_name, 1020); if (_machine != _MACH_bplan) strcat(buffer, ":0"); /* 0 is full disk in (non-buggy) OF */ file->of_device = prom_open( buffer ); DEBUG_F( "Trying to open dev_name=%s; filename=%s; partition offset=%Lu\n", buffer, file_name, INFO->partition_offset ); if ( file->of_device == PROM_INVALID_HANDLE || file->of_device == NULL ) { DEBUG_F( "Can't open device %p\n", file->of_device ); DEBUG_LEAVE(FILE_ERR_BADDEV); return FILE_ERR_BADDEV; } DEBUG_F("%p was successfully opened\n", file->of_device); if ( reiserfs_read_super() != 1 ) { DEBUG_F( "Couldn't open ReiserFS @ %s/%Lu\n", buffer, INFO->partition_offset ); prom_close( file->of_device ); DEBUG_LEAVE(FILE_ERR_BAD_FSYS); return FILE_ERR_BAD_FSYS; } DEBUG_F( "Attempting to open %s\n", file_name ); strcpy(buffer, file_name); /* reiserfs_open_file modifies argument */ if (reiserfs_open_file(buffer) == 0) { DEBUG_F( "reiserfs_open_file failed. errnum = %d\n", errnum ); prom_close( file->of_device ); DEBUG_LEAVE_F(errnum); return errnum; } DEBUG_F( "Successfully opened %s\n", file_name ); DEBUG_LEAVE(FILE_ERR_OK); DEBUG_SLEEP; return FILE_ERR_OK; }
EXPORT bool scatter_front( Front *front) { COMPONENT max_comp; INTERFACE *intfc = front->interf; RECT_GRID *gr = front->rect_grid; bool status; bool sav_copy = copy_intfc_states(); bool sav_intrp = interpolate_intfc_states(intfc); int i, dim = gr->dim; DEBUG_ENTER(scatter_front) max_comp = max_component(intfc); pp_global_imax(&max_comp,1L); add_time_start(3); if ((dim == 3) && debugging("consistency")) { (void) printf("Check consistency of interface " "before scatter_front()\n"); if (!consistent_interface(intfc)) { screen("ERROR in scatter_front(), input interface is " "inconsistent\n"); clean_up(ERROR); } (void) printf("Interface into scatter_front is consistent\n"); } if (dim == 2) { for (i = 0; i < dim; ++i) if ((gr->lbuf[i] > 0) || (gr->ubuf[i] > 0)) break; if (i == dim) { DEBUG_LEAVE(scatter_front) status = FUNCTION_SUCCEEDED; /* No subdomains to process */ return pp_min_status(status); } } set_copy_intfc_states(YES); interpolate_intfc_states(intfc) = NO; status = form_subintfc_via_communication(front); //if(dim == 3) // delete_outside_surface(front->interf); max_comp = max_component(intfc); pp_global_imax(&max_comp,1L); max_component(intfc) = max_comp; interpolate_intfc_states(intfc) = sav_intrp; set_copy_intfc_states(sav_copy); if ((status) && (dim == 3) && debugging("consistency")) { (void) printf("Check consistency of interface "); (void) printf("after scatter_front()\n"); if (!consistent_interface(intfc)) { screen("ERROR in scatter_front(), output interface is " "inconsistent\n"); clean_up(ERROR); } } DEBUG_LEAVE(scatter_front) status = pp_min_status(status); add_time_end(3); return status; } /*end scatter_front*/