-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshattermem.c
195 lines (187 loc) · 5.33 KB
/
shattermem.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#define SLEEPTIME 3600 // How long to wait before exiting (in seconds)
#define MINTIME 60 // How long to wait before returning free memory
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
long unsigned int convertsizetolong (char *sizestr)
{
long unsigned int answer=0;
int i=0;
while(sizestr[i] != '\0')
{
if(sizestr[i] == '0')
answer*=10;
if(sizestr[i] >= '1' && sizestr[i] <= '9')
{
answer*=10;
answer+=(sizestr[i]-'1'+1);
}
if(sizestr[i] == 'k' || sizestr[i] == 'K')
answer*=1024;
if(sizestr[i] == 'm' || sizestr[i] == 'M')
answer*=(1024*1024);
if(sizestr[i] == 'g' || sizestr[i] == 'G')
answer*=(1024*1024*1024);
i++;
}
return answer;
}
int main (int argc, char **argv)
{
struct datanode
{
char *data;
struct datanode *next;
};
char *totalmemsize_text = NULL;
char *numchunks_text = NULL;
char *chunksize_text = NULL;
char *tempstr;
char randstr[11];
struct datanode *basenode;
struct datanode *thisnode;
struct datanode *tempnode;
unsigned long totalmemsize = 0;
unsigned long numchunks = 0;
unsigned long chunksize = 0;
int i=0;
int j=0;
int k;
int errstate = 0;
int isparent = 0;
int opterr = 0;
pid_t childPID;
FILE *fp;
while ((k = getopt (argc, argv, "t:n:s:")) != -1)
switch (k)
{
case 't':
totalmemsize_text = optarg;
break;
case 'n':
numchunks_text = optarg;
break;
case 's':
chunksize_text = optarg;
break;
case '?':
errstate = 1;
break;
default:
errstate = 1;
break;
}
if(totalmemsize_text && numchunks_text && chunksize_text)
errstate = 1;
if(totalmemsize_text)
{
totalmemsize=convertsizetolong(totalmemsize_text);
if(numchunks_text)
{
numchunks=convertsizetolong(numchunks_text);
chunksize=totalmemsize/numchunks;
}
else if (chunksize_text)
{
chunksize=convertsizetolong(chunksize_text);
numchunks=totalmemsize/chunksize;
}
else
errstate = 1;
}
else
{
if(numchunks_text && chunksize_text)
{
numchunks=convertsizetolong(numchunks_text);
chunksize=convertsizetolong(chunksize_text);
totalmemsize=numchunks*chunksize;
}
else
errstate = 1;
}
if(errstate)
{
printf("Usage: shattermem [-t SIZE] [-n nn] [-s SIZE]\n where: -t is the total size of the memory you want to consume\n -n is the number of chunks into which you want the memory split\n -s is the size of the memory to allocate at once\n SIZE can be as a number in k (kilobytes) M (megabytes) or G (gigabytes)\n nn is an integer\n\n Note that you must have EXACTLY 2 of the 3 arguments specified. The third will be computed. n*s=t.\n");
return 0;
}
printf("totalmemsize=%lu; chunksize=%lu; numchunks=%lu \n",totalmemsize,chunksize,numchunks);
/*
* Now that we have the numbers, time for some explanation.
* If we just malloc() and free(), the memory doesn't go back to being
* available by the OS. So we're going to create a new process here. Each
* process will allocate half the memory (and since they're doing this at the
* same time, they should intertwine reasonably well). Then, we'll kill off
* one of the processes, making only fragmented memory available to the OS.
*/
numchunks/=2; // each side of the fork gets half of the memory allocation
childPID=fork();
if(childPID >= 0) // fork was successful
{
if(childPID == 0)
isparent=1;
if (!(basenode = malloc(sizeof (struct datanode))))
{
if(isparent)
tempstr="parent";
else
tempstr="child";
printf ("Could not make initial memory allocation for %s.",tempstr);
return -1;
}
thisnode=basenode;
while((tempstr = malloc(chunksize)) && ((long unsigned int) i < numchunks)) // doing this as a while to immediately break out if the malloc fails
{
tempnode = malloc(sizeof (struct datanode));
thisnode->data = tempstr;
thisnode->next = tempnode;
/*
* Linux is smart enough that it won't actually use the memory unless you write
* something to it. So we grab 10 bytes from /dev/urandom and fill the memory
* we just allocated with it over and over.
*/
fp=fopen("/dev/urandom","r");
fread(randstr,1,10,fp);
fclose(fp);
for(k=0; k<chunksize; k++)
{
tempstr[k]=randstr[j++];
if(j == 10)
j=0;
}
// printf("done with chunk %d on PID %d",i,childPID);
thisnode = tempnode;
i++;
}
if(i < numchunks)
printf("Failed to allocate memory on iteration %d. Giving up.\n",i);
sleep(10); // make sure the other side is caught up
if(childPID != 0) // Only do this for the child process
{
while(basenode != thisnode)
{
tempnode=basenode;
basenode=tempnode->next;
free(tempnode->data);
free(tempnode);
}
return 0;
}
sleep (3600); // if this goes on longer than an hour without being <ctrl-c>'d, go ahead and kill it.
while(basenode != thisnode)
{
tempnode=basenode;
basenode=tempnode->next;
free(tempnode->data);
free(tempnode);
}
return 0;
}
else
return -1;
}