0

Can anyone help me understand what these two lines are doing

buf = (char *)(malloc(2 * pagesize) & pagemask);
buf = (char *)(((long)buf + pagesize) & ∼pagemask);

I understand malloc but not sure what the & operation is trying to achieve in both expressions

Pagesize and pagemask are defined as follows earlier

pagesize = sysconf(_SC_PAGESIZE);
pagemask = pagesize - 1;

Thanks!

Edit1

This code is from a book "Unix FileSystems" by Steve D. Pate

Edit2

This is the full code

#include <sys/unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include “sys/fs/vx_ioctl.h”

#define MB (1024 * 1024)

main(int argc, char argv[])
{
    char        *buf;
    int         i, fd, advisory;
    long        pagesize, pagemask;

    if (argc != 2) {
        exit(1);
    }
    if (strcmp(argv[1], “VX_SEQ”) == 0) {
        advisory = VX_SEQ;
    } else if (strcmp(argv[1], “VX_RANDOM”) == 0) {
        advisory = VX_RANDOM;
    } else if (strcmp(argv[1], “VX_DIRECT”) == 0) {
        advisory = VX_DIRECT;
    }
    pagesize = sysconf(_SC_PAGESIZE);
    pagemask = pagesize - 1;
    buf = (char *)(malloc(2 * pagesize) & pagemask);
    buf = (char *)(((long)buf + pagesize) & ∼pagemask);

    fd = open(“myfile”, O_RDWR);
    ioctl(fd, VX_SETCACHE, advisory);
    for (i=0 ; i<MB ; i++) {
         read(fd, buf, 4096);
    }
}
3
  • The & is a binary and. Commented Feb 1, 2020 at 20:59
  • 2
    It seems like a bad idea to call malloc and immediately do arithmetic on the result. Later you will need to pass the original pointer to free. Commented Feb 1, 2020 at 21:02
  • 3
    Pick a random number, something that you think that malloc might return. Then write it down on paper. Then perform the second operation using pen and paper. Do that for a few different numbers, and you might begin to see a pattern. Pen and paper are two very important parts of a programmers toolbox, still. Commented Feb 1, 2020 at 21:03

1 Answer 1

1

Preliminary Notes

  • Memory "pages" always (well, effectively always) have a size which is a power of 2. That means that, for a given page size, the upper bits of an address indicate a page, and the lower bits - an offset into the page.
  • Don't write this kind of code. Make explicit conversions; use multiple, simpler instructions; try using more meaningful variable names (e.g. offset_into_page = ((const uintptr_t) address) & page_mask;) and so on.

First line

The first line does the following:

  1. Allocate 2 pages' worth of memory.
  2. Treating the address as a number, keep only the bits of the offset within the page in which the allocated area begins.

It's not clear to me why this is useful.

Second line

The second line does the following:

  1. Treat the address of buf as a number (although in a crooked, error-prone and non-portable way).
  2. Move one page ahead from the address of buf.
  3. Keep the page bits of the address - obtaining the first page-boundary-aligned address within buf.

This sacrifices some of the space allocated for buf, making it aligned (and keeping it in actually allocated space.

Sign up to request clarification or add additional context in comments.

3 Comments

Cool. I understand most of what you explained. What I am still confused about is the following. After the first assignment, wouldn't you mess up your pointer since you discarded the page bits and are just keeping the offset bits? Hence in the second line, you'd be pointing to some space that wasn't allocated by malloc?
@AbdulRahman: Wait, the two assignments are supposed to happen one after another? I thought they were unrelated....
Will update the question with code that I see in the book for the function

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.